目录
1.案例的前期准备
2.移动的实现
3.翻滚的实现
4.瞬移的实现
1.创建2D项目
2.搭建场景
分别创建player(玩家),background(背景图),barrier(障碍物)。
3.创建C#脚本
在对象player上创建CharacterController2D脚本
public class CharacterController2D : MonoBehaviour
{
private const float MOVE_SPEED = 5f;
private void Awake()
{
rigidbody2D = GetComponent();
}
private void Update()
{
float moveX = 0f;
float moveY = 0f;
if (Input.GetKey(KeyCode.W))
{
// transform.position += new Vector3(0,+1);
moveY = +1f;
}
if (Input.GetKey(KeyCode.S))
{
// transform.position += new Vector3(0,-1);
moveY = -1f;
}
if (Input.GetKey(KeyCode.A))
{
// transform.position += new Vector3(-1,0);
moveX = -1f;
}
if (Input.GetKey(KeyCode.D))
{
// transform.position += new Vector3(+1,0);
moveX = +1f;
}
moveDir = new Vector3(moveX, moveY).normalized;
}
private void FixedUpdate()
{
rigidbody2D.velocity = moveDir * MOVE_SPEED;
}
}
实现方法:方向向量*移动速度
1,使用const储存物体速度(float)
2,在Update()中使用Input.GetKey(keyCode.按键)方法读取玩家相应按键
3,使用moveX,moveY分别保存在X,Y轴的移动增量,以此创建Vector
4,使用normalized获取Vector对象的方向向量(单位向量)赋给moveDir
Rigidbody2D.velocity
描述
刚体的线性速度,采用单位/秒形式。
在移动或旋转一个物体时,往往会直接使用Transform来执行这些操作。这种方法对于不具物理特性的GameObject来说,是可行的。但是一旦GameObject上附带有Rigidbody2D,这种方式就会带来性能的损失
public class CharacterController2D : MonoBehaviour
{
//构建枚举类区分行走状态和翻滚状态
private enum State
{
Normal, //正常行走
Rolling, //翻滚
}
[SerializeField] private LayerMask dashLayerMask;
private Rigidbody2D rigidbody2D;
private Vector3 moveDir;
private Vector3 rollDir; //翻滚的方向
private Vector3 lastMoveDir; //保存最后一次非静止状态的Vector
private float rollSpeed; //翻滚的初始速度
private State state;
private void Awake()
{
rigidbody2D = GetComponent();
state = State.Normal;
}
private void Update()
{
switch (state)
{
case State.Normal:
float moveX = 0f;
float moveY = 0f;
if (Input.GetKey(KeyCode.W))
{
// transform.position += new Vector3(0,+1);
moveY = +1f;
}
if (Input.GetKey(KeyCode.S))
{
// transform.position += new Vector3(0,-1);
moveY = -1f;
}
if (Input.GetKey(KeyCode.A))
{
// transform.position += new Vector3(-1,0);
moveX = -1f;
}
if (Input.GetKey(KeyCode.D))
{
// transform.position += new Vector3(+1,0);
moveX = +1f;
}
moveDir = new Vector3(moveX, moveY).normalized;
//保存最后一次非静止状态的Vector,防止原地翻滚
if(moveX != 0f || moveY != 0)
{
lastMoveDir = moveDir;
}
//按下空格键进入翻滚状态
if (Input.GetKey(KeyCode.Space))
{
//最后一次非静止状态的Vector,即翻滚的方向
rollDir = lastMoveDir;
//翻滚的初始速度
rollSpeed = 25f;
state = State.Rolling;
}
break;
case State.Rolling:
//翻滚是一个减速过程
//减速系数
float rollSpeedDropMultiplier = 5f;
//按帧减速
rollSpeed -= rollSpeed * rollSpeedDropMultiplier * Time.deltaTime;
//设置下限
float rollSpeedMinimum = 5f;
//小于下限切换至行走状态
if(rollSpeed < rollSpeedMinimum)
{
state=State.Normal;
}
break;
}
}
private void FixedUpdate()
{
switch (state)
{
case State.Normal:
rigidbody2D.velocity = moveDir * MOVE_SPEED;
break;
case State.Rolling:
rigidbody2D.velocity = rollDir * rollSpeed;
break;
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CharacterController2D : MonoBehaviour
{
private const float MOVE_SPEED = 5f;
private enum State
{
Normal,
Rolling,
}
[SerializeField] private LayerMask dashLayerMask;//设置射线与哪些层级发生碰撞,此项为可序列化的
private Rigidbody2D rigidbody2D;
private Vector3 moveDir;
private Vector3 rollDir;
private Vector3 lastMoveDir;
private float rollSpeed;
private bool isDashButtonDown;//瞬移状态切换
private State state;
private void Awake()
{
rigidbody2D = GetComponent();
state = State.Normal;
}
private void Update()
{
switch (state)
{
case State.Normal:
float moveX = 0f;
float moveY = 0f;
if (Input.GetKey(KeyCode.W))
{
// transform.position += new Vector3(0,+1);
moveY = +1f;
}
if (Input.GetKey(KeyCode.S))
{
// transform.position += new Vector3(0,-1);
moveY = -1f;
}
if (Input.GetKey(KeyCode.A))
{
// transform.position += new Vector3(-1,0);
moveX = -1f;
}
if (Input.GetKey(KeyCode.D))
{
// transform.position += new Vector3(+1,0);
moveX = +1f;
}
moveDir = new Vector3(moveX, moveY).normalized;
if(moveX != 0f || moveY != 0)
{
lastMoveDir = moveDir;
}
//按F进入瞬移状态
if (Input.GetKey(KeyCode.F))
{
isDashButtonDown = true;
}
if (Input.GetKey(KeyCode.Space))
{
rollDir = lastMoveDir;
rollSpeed = 25f;
state = State.Rolling;
}
break;
case State.Rolling:
float rollSpeedDropMultiplier = 5f;
rollSpeed -= rollSpeed * rollSpeedDropMultiplier * Time.deltaTime;
float rollSpeedMinimum = 5f;
if(rollSpeed < rollSpeedMinimum)
{
state=State.Normal;
}
break;
}
}
private void FixedUpdate()
{
switch (state)
{
case State.Normal:
rigidbody2D.velocity = moveDir * MOVE_SPEED;
if (isDashButtonDown)
{
//瞬移距离
float dashAmount = 0.5f;
//无障碍物情况下的瞬移量
Vector3 dashPosition = transform.position + lastMoveDir * dashAmount;
//使用射线判断瞬移路径上是否有障碍物,有则被阻碍
RaycastHit2D raycastHit2D = Physics2D.Raycast(transform.position, lastMoveDir, dashAmount, dashLayerMask);
//射线碰撞的物体不为空
if (raycastHit2D.collider != null)
{
//射线与物体碰撞的点即为瞬移的最终位置
dashPosition = raycastHit2D.point;
}
rigidbody2D.MovePosition(dashPosition);
//切换至行走状态
isDashButtonDown = false;
}
break;
case State.Rolling:
rigidbody2D.velocity = rollDir * rollSpeed;
break;
}
}
}
RigidBody2D.MovePosition
描述
将刚体移动到 /position/。
通过计算在下一次物理更新期间将刚体移动到指定
position
所需的适当线速度来将刚体移动到该位置。在移动过程中,重力或线性阻力都不会影响刚体。这使得对象能够快速从现有位置穿过世界移动到指定的 /position/。
由于该功能允许刚体穿过世界快速移动到指定的 /position/,因此附加到刚体的任何碰撞体都将按预期作出反应,也就是说,它们将产生碰撞和/或触发。这也意味着如果碰撞体产生碰撞,则将影响到刚体的运动,并可能阻止刚体在下一次物理更新期间到达指定的 /position/。如果是运动刚体,则任何碰撞都不影响刚体本身,只会影响任何其他动态碰撞体。
2D 刚体对其移动速度有固定限制,因此在短时间内尝试移动较远的距离会导致刚体无法在下一次物理更新期间到达指定 /position/。建议仅将该函数用于相对较短距离的移动。
请务必注意, 实际的位置更改只在下一次物理更新期间进行, 因此重复调用该方法而不等待下一次物理更新将导致使用最后一次调用。 因此,建议在 FixedUpdate 回调期间调用该函数。
Rigidbody2D.velocity:将钢体线性移动至某一位置
RigidBody2D.MovePosition:将钢体线性瞬移至某一位置
如何理解本案例中的射线RaycastHit2D
若没有使用射线进行判定,这钢体可能可以穿越碰撞体
RaycastHit2D raycastHit2D = Physics2D.Raycast(transform.position, lastMoveDir, dashAmount, dashLayerMask);
本案例的射线分别有如下参数
1.射线的起始位置
2.射线的方向
3.射线的距离
4.射线应于哪些层级发生碰撞
ps:若不设置此项,则与所有层级发生碰撞。可能导致本案例中的瞬移无法实现