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

Unity2D中如何通过RayCastHit2D获取碰撞瓦片的正确位置

Unity2D抓攀边缘位置修正方案

问题根源:Raycast获取的是Tilemap而非单个瓦片的位置

你用hit.collider.transform.position拿到的是整个Tilemap的Transform位置(Tilemap的碰撞体挂载在Tilemap对象本身上,而非单个瓦片),而Tilemap作为Grid的子物体默认位置是(0,0,0),所以无论碰撞哪个瓦片,ledgeY都会返回0。

正确获取目标瓦片的世界位置

要拿到碰撞点对应单个瓦片的实际世界位置,按以下步骤修改:

  1. 通过Raycast的hit.point获取碰撞的世界坐标
  2. 用Tilemap的WorldToCell方法将世界坐标转换为瓦片的网格坐标
  3. 再通过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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 12:22:41