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

如何提升Unity 2D角色跳跃操作的响应性?

Unity 2D玩家控制器跳跃延迟问题修复

问题描述

我接触Unity编程已有数月,尝试开发2D游戏并编写了玩家控制器脚本。该脚本功能正常,但测试时发现跳跃操作(尤其使用手柄时)响应迟缓,存在约半秒的可跳跃判定延迟。以下是我的BasicMovement脚本代码:

using UnityEngine;
using UnityEngine.InputSystem;
using System.Collections;

public class BasicMovement : MonoBehaviour
{
    float horizontalInput;
    float movespeed = 5f;
    float jumpForce = 7f;
    public bool isGrounded;
    bool wasGrounded;
    float dashForce = 15f;
    float dashDuration = 0.2f;
    int dashCount = 1;
    bool isDashing;
    bool canDash = true;
    float facingDirection = 1f;

    Animator anim;
    Rigidbody2D rb;

    [SerializeField] Transform groundCheck;
    [SerializeField] LayerMask groundLayer;
    float checkRadius = 0.2f;

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        anim = GetComponent<Animator>();
    }

    void OnMove(InputValue value)
    {
        horizontalInput = value.Get<Vector2>().x;
        if (horizontalInput != 0)
        {
            facingDirection = horizontalInput;
        }
    }

    void OnJump()
    {
        if (isGrounded)
        {
            rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
        }
    }

    void OnDash()
    {
        if (canDash && dashCount > 0)
        {
            StartCoroutine(Dash());
        }
    }

    IEnumerator Dash()
    {
        isDashing = true;
        canDash = false;
        dashCount--;

        rb.AddForce(new Vector2(facingDirection, 0) * dashForce, ForceMode2D.Impulse);

        yield return new WaitForSeconds(dashDuration);
        isDashing = false;
    }

    private void FixedUpdate()
    {
        if (isGrounded && !wasGrounded)
        {
            rb.linearVelocity = new Vector2(rb.linearVelocity.x, 0f);
        }
        wasGrounded = isGrounded;

        anim.SetFloat("speed", Mathf.Abs(horizontalInput));
        anim.SetBool("isGrounded", isGrounded);

        if (horizontalInput > 0)//check which way to flip player
        {
            transform.localScale = new Vector3(3, 3, 3);
        }
        if (horizontalInput < 0)
        {
            transform.localScale = new Vector3(-3, 3, 3);
        }

        isGrounded = Physics2D.OverlapCircle(groundCheck.position, checkRadius, groundLayer);

        // Recharge dash when landing
        if (isGrounded && dashCount < 1)
        {
            dashCount = 1;
            canDash = true;
        }

        if (!isDashing)
        {
            rb.linearVelocity = new Vector2(horizontalInput * movespeed, rb.linearVelocity.y);
        }
    }
}

问题根源

  • 地面判定更新滞后:isGrounded的检测放在FixedUpdate后半段,而Input System的OnJump回调默认在Update阶段触发。当玩家按下跳跃键时,isGrounded可能还是上一帧的旧值(比如刚落地但FixedUpdate未执行),导致跳跃判定不生效,需等待下一次FixedUpdate更新状态后才能触发,产生延迟。
  • 手柄输入同步问题:部分手柄采样率较低,但核心矛盾还是代码中地面状态与输入响应的不同步。

修复方案

1. 跳跃时实时检测地面

在OnJump方法内直接执行地面检测,不依赖FixedUpdate中更新的isGrounded变量,确保按下跳跃键时立刻获取最新的地面状态。

2. 调整FixedUpdate中地面检测顺序

将isGrounded的检测移到FixedUpdate最开头,保证后续逻辑使用的是最新的地面状态。

修改后的完整代码

using UnityEngine;
using UnityEngine.InputSystem;
using System.Collections;

public class BasicMovement : MonoBehaviour
{
    float horizontalInput;
    float movespeed = 5f;
    float jumpForce = 7f;
    public bool isGrounded;
    bool wasGrounded;
    float dashForce = 15f;
    float dashDuration = 0.2f;
    int dashCount = 1;
    bool isDashing;
    bool canDash = true;
    float facingDirection = 1f;

    Animator anim;
    Rigidbody2D rb;

    [SerializeField] Transform groundCheck;
    [SerializeField] LayerMask groundLayer;
    float checkRadius = 0.2f;

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        anim = GetComponent<Animator>();
    }

    void OnMove(InputValue value)
    {
        horizontalInput = value.Get<Vector2>().x;
        if (horizontalInput != 0)
        {
            facingDirection = horizontalInput;
        }
    }

    void OnJump()
    {
        // 实时检测地面,避免依赖滞后的isGrounded变量
        bool isCurrentlyGrounded = Physics2D.OverlapCircle(groundCheck.position, checkRadius, groundLayer);
        if (isCurrentlyGrounded)
        {
            rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
        }
    }

    void OnDash()
    {
        if (canDash && dashCount > 0)
        {
            StartCoroutine(Dash());
        }
    }

    IEnumerator Dash()
    {
        isDashing = true;
        canDash = false;
        dashCount--;

        rb.AddForce(new Vector2(facingDirection, 0) * dashForce, ForceMode2D.Impulse);

        yield return new WaitForSeconds(dashDuration);
        isDashing = false;
    }

    private void FixedUpdate()
    {
        // 先更新地面状态,确保后续逻辑使用最新值
        isGrounded = Physics2D.OverlapCircle(groundCheck.position, checkRadius, groundLayer);

        if (isGrounded && !wasGrounded)
        {
            rb.linearVelocity = new Vector2(rb.linearVelocity.x, 0f);
        }
        wasGrounded = isGrounded;

        anim.SetFloat("speed", Mathf.Abs(horizontalInput));
        anim.SetBool("isGrounded", isGrounded);

        if (horizontalInput > 0)//check which way to flip player
        {
            transform.localScale = new Vector3(3, 3, 3);
        }
        if (horizontalInput < 0)
        {
            transform.localScale = new Vector3(-3, 3, 3);
        }

        // Recharge dash when landing
        if (isGrounded && dashCount < 1)
        {
            dashCount = 1;
            canDash = true;
        }

        if (!isDashing)
        {
            rb.linearVelocity = new Vector2(horizontalInput * movespeed, rb.linearVelocity.y);
        }
    }
}

额外优化建议

  • 添加地面判定缓冲:可以保留最近2-3帧的isGrounded状态,避免因微小离地(如斜坡碰撞误差)导致无法跳跃,进一步提升手感。
  • 检查手柄输入设置:在Input System中确保手柄输入的Response Curve设为线性,减少输入响应延迟。

内容的提问来源于stack exchange,提问作者Karoll Stoll

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.01 13:08:16