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

Unity 3D移动端跳跃游戏两类碰撞检测异常问题求助

Unity移动端跳跃游戏碰撞检测问题解决方案

我正在Unity 3D中开发一款移动端跳跃游戏,玩法为从一面墙跳跃到另一面墙并躲避尖刺。游戏视觉上呈现垂直视角,但实际仅为相机旋转效果。目前遇到两类碰撞检测相关问题,以下是玩家控制器代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public Rigidbody rgb;

    public float jumpStrenght;
    public bool walled;
    public bool jump;

    void Start()
    {

    }

    void FixedUpdate()
    {
        if(Input.GetButtonDown("Jump"))
        {
            Jump();
        }

        if(jump)
        {
            Jump();
        }

        if (walled)
        {
            rgb.isKinematic = true;
        }
    }

    public void Jump()
    {
        if (walled)
        {
            walled = false;
            rgb.isKinematic = false;
            rgb.AddForce(transform.up * jumpStrenght, ForceMode.Impulse);
        }
    }

    void OnCollisionEnter(Collision col)
    {
        if (col.gameObject.CompareTag("Wall"))
        {
            walled = true;
        }
        //print("col enter");
    }

    void OnTriggerEnter(Collider col)
    {
        if (col.gameObject.CompareTag("WallEnd"))
        {
            walled = false;
        }
        //print("trigger enter");
    }

    void OnCollisionExit(Collision col)
    {
        //print("col exit");
    }


    public void OnPress()
    {
        jump = true;   
    }

    public void OnRelese()
    {
        jump = false;
    }
}

问题1:玩家落到墙面边缘时OnCollisionExit不触发

现象:玩家落到墙面边缘时OnCollisionExit完全不触发;补充说明显示,OnCollisionExit会在玩家进入碰撞时错误触发,且玩家已与地面碰撞时OnCollisionEnter也不会触发。当前通过设置Rigidbody为Kinematic实现玩家贴墙状态。

问题分析

核心原因是设置Rigidbody为Kinematic后,Unity物理引擎会停止跟踪该物体的碰撞状态变化。当玩家贴墙时设置rgb.isKinematic = true,物理引擎不再检测碰撞退出事件,自然不会调用OnCollisionExit。此外,边缘碰撞时接触点可能瞬间消失,引擎来不及捕获退出事件。

解决方案

  1. 替换Kinematic状态为冻结位置/速度,保留物理碰撞检测能力:
    // 替换原FixedUpdate中walled的处理逻辑
    if (walled)
    {
        rgb.velocity = Vector3.zero;
        rgb.constraints = RigidbodyConstraints.FreezePosition;
    }
    else
    {
        rgb.constraints = RigidbodyConstraints.None;
    }
    
  2. 增加OnCollisionStay持续验证墙面接触状态,避免边缘接触时状态异常:
    void OnCollisionStay(Collision col)
    {
        if (col.gameObject.CompareTag("Wall"))
        {
            // 通过接触点数量判断是否仍有效贴墙
            walled = col.contacts.Length > 0;
        }
    }
    
  3. 修复OnCollisionExit逻辑,确保离开墙面时正确重置状态:
    void OnCollisionExit(Collision col)
    {
        if (col.gameObject.CompareTag("Wall"))
        {
            walled = false;
            rgb.constraints = RigidbodyConstraints.None;
        }
    }
    

问题2:非上方接触尖刺时碰撞检测不触发

现象:玩家不从上方落到尖刺上时,尖刺的OnCollisionEnter不会触发,游戏仍正常运行。以下是尖刺代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Danger : MonoBehaviour
{
    void OnCollisionEnter(Collision col)
    {
        print("col");
        if(col.gameObject.GetComponent<PlayerController>())
        {
            print("colPl");
            GameManager.instance.EndGame();
        }
    }
}

问题分析

可能的触发原因:

  • 尖刺碰撞体形状/大小不合理,非上方角度接触时无法触发碰撞检测;
  • 玩家Rigidbody处于Kinematic状态时,不会触发普通碰撞事件;
  • 碰撞层矩阵设置错误,玩家与尖刺所在层未开启碰撞检测。

解决方案

  1. 将尖刺改为Trigger碰撞体,使用OnTriggerEnter实现全角度检测:
    修改尖刺脚本:
    using UnityEngine;
    
    public class Danger : MonoBehaviour
    {
        void OnTriggerEnter(Collider col)
        {
            if (col.TryGetComponent(out PlayerController player))
            {
                GameManager.instance.EndGame();
            }
        }
    }
    
    同时在Inspector中勾选尖刺碰撞体的Is Trigger选项。
  2. 确保玩家在碰撞尖刺时,Rigidbody的isKinematic为false(贴墙时的位置冻结不影响Trigger检测);
  3. 检查Edit → Project Settings → Physics中的碰撞层矩阵,确认玩家层与尖刺层的碰撞检测处于开启状态。

玩家控制器代码优化建议

原代码存在逻辑冗余、命名不规范等问题,整理后版本如下:

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public Rigidbody rgb;
    public float jumpStrength;
    public bool isWalled;
    private bool jumpInput;

    void FixedUpdate()
    {
        // 合并跳跃输入逻辑
        if (jumpInput && isWalled)
        {
            Jump();
        }

        // 贴墙时冻结位置,保留物理检测
        if (isWalled)
        {
            rgb.velocity = Vector3.zero;
            rgb.constraints = RigidbodyConstraints.FreezePosition;
        }
        else
        {
            rgb.constraints = RigidbodyConstraints.None;
        }
    }

    public void Jump()
    {
        isWalled = false;
        rgb.AddForce(transform.up * jumpStrength, ForceMode.Impulse);
        jumpInput = false;
    }

    void OnCollisionEnter(Collision col)
    {
        if (col.gameObject.CompareTag("Wall"))
        {
            isWalled = true;
        }
    }

    void OnCollisionStay(Collision col)
    {
        if (col.gameObject.CompareTag("Wall"))
        {
            isWalled = col.contacts.Length > 0;
        }
    }

    void OnCollisionExit(Collision col)
    {
        if (col.gameObject.CompareTag("Wall"))
        {
            isWalled = false;
        }
    }

    void OnTriggerEnter(Collider col)
    {
        if (col.gameObject.CompareTag("WallEnd"))
        {
            isWalled = false;
        }
    }

    // 移动端输入回调(修正拼写错误)
    public void OnPress()
    {
        jumpInput = true;
    }

    public void OnRelease()
    {
        jumpInput = false;
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 02:07:05