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

Unity 2D象棋游戏拖拽故障及格子锁定移动实现求助

问题1:保留格子碰撞体时确保棋子可拖拽

你的问题核心是Unity 2D的射线检测不区分渲染层级(Order in Layer)和Z轴——即使棋子渲染在格子上方,重叠的碰撞体中,射线会优先命中格子的碰撞体,导致棋子的OnMouseDown完全触发不了。

给你两个靠谱的解决思路:

方案A:用LayerMask自定义射线检测(推荐)

放弃Unity自带的OnMouseXXX系列函数,自己在Update里处理鼠标输入,通过射线检测精准命中棋子:

  1. 新建两个Layer:ChessPiece和ChessBoard,分别把棋子和格子拖到对应Layer。
  2. 修改拖拽脚本,替换成自定义射线检测逻辑:
using UnityEngine;

public class Draggable : MonoBehaviour
{
    private Vector3 offset;
    private bool isDragging = false;
    // 只检测棋子Layer的掩码
    private LayerMask pieceMask;

    void Awake()
    {
        pieceMask = LayerMask.GetMask("ChessPiece");
    }

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            var hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero, Mathf.Infinity, pieceMask);
            if (hit.collider != null && hit.collider.gameObject == gameObject)
            {
                isDragging = true;
                offset = transform.position - Camera.main.ScreenToWorldPoint(Input.mousePosition);
                offset.z = transform.position.z; // 保持Z轴层级
            }
        }

        if (isDragging && Input.GetMouseButton(0))
        {
            Vector3 targetPos = Camera.main.ScreenToWorldPoint(Input.mousePosition) + offset;
            targetPos.z = transform.position.z; // 固定Z轴,防止层级混乱
            transform.position = targetPos;
        }

        if (Input.GetMouseButtonUp(0))
        {
            isDragging = false;
            Debug.Log("OnMouseUp");
        }
    }
}

这个方法直接让射线只检测棋子的Layer,完全避开格子的碰撞体干扰,同时保留格子碰撞体用于后续落点检测。

方案B:给格子碰撞体添加射线检测过滤

如果不想改脚本,可以给格子的BoxCollider2D设置射线检测过滤:

  1. 在格子预制体的BoxCollider2D组件里,找到Raycast Target选项,取消勾选。
    • 注意:这个选项只会让该碰撞体忽略鼠标射线检测,但依然保留碰撞体的物理特性,完全不影响后续棋子落点的碰撞检测。

问题2:扩展脚本实现棋子锁定到格子

基于上面的自定义拖拽脚本,只需要在鼠标抬起时检测当前位置的格子,将棋子移动到格子中心即可:

  1. 先给格子添加一个标识脚本(比如ChessGrid),用来标记格子位置:
using UnityEngine;

public class ChessGrid : MonoBehaviour
{
    // 记录格子的行列坐标,方便后续规则判断
    public int row;
    public int col;
}
  1. 修改拖拽脚本的鼠标抬起逻辑:
void Update()
{
    // ... 前面的拖拽逻辑不变 ...

    if (Input.GetMouseButtonUp(0))
    {
        isDragging = false;
        // 检测当前鼠标位置下的格子
        var gridHit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero, Mathf.Infinity, LayerMask.GetMask("ChessBoard"));
        if (gridHit.collider != null)
        {
            ChessGrid targetGrid = gridHit.collider.GetComponent<ChessGrid>();
            if (targetGrid != null)
            {
                // 移动棋子到格子中心(保持Z轴层级)
                Vector3 gridPos = targetGrid.transform.position;
                gridPos.z = transform.position.z;
                transform.position = gridPos;
                // 这里可以添加后续逻辑,比如判断是否符合走棋规则
            }
        }
        Debug.Log("OnMouseUp");
    }
}
  1. 实例化格子时,给每个ChessGrid组件赋值对应的行列坐标,方便后续扩展象棋走棋规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 00:56:25