Unity 2D象棋游戏拖拽故障及格子锁定移动实现求助
问题1:保留格子碰撞体时确保棋子可拖拽
你的问题核心是Unity 2D的射线检测不区分渲染层级(Order in Layer)和Z轴——即使棋子渲染在格子上方,重叠的碰撞体中,射线会优先命中格子的碰撞体,导致棋子的OnMouseDown完全触发不了。
给你两个靠谱的解决思路:
方案A:用LayerMask自定义射线检测(推荐)
放弃Unity自带的OnMouseXXX系列函数,自己在Update里处理鼠标输入,通过射线检测精准命中棋子:
- 新建两个Layer:
ChessPiece和ChessBoard,分别把棋子和格子拖到对应Layer。 - 修改拖拽脚本,替换成自定义射线检测逻辑:
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设置射线检测过滤:
- 在格子预制体的BoxCollider2D组件里,找到
Raycast Target选项,取消勾选。- 注意:这个选项只会让该碰撞体忽略鼠标射线检测,但依然保留碰撞体的物理特性,完全不影响后续棋子落点的碰撞检测。
问题2:扩展脚本实现棋子锁定到格子
基于上面的自定义拖拽脚本,只需要在鼠标抬起时检测当前位置的格子,将棋子移动到格子中心即可:
- 先给格子添加一个标识脚本(比如
ChessGrid),用来标记格子位置:
using UnityEngine; public class ChessGrid : MonoBehaviour { // 记录格子的行列坐标,方便后续规则判断 public int row; public int col; }
- 修改拖拽脚本的鼠标抬起逻辑:
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"); } }
- 实例化格子时,给每个
ChessGrid组件赋值对应的行列坐标,方便后续扩展象棋走棋规则。
内容的提问来源于stack exchange,提问作者daveekh
相关产品推荐
相关产品推荐

