Unity平滑跳跃实现求助:修改代码解决跳跃不流畅问题
Unity角色跳跃平滑优化方案
原代码核心问题
- 跳跃逻辑仅在
FixedUpdate中执行一次MovePosition,仅给角色一个瞬间位移,没有模拟真实的上升、下落过程,导致跳跃生硬甚至视觉上无效果 - 你提到
AddForce无效,大概率是Rigidbody2D设置错误:比如勾选了「冻结位置Y轴」、「重力缩放设为0」,或者刚体类型不是Dynamic
方案1:正确使用AddForce(推荐,符合物理引擎逻辑)
让物理引擎自动处理跳跃的上升、下落和重力影响,是最自然平滑的实现方式:
[SerializeField] private float moveSpeed = 5f; [SerializeField] private float jumpForce = 300f; private Rigidbody2D _rb; private Animator anim; private bool _isGrounded; private void Awake() { _rb = GetComponent<Rigidbody2D>(); anim = GetComponent<Animator>(); } private void Update() { // 水平移动:直接修改velocity,保持与物理引擎兼容 float horizontalInput = Input.GetAxisRaw("Horizontal"); _rb.velocity = new Vector2(horizontalInput * moveSpeed, _rb.velocity.y); // 跑步动画控制 anim.SetBool("isRunning", horizontalInput != 0); // 跳跃触发:Update处理输入更精准 if (_isGrounded && Input.GetKeyDown(KeyCode.Space)) { _rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse); _isGrounded = false; } } private void OnCollisionEnter2D(Collision2D collision) { // 用CompareTag替代直接判断tag,性能更优且更安全 if (collision.collider.CompareTag("Ground")) { _isGrounded = true; } }
改动说明
- 移除原代码中一次性的
MovePosition跳跃逻辑,交给物理引擎处理完整跳跃过程 - 使用
ForceMode2D.Impulse(瞬间冲量)模拟跳跃的爆发力,符合真实物理逻辑 - 水平移动改为直接设置
velocity,避免与物理引擎的冲突
方案2:手动控制速度(适合自定义跳跃曲线)
如果需要完全自定义跳跃的上升/下落节奏,可以手动模拟重力和速度:
[SerializeField] private float moveSpeed = 5f; [SerializeField] private float jumpHeight = 3f; [SerializeField] private float gravity = -9.81f; private Rigidbody2D _rb; private Animator anim; private bool _isGrounded; private float _yVelocity; private void Awake() { _rb = GetComponent<Rigidbody2D>(); anim = GetComponent<Animator>(); // 关闭物理重力,改用手动模拟 _rb.gravityScale = 0; } private void Update() { float horizontalInput = Input.GetAxisRaw("Horizontal"); Vector2 moveVelocity = new Vector2(horizontalInput * moveSpeed, _yVelocity); // 跳跃触发:用物理公式计算初始速度,保证固定跳跃高度 if (_isGrounded && Input.GetKeyDown(KeyCode.Space)) { _yVelocity = Mathf.Sqrt(2 * Mathf.Abs(gravity) * jumpHeight); _isGrounded = false; } // 手动应用重力,实现平滑下落 if (!_isGrounded) { _yVelocity += gravity * Time.deltaTime; } else { _yVelocity = 0; } // 用MovePosition更新位置,保证碰撞检测正常 _rb.MovePosition(_rb.position + moveVelocity * Time.deltaTime); // 跑步动画控制 anim.SetBool("isRunning", horizontalInput != 0); } private void OnCollisionEnter2D(Collision2D collision) { if (collision.collider.CompareTag("Ground")) { _isGrounded = true; _yVelocity = 0; // 落地重置Y速度,避免穿透地面 } }
改动说明
- 通过公式
v = sqrt(2*g*h)计算跳跃初始速度,保证不同设备上跳跃高度一致 - 用
Time.deltaTime实现帧率无关的速度计算,避免跳跃速度随帧率波动 - 落地时重置Y速度,防止角色因残留速度穿透地面
关于你提到的Async/延时/计数器循环的说明
- Async任务不适合:Unity的物理更新和Transform修改必须在主线程执行,Async会引发线程安全问题,导致跳跃卡顿、位置错乱
- 延时/计数器循环:可以用协程(Coroutine)模拟跳跃,但完全没必要——要么依赖物理引擎的
AddForce,要么手动控制速度,这两种方式比协程更高效且更符合Unity运行逻辑
内容的提问来源于stack exchange,提问作者Archie TheFox
相关产品推荐
相关产品推荐

