如何让Unity中Raycast 2D正确检测Tilemap?
问题描述
使用Physics2D.Raycast检测带Tilemap Collider 2D和Composite Collider 2D的Tilemap,已给墙体Tilemap设置「CollideLayer」标签,但检测结果不稳定:首次测试仅原点能检测到,其他位置无响应;第二次测试完全失效。另一段基于鼠标位置的射线检测脚本表现同样异常。禁用地面Tilemap的碰撞体后,墙体检测恢复正常,推测存在碰撞体干扰或Layer Mask设置问题。
涉及代码
第一段射线检测代码
void Update() { RaycastHit2D hit = Physics2D.Raycast(transform.position, Vector2.up, 4f); Debug.DrawRay(transform.position, Vector2.up * 4f, Color.red); if (hit.collider != null) { if (hit.collider.tag == "CollideLayer") { Debug.Log(hit.collider.name); } } }
第二段鼠标位置关联的检测代码
public class BeaconBehaviour : MonoBehaviour { public Tilemap map; void Update() { Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition); Vector3Int mouseToCell = map.WorldToCell(new Vector3(mousePosition.x, mousePosition.y, 0)); Vector3 getCenterCell = map.GetCellCenterWorld(mouseToCell); RaycastHit2D hit = Physics2D.Raycast(getCenterCell, Vector2.up, 4f); Debug.DrawRay(getCenterCell, Vector2.up * 4f, Color.red); if (hit.collider != null) { // Debug.Log("hitting " + hit.collider.name); if (hit.collider.tag == "CollideLayer") { Debug.Log(hit.collider.name); } } transform.position = getCenterCell; } private void OnTriggerEnter2D(Collider2D other) { // Debug.Log(other.gameObject.name); } private void OnTriggerExit2D(Collider2D other) { // Debug.Log(other.gameObject.name + " not touching" ); } }
排查与修复方案
精准过滤检测目标:使用Layer Mask
标签仅用于标识物体,射线检测时应通过Layer Mask指定只检测墙体Tilemap所在的Layer(注意区分标签和Layer,二者是不同概念)。修改代码如下:// 在Inspector面板给墙体Tilemap指定专属Layer(如WallLayer),然后将该Layer赋值给wallLayer变量 public LayerMask wallLayer; void Update() { // 最后一个参数传入LayerMask,只检测目标Layer RaycastHit2D hit = Physics2D.Raycast(transform.position, Vector2.up, 4f, wallLayer); Debug.DrawRay(transform.position, Vector2.up * 4f, Color.red); if (hit.collider != null) { Debug.Log(hit.collider.name); } }检查Composite Collider 2D配置
确保墙体Tilemap的Tilemap Collider 2D勾选了「Used By Composite」,且Composite Collider 2D的「Is Trigger」未被误勾选(Trigger不会被普通Raycast检测到)。修正射线起点位置偏差
2D游戏中使用ScreenToWorldPoint时,需设置正确的z值(取Camera的nearClipPlane,避免位置偏移),修改第二段代码中的鼠标位置转换:Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition); mousePosition.z = Camera.main.nearClipPlane; // 修正z轴位置 Vector3Int mouseToCell = map.WorldToCell(mousePosition);排查碰撞体重叠干扰
若地面与墙体Tilemap的碰撞体重叠,射线会优先检测到排序靠前的碰撞体。可调整Tilemap的排序层,或通过Layer Mask彻底排除地面Layer的检测。添加Debug信息定位问题
在射线检测后打印详细信息,确认检测到的物体:if (hit.collider != null) { Debug.Log($"检测到:{hit.collider.name} | 标签:{hit.collider.tag} | Layer:{LayerMask.LayerToName(hit.collider.gameObject.layer)}"); }
内容的提问来源于stack exchange,提问作者winnieTheWind

