Unity中基于CharacterController的玩家如何添加空中动量
问题根源
现有代码出现空中滑翔效果由三个问题直接导致:
- 声明了
airSpeed参数但从未调用,地面与空中共用同一套水平速度计算逻辑,空中可获得与地面完全一致的移动加速度 - 未保存起跳瞬间的水平动量,每帧直接重新计算水平移动量传入
controller.Move,完全没有保留起跳惯性 - 空中
stepOffset参数设置错误,代码中给空中设置了1f的步高,比地面0.5f的步高还大,会触发CharacterController自带的斜面/墙面贴滑逻辑,加重滑翔感
修改方案
- 新增私有变量存储起跳后保留的水平动量,新增
airControlStrength参数控制空中调整方向的力度 - 地面状态下正常计算水平移动速度,每帧同步更新水平动量值
- 起跳后不再直接覆盖水平速度,在原有起跳动量的基础上叠加小幅的空中控制偏移,同时限制空中水平速度上限不超过
airSpeed - 修正空中
stepOffset值为0,避免贴墙/贴斜面自动滑动 - 落地后自动切回地面移动逻辑,重置垂直速度
修改后可直接使用的完整代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Move : MonoBehaviour { public CharacterController controller; // 移动倍率参数 private float speedMult = 1f; private float speed; public float baseSpeed = 20f; public float gravity = -9.81f; public float jumpHeight = 3f; public float walkMult = 1f; public float sprintMult = 1.5f; public float crouchMult = 0.5f; private int jumpAmount = 2; public float airSpeed = 6f; // 空中控制力度,可在Inspector面板调整 public float airControlStrength = 2f; public float crouchYMult = 0.5f; private float startYMult = 1f; public MovementState state; public enum MovementState { walking, sprinting, crouching, air } // 地面检测参数 public Transform groundCheck; public float groundDistance = 0.5f; public LayerMask groundMask; Vector3 velocity; // 存储水平方向动量 private Vector3 horizontalMomentum; bool isGrounded; private void StateHandler() { if(isGrounded && Input.GetButton("Sprint")) { state = MovementState.sprinting; speedMult = sprintMult; } else if(isGrounded && Input.GetButton("Crouch")) { state = MovementState.crouching; speedMult = crouchMult; } else if(isGrounded) { state = MovementState.walking; speedMult = walkMult; } else { state = MovementState.air; } } private void Start() { startYMult = transform.localScale.y; } void Update() { StateHandler(); // 地面检测 isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask); if (isGrounded) { jumpAmount = 2; if (velocity.y < 0) { velocity.y = -5f; } } // 获取输入方向 float x = Input.GetAxis("Horizontal"); float z = Input.GetAxis("Vertical"); Vector3 moveDir = transform.right * x + transform.forward * z; if (moveDir.magnitude > 1) { moveDir = moveDir.normalized; } if (isGrounded) { // 地面移动逻辑 speed = speedMult * baseSpeed; horizontalMomentum = moveDir * speed; controller.stepOffset = 0.5f; } else { // 空中移动逻辑:保留动量+小幅控制 Vector3 airMoveOffset = moveDir * airControlStrength; horizontalMomentum += airMoveOffset * Time.deltaTime; // 限制空中最高速度 if (horizontalMomentum.magnitude > airSpeed) { horizontalMomentum = horizontalMomentum.normalized * airSpeed; } controller.stepOffset = 0f; } // 应用水平移动 controller.Move(horizontalMomentum * Time.deltaTime); // 跳跃逻辑 if (Input.GetButtonDown("Jump") && isGrounded) { velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity); } else if (Input.GetButtonDown("Jump") && jumpAmount > 0) { velocity.y = Mathf.Sqrt(jumpHeight * 1.2f * -2f * gravity); jumpAmount -= 1; } // 应用重力 velocity.y += gravity * Time.deltaTime; controller.Move(velocity * Time.deltaTime); // 蹲伏缩放 if(Input.GetButton("Crouch")) { transform.localScale = new Vector3(transform.localScale.x, crouchYMult, transform.localScale.z); } else { transform.localScale = new Vector3(transform.localScale.x, startYMult, transform.localScale.z); } } }
参数调整说明
- 直接在Inspector面板调小
airSpeed可以降低空中最高移动速度,调小airControlStrength可以让空中转向、变速更迟钝,起跳动量保留效果更明显 - 如果需要更真实的空气阻力效果,可以在空中逻辑块中添加一行
horizontalMomentum *= 0.998f;,数值越小空中减速越快
内容的提问来源于stack exchange,提问作者T14D3
相关产品推荐
相关产品推荐

