Unity 3D双跳功能实现异常:Input.GetAxis相关问题排查
Unity双跳功能异常问题排查与修复
问题描述
普通跳跃功能正常,但二次跳跃存在异常:
- 最初用
Input.GetButtonUp("Jump")实现时,控制台显示已触发二次跳跃,但角色实际不执行,偶尔需要按空格键30次才能成功触发。 - 改用
jump = Input.GetAxisRaw("Jump")后,按下空格键会触发多次函数调用,导致地面检测状态变为false。
原脚本代码
public class PlayerBHV : MonoBehaviour { private float horizontal; private float jump; public float speed = 1000f; public float jumpHeight = 50f; public float run = 1.5f; public Transform groundCheck; public float groundCheckRadius; public LayerMask WhatIsGround; public bool grounded; public bool doubleJump; [SerializeField] private Rigidbody2D rb; void Start() { } private bool IsGrounded() { return grounded = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius ,WhatIsGround); } void Update() { IsGrounded(); horizontal = Input.GetAxisRaw("Horizontal"); jump = Input.GetAxisRaw("Jump"); if (grounded && jump == 0) { doubleJump = false; } if (rb != null) { if (Input.GetKey(KeyCode.LeftShift)) { rb.velocity = new Vector2(horizontal, 0) * Time.fixedDeltaTime * speed * run; } if (!Input.GetKey(KeyCode.LeftShift)) { rb.velocity = new Vector2(horizontal, 0) * Time.fixedDeltaTime * speed; } if (jump != 0 && grounded) { rb.velocity = new Vector2(horizontal, jumpHeight); Debug.Log("skok"); } if (jump != 0 && !doubleJump && !grounded) { Debug.Log("tutaj"); rb.velocity = new Vector2(horizontal, jumpHeight); doubleJump = true; } } } private void FixedUpdate() { rb = GetComponent<Rigidbody2D>(); } }
问题分析
- 输入检测逻辑错误:
Input.GetAxisRaw("Jump")在Update中会每帧检测,按住空格时会持续触发跳跃逻辑,导致双跳状态被反复修改,同时干扰地面检测。 - Rigidbody2D初始化时机错误:FixedUpdate中每次都执行
rb = GetComponent<Rigidbody2D>(),属于冗余操作,且可能导致帧同步问题。 - 速度设置逻辑问题:
- Update中使用
Time.fixedDeltaTime错误,应该用Time.deltaTime; - 直接覆盖
rb.velocity的Y轴值会忽略重力影响,导致跳跃手感异常; - 移动逻辑和跳跃逻辑混在Update中,物理操作应该放在FixedUpdate里。
- Update中使用
- 双跳重置逻辑不严谨:仅当
grounded && jump == 0时重置双跳,若落地时刚好按住空格,双跳无法重置。
修复后的代码
public class PlayerBHV : MonoBehaviour { private float horizontal; public float speed = 1000f; public float jumpHeight = 50f; public float run = 1.5f; public Transform groundCheck; public float groundCheckRadius; public LayerMask WhatIsGround; public bool grounded; public bool doubleJump; [SerializeField] private Rigidbody2D rb; void Awake() { // 初始化Rigidbody2D,避免重复获取 rb = GetComponent<Rigidbody2D>(); } private bool IsGrounded() { return grounded = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, WhatIsGround); } void Update() { IsGrounded(); horizontal = Input.GetAxisRaw("Horizontal"); // 落地直接重置双跳,无需判断输入状态 if (grounded) { doubleJump = false; } // 只在按下跳跃键的瞬间触发一次 if (Input.GetButtonDown("Jump")) { if (grounded) { Jump(); Debug.Log("普通跳跃"); } else if (!doubleJump) { Jump(); doubleJump = true; Debug.Log("二次跳跃"); } } } private void FixedUpdate() { // 移动逻辑放在FixedUpdate中,使用Time.fixedDeltaTime处理物理 float moveSpeed = Input.GetKey(KeyCode.LeftShift) ? speed * run : speed; rb.velocity = new Vector2(horizontal * moveSpeed * Time.fixedDeltaTime, rb.velocity.y); } private void Jump() { // 保留X轴速度,只修改Y轴跳跃速度,避免覆盖移动状态 rb.velocity = new Vector2(rb.velocity.x, jumpHeight); } }
关键修改点说明
- 输入检测:改用
Input.GetButtonDown("Jump"),确保每次按下空格只触发一次跳跃逻辑。 - Rigidbody初始化:在Awake中一次性获取组件,避免冗余操作。
- 物理逻辑分离:移动逻辑放到FixedUpdate中,符合Unity物理更新的帧同步规则。
- 跳跃逻辑优化:单独封装Jump方法,保留X轴速度,避免覆盖移动状态,同时让逻辑更清晰。
- 双跳重置:只要落地就重置双跳,逻辑更严谨,避免因按住空格导致无法重置的问题。
内容的提问来源于stack exchange,提问作者Mateusz Jarecki
相关产品推荐
相关产品推荐

