You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 00:00:57