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

未接地时coyoteTimeCounter仍设为0.5f?空中多次跳跃问题求助

问题:修复Coyote Time导致的空中多次跳跃问题

我参考Coyote Time实现功能,期望角色离开地面后0.5秒内仅能跳跃一次,但当前代码中,即使角色未处于地面状态,if (isGrounded)分支仍会将coyoteTimeCounter设为0.5f,导致角色可在空中多次跳跃。

我的代码如下:

public class jump : MonoBehaviour
{

    [SerializeField] float coyoteTime = 0.5f,coyoteTimeCounter = 0.0f;
    [SerializeField] float horizontalSpeed = 7.8f;
    [SerializeField] float horiMove;
    [SerializeField] float jumpVelocity = 7.5f;
    Rigidbody2D rb;
    [SerializeField] bool isGrounded = false;

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

  
    void Update()
    {
        horiMove = Input.GetAxis("Horizontal") * horizontalSpeed * Time.deltaTime;

        rb.transform.Translate(new Vector2(horiMove,0f));
        
        if (isGrounded)
        {
            coyoteTimeCounter = coyoteTime;
        }

        else
        {
            coyoteTimeCounter -= Time.deltaTime;
        }

        if (Input.GetKeyDown(KeyCode.Space) && coyoteTimeCounter > 0f)
        {
            rb.velocity += jumpVelocity * Vector2.up; //jumping
            coyoteTimeCounter = 0.0f; // equals to 0.0 but quickly changing to 0.5 (coyoteTime)
        }

    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
    
        if (collision.gameObject.tag == "Ground")
        {
            isGrounded = true;
        }

    }
    private void OnCollisionStay2D(Collision2D collision)
    {
        if(collision.gameObject.tag == "Ground")
        {
            isGrounded = true;
        }
    }
    private void OnCollisionExit2D(Collision2D collision)
    {
        if(collision.gameObject.tag == "Ground")
        {
            isGrounded = false;
        }
    }
}

问题核心:即使角色未接地,if (isGrounded)分支仍执行,将coyoteTimeCounter重置为0.5f,导致可多次空中跳跃。


修复方案

问题分析

  1. 碰撞检测误判:当前逻辑只要接触Ground标签物体就设isGrounded=true,包括侧面碰撞,会导致角色贴墙时错误重置计数器。
  2. 无跳跃锁定机制:仅重置coyoteTimeCounter不足以阻止后续跳跃,一旦isGrounded被误设为true,计数器会立刻被重新赋值。

具体修复步骤

  1. 添加canJump变量锁定跳跃状态,确保一次Coyote Time窗口内只能跳一次。
  2. 优化碰撞检测,只承认从下方接触地面的情况(通过碰撞法线Y轴判断)。
  3. 调整计数器更新逻辑,仅在落地且可跳跃时重置计数器。

修复后的完整代码

public class Jump : MonoBehaviour // 遵循C#大驼峰命名规范
{
    [SerializeField] float coyoteTime = 0.5f;
    [SerializeField] float coyoteTimeCounter = 0.0f;
    [SerializeField] float horizontalSpeed = 7.8f;
    [SerializeField] float jumpVelocity = 7.5f;
    
    Rigidbody2D rb;
    [SerializeField] bool isGrounded = false;
    private bool canJump = true; // 新增跳跃锁定标记

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

    void Update()
    {
        float horiMove = Input.GetAxis("Horizontal") * horizontalSpeed * Time.deltaTime;
        rb.transform.Translate(new Vector2(horiMove, 0f));

        // 仅在落地且可跳跃时重置Coyote Time计数器
        if (isGrounded && canJump)
        {
            coyoteTimeCounter = coyoteTime;
        }
        else if (!isGrounded)
        {
            coyoteTimeCounter -= Time.deltaTime;
            coyoteTimeCounter = Mathf.Max(coyoteTimeCounter, 0f); // 避免计数器为负
        }

        // 跳跃逻辑:满足Coyote Time窗口且未锁定跳跃
        if (Input.GetKeyDown(KeyCode.Space) && coyoteTimeCounter > 0f && canJump)
        {
            rb.velocity = new Vector2(rb.velocity.x, jumpVelocity); // 直接设置Y轴速度更稳定
            coyoteTimeCounter = 0f;
            canJump = false; // 锁定跳跃,直到落地解锁
        }
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        if (collision.gameObject.CompareTag("Ground"))
        {
            // 检查碰撞法线是否来自下方(排除侧面贴墙情况)
            foreach (ContactPoint2D contact in collision.contacts)
            {
                if (contact.normal.y > 0.7f) // 法线Y轴大于0.7,判定为落地
                {
                    isGrounded = true;
                    canJump = true; // 落地后解锁跳跃
                    break;
                }
            }
        }
    }

    private void OnCollisionStay2D(Collision2D collision)
    {
        if (collision.gameObject.CompareTag("Ground"))
        {
            bool isTouchingGroundFromBelow = false;
            foreach (ContactPoint2D contact in collision.contacts)
            {
                if (contact.normal.y > 0.7f)
                {
                    isTouchingGroundFromBelow = true;
                    break;
                }
            }
            isGrounded = isTouchingGroundFromBelow;
            if (isGrounded) canJump = true;
        }
    }

    private void OnCollisionExit2D(Collision2D collision)
    {
        if (collision.gameObject.CompareTag("Ground"))
        {
            isGrounded = false;
        }
    }
}

额外说明

  • 类名修改为Jump提升代码可读性,符合C#命名规范。
  • 跳跃时直接设置Y轴速度,避免叠加导致的速度异常。
  • 通过碰撞法线判断落地,消除侧面接触地面的误判。
  • 用Mathf.Max确保计数器不会变为负数,逻辑更严谨。

内容的提问来源于stack exchange,提问作者Halil Cinar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 07:14:52