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

Unity2D Mirror中OverlapCircle无法检测碰撞体/层掩码问题求助

网格移动碰撞检测失效问题排查与解决

我正在开发一款多人RPG游戏原型,采用基于网格的移动方式,通过移动点(movePoint)实现位置跳转,移动脚本本身运行正常,但碰撞检测存在问题。

我的玩家移动脚本如下:

using UnityEngine;
using UnityEngine.InputSystem;
using Mirror;
using Mirror.Examples.AdditiveLevels;
using Unity.Cinemachine;

public class GridBasedMovement : NetworkBehaviour
{

    public Transform movePoint;
    public LayerMask whatStopsMovement;

    public float moveSpeed;

    private Vector2 direction;

    public InputSystem_Actions playerControls;
    private InputAction move;

    private void Awake()
    {
        playerControls = new InputSystem_Actions();
    }

    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {
        movePoint.parent = null;

        if (isLocalPlayer)
        {
            GameObject camera = GameObject.FindGameObjectWithTag("MainCamera");
            camera.GetComponent<CinemachineCamera>().Follow = movePoint;
        }
    }

    public void ResetMovePoint()
    {
        movePoint.position = this.transform.position;
    }

    private void OnEnable()
    {
        ResetMovePoint();
        move = playerControls.Player.Move;
        move.Enable();
    }

    private void OnDisable()
    {
        move = playerControls.Player.Move;
        move.Disable();
    }

    private void Update()
    {
        if (isLocalPlayer)
        {
            transform.position = Vector3.MoveTowards(transform.position, movePoint.position, moveSpeed * Time.deltaTime);

            direction = move.ReadValue<Vector2>();
            if (direction.x != 0 && direction.y != 0)
            {
                if (direction.x > 0)
                {
                    direction.x = 1;
                }
                else
                {
                    direction.x = -1;
                }
                direction.y = 0;
            }
            print(!Physics2D.OverlapCircle(movePoint.position + new Vector3(1, 0, 0), 0.45f, whatStopsMovement));

            if (Vector3.Distance(transform.position, movePoint.position) <= 0.05f)
            {
                if (Mathf.Abs(direction.x) > 0)
                {
                    if (!Physics2D.OverlapCircle(movePoint.position + new Vector3(direction.x, 0, 0), 0.45f, whatStopsMovement))
                    {
                        print("Test");
                        movePoint.position += new Vector3(direction.x, 0, 0);
                    }
                }

                if (Mathf.Abs(direction.y) > 0)
                {
                    if (!Physics2D.OverlapCircle(movePoint.position + new Vector3(0, direction.y, 0), 0.45f, whatStopsMovement))
                    {
                        movePoint.position += new Vector3(0, direction.y, 0);
                    }
                }
            }
        }
    }
}

在脚本中,我使用以下代码判断移动点下一个位置是否存在阻挡层的碰撞体:

!Physics2D.OverlapCircle(movePoint.position + new Vector3(direction.x, 0, 0), 0.45f, whatStopsMovement)

以及

!Physics2D.OverlapCircle(movePoint.position + new Vector3(0, direction.y, 0), 0.45f, whatStopsMovement)

这原本应该阻止移动点跳转到存在阻挡层碰撞体的位置,但完全不起作用。我还尝试过使用碰撞体、触发器等方式,均无法解决问题,特此求助。


排查与解决步骤

  • 验证LayerMask配置
    确保Inspector面板中whatStopsMovement变量正确勾选了阻挡层。LayerMask本质是位掩码,若直接用整数赋值可能导致层选择错误,可在Awake中添加调试输出确认:

    void Awake()
    {
        playerControls = new InputSystem_Actions();
        Debug.Log("阻挡层掩码值: " + whatStopsMovement.value);
    }
    
  • 修正碰撞检测的位置与半径
    若网格单元格大小为1单位,目标位置计算应确保对齐网格(比如movePoint.position + new Vector3(direction.x * 1f, 0, 0))。同时检查0.45f的半径是否匹配阻挡物碰撞体大小——如果阻挡物是1x1的BoxCollider2D,建议将半径调整为0.5f,避免检测范围覆盖不全。

  • 区分2D/3D碰撞体类型
    代码中使用Physics2D.OverlapCircle,意味着所有阻挡物必须挂载2D碰撞体(如BoxCollider2D、CircleCollider2D),且不能勾选Is Trigger(当前逻辑未处理触发器检测)。若场景中用的是3D碰撞体,需改用Physics.OverlapSphere。

  • 添加调试输出定位问题
    在碰撞检测处增加详细日志,明确是否检测到碰撞体:

    Vector3 targetXPos = movePoint.position + new Vector3(direction.x, 0, 0);
    Collider2D hitX = Physics2D.OverlapCircle(targetXPos, 0.45f, whatStopsMovement);
    if (hitX != null)
    {
        Debug.Log("X方向检测到碰撞: " + hitX.gameObject.name + " 位置: " + targetXPos);
    }
    else
    {
        Debug.Log("X方向无碰撞,目标位置: " + targetXPos);
    }
    
  • 同步逻辑适配多人场景
    由于使用Mirror框架,碰撞检测应放在服务器端执行,避免客户端作弊。可将移动逻辑改为命令模式:

    [Command]
    void CmdMove(Vector2 dir)
    {
        if (Vector3.Distance(transform.position, movePoint.position) <= 0.05f)
        {
            Vector3 targetPos = movePoint.position + new Vector3(dir.x, dir.y, 0);
            if (!Physics2D.OverlapCircle(targetPos, 0.5f, whatStopsMovement))
            {
                movePoint.position = targetPos;
                RpcSyncMovePoint(movePoint.position);
            }
        }
    }
    
    [ClientRpc]
    void RpcSyncMovePoint(Vector3 pos)
    {
        if (!isLocalPlayer)
        {
            movePoint.position = pos;
        }
    }
    

    然后在客户端Update中调用CmdMove(direction),而非直接修改movePoint位置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 15:30:14