Unity2D中如何通过RayCastHit2D获取碰撞瓦片的正确位置
Unity2D抓攀边缘位置修正方案
问题根源:Raycast获取的是Tilemap而非单个瓦片的位置
你用hit.collider.transform.position拿到的是整个Tilemap的Transform位置(Tilemap的碰撞体挂载在Tilemap对象本身上,而非单个瓦片),而Tilemap作为Grid的子物体默认位置是(0,0,0),所以无论碰撞哪个瓦片,ledgeY都会返回0。
正确获取目标瓦片的世界位置
要拿到碰撞点对应单个瓦片的实际世界位置,按以下步骤修改:
- 通过Raycast的
hit.point获取碰撞的世界坐标 - 用Tilemap的
WorldToCell方法将世界坐标转换为瓦片的网格坐标 - 再通过
CellToWorld将网格坐标转回世界坐标,得到单个瓦片的位置
修改后的FixedUpdate代码:
// 提前缓存频繁用到的组件,避免重复查找 private Tilemap ledgeTilemap; private GameObject playerObj; void Awake() { // 根据场景中实际的Tilemap名称修改 ledgeTilemap = GameObject.Find("LedgeTilemap").GetComponent<Tilemap>(); playerObj = GameObject.Find("Player"); } void FixedUpdate() { RaycastHit2D hit = Physics2D.Raycast(playerObj.transform.position, Vector2.right, 1f, LayerMask.GetMask("Ledgeonly")); RaycastHit2D hitLeft = Physics2D.Raycast(playerObj.transform.position, Vector2.left, 1f, LayerMask.GetMask("Ledgeonly")); CanGrabLedge = false; ledgeY = 0; if (hit.collider != null) { CanGrabLedge = true; // 计算瓦片的实际世界位置 Vector3Int cellPos = ledgeTilemap.WorldToCell(hit.point); Vector3 tileWorldPos = ledgeTilemap.CellToWorld(cellPos); // 加上瓦片半高偏移,让玩家位置更贴合边缘 ledgeY = tileWorldPos.y + ledgeTilemap.cellSize.y / 2f; } else if (hitLeft.collider != null) { CanGrabLedge = true; Vector3Int cellPos = ledgeTilemap.WorldToCell(hitLeft.point); Vector3 tileWorldPos = ledgeTilemap.CellToWorld(cellPos); ledgeY = tileWorldPos.y + ledgeTilemap.cellSize.y / 2f; } Debug.Log("LedgeY is: " + ledgeY); }
抓攀逻辑优化建议
直接设置transform.position.y会导致位置跳变,建议结合玩家朝向添加X轴偏移,让抓攀姿势更自然:
else if (context.started && !touchingDirections.IsGrounded && touchingDirections.CanGrabLedge && !touchingDirections.IsGrabbingLedge) { touchingDirections.IsGrabbingLedge = true; animator.SetBool(AnimationStrings.isGrabbingLedge, touchingDirections.IsGrabbingLedge); rb.velocity = Vector2.zero; rb.bodyType = RigidbodyType2D.Kinematic; // 根据朝向调整X轴位置,让玩家身体贴合瓦片边缘 float xOffset = touchingDirections.IsFacingRight ? 0.3f : -0.3f; // 替换为你的朝向判断变量 Vector3 targetPos = new Vector3(transform.position.x + xOffset, touchingDirections.ledgeY, transform.position.z); transform.position = targetPos; // 如需平滑移动,可改用协程或动画过渡 animator.SetBool(AnimationStrings.canMove, false); }
额外注意事项
- 确保Tilemap的碰撞体配置正确:使用
Tilemap Collider 2D配合Composite Collider 2D,并勾选Tilemap Collider的"Used By Composite"选项 - 所有频繁调用的组件(如Rigidbody2D、Animator)都要提前缓存,避免在Update/FixedUpdate中重复查找,影响性能
内容的提问来源于stack exchange,提问作者BugsForBreakfast
相关产品推荐
相关产品推荐

