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

Unity 2D平台跳跃异常:玩家每隔几次跳跃高度过高问题排查

2D平台游戏超高跳跃异常问题排查与修复

问题描述

我正在开发一款2D平台游戏,玩家多数时候跳跃高度正常,但每隔几次会出现超高跳跃的异常情况。怀疑是已停用平台的影响,但不知道如何修复。

问题代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class Movement : MonoBehaviour
{
    public float speedright = 30;
    public GameObject player;
    public Rigidbody2D rb;
    public float speedleft = -100;
    public Text e;
    Scene currentScene;
    string sceneName;
    public float jumpheight = 115;
    public Talking script;
    bool isJumping;
    public Text h;
    public float hp = 100;
    public GameObject playerbody;
    public Animator anim;
    public Rigidbody2D bg;
    public float bgspeedright = -1.5f;
    public float bgspeedleft = 1.5f;
    bool cjump = false;
    public float Health = 100;
    public float Count;
    public string Scene2;

    void Start()
    {
        Count = 0;
        Cursor.visible = false;
        Cursor.lockState = CursorLockMode.Locked;
        rb.constraints = RigidbodyConstraints2D.FreezeRotation;
        script.CanMove = 1;
    }

    private void OnTriggerStay2D(Collider2D collider)
    {
        if (sceneName == "Bedroom"){
            e.text = "E To Interact";
            e.gameObject.SetActive(true);
            if(Input.GetKeyDown("e"))
            {
                SceneManager.LoadScene("Hallway");
            }
        }
    }

    void Update()
    {
        Health = script.Health;
        bgspeedright = -0.9f;
        bgspeedleft = 0.9f;
        if (sceneName == "Butterland")
        {
            h.text = $"Health: {Health}";
        }
        jumpheight = 80;
        if (Health <= 1)
        {
            Debug.Log("DIE");
            SceneManager.LoadScene("Death");
        }

        if (Count == 5 || Count > 5)
        {
            SceneManager.LoadScene("You Cheater!");
        }
    }

    private void OnCollisionEnter2D(Collision2D other)
    {
        if (other.gameObject.CompareTag("Cheater Detection"))
        {
            InvokeRepeating("Counter", 1, 1);
        }

        if (other.gameObject.CompareTag("Floor"))
        {
            isJumping = false;
        }

        if (other.gameObject.CompareTag("Platform"))
        {
            isJumping = false;
        }

        if (other.gameObject.CompareTag("Floor") && script.floordanger == true)
        {
            Health = 0;
        }
    }

    private void OnCollisionExit2D(Collision2D other)
    {
        CancelInvoke("Counter");
    }

    void FixedUpdate()
    {
        if (script.CanMove == 1)
        {

            if (Input.GetKey("d"))
            {
                rb.velocity = new Vector2(speedright, rb.velocity.y);
                rb.transform.eulerAngles = new Vector3(0, 0, 0);
                bg.velocity = new Vector2(bgspeedright, bg.velocity.y);
            }

            if (Input.GetKey("a"))
            {
                rb.velocity = new Vector2(speedleft, rb.velocity.y);
                bg.velocity = new Vector2(bgspeedleft, bg.velocity.y);
                rb.transform.eulerAngles = new Vector3(0, 180, 0);
            }

            if (!Input.GetKey("a") && !Input.GetKey("d"))
            {
                bg.velocity = new Vector2(0, bg.velocity.y);
            }

            if (Input.GetKey("a") || Input.GetKey("d"))
            {
                anim.SetBool("IsWalking", true);
            }

            if (Input.GetKeyUp("d"))
            {
                anim.SetBool("IsWalking_Right", false);
            }

            if (Input.GetKeyUp("a"))
            {
                anim.SetBool("IsWalking", false);
            }

            if (Input.GetKeyDown(KeyCode.Space) && isJumping == false)
            {
                rb.AddForce(Vector2.up * jumpheight, ForceMode2D.Impulse);
                cjump = true;
                if(cjump == true)
                {
                    Invoke("CJump", 0.012f);
                }
            }

            if (Input.GetKeyDown(KeyCode.LeftShift))
            {
                speedleft = -15;
                speedright = 15;
            }

            if (!Input.GetKeyDown(KeyCode.LeftShift))
            {
                speedleft = -10;
                speedright = 10;
            }
        }
    }

    void CJump()
    {
        isJumping = true;
        cjump = false;
    }

    void Counter()
    {
        Count = Count + 1;
    }
}

问题根源分析

  1. 跳跃状态延迟标记漏洞:当前通过Invoke("CJump", 0.012f)延迟设置isJumping = true,这12毫秒内如果碰撞检测异常或误触输入,会重复触发rb.AddForce,叠加跳跃力导致超高跳。
  2. 无效碰撞未过滤:已停用的平台如果仍能触发OnCollisionEnter2D,会错误将isJumping重置为false,让玩家可以再次跳跃。
  3. 移动速度逻辑错误:FixedUpdate中用!Input.GetKeyDown(KeyCode.LeftShift)判断松开Shift,会每帧都重置速度,导致加速状态不稳定。

修复方案

1. 同步标记跳跃状态,移除延迟逻辑

删除cjump变量、CJump()方法和Invoke调用,按下空格时立即标记跳跃状态:

if (Input.GetKeyDown(KeyCode.Space) && isJumping == false)
{
    rb.AddForce(Vector2.up * jumpheight, ForceMode2D.Impulse);
    isJumping = true; // 直接标记为跳跃中,避免重复触发
}

2. 过滤已停用平台的碰撞触发

在OnCollisionEnter2D中添加平台激活状态判断,仅允许激活的平台重置跳跃状态:

if (other.gameObject.CompareTag("Platform") && other.gameObject.activeSelf)
{
    isJumping = false;
}

3. 修正移动速度的判定逻辑

将Shift松开的判断改为Input.GetKeyUp,避免每帧重置速度:

if (Input.GetKey(KeyCode.LeftShift))
{
    speedleft = -15;
    speedright = 15;
}

if (Input.GetKeyUp(KeyCode.LeftShift))
{
    speedleft = -10;
    speedright = 10;
}

4. 可选:限制垂直速度上限

为防止意外力叠加,添加垂直速度限制:

// 在FixedUpdate末尾添加
if (rb.velocity.y > 12f) // 根据游戏需求调整数值
{
    rb.velocity = new Vector2(rb.velocity.x, 12f);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 01:12:17