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

基于Tilemap的A*寻路算法中不可通行节点的判定问题

解决Tilemap拆分4个子节点的A*寻路可通行判定问题

我之前在做2D Tilemap的精细粒度A*寻路时,也碰到过类似的碰撞体边界和子节点不匹配的问题,分享几个能落地的解决方案:

1. 精准计算每个子节点的世界边界

首先,我们需要明确每个子节点的尺寸和世界坐标范围:

  • 先获取Tilemap的基础瓦片尺寸:tilemap.cellSize,每个子节点的宽高就是这个值的一半(cellSize.x/2、cellSize.y/2)
  • 对于任意瓦片的网格坐标(x, y),先通过tilemap.CellToWorld(tilePos)获取瓦片左下角的世界坐标,再加上瓦片半尺寸得到瓦片中心,最后通过偏移量算出四个子节点的中心和边界

四个子节点的位置偏移分别对应左上、右上、左下、右下四个区域,这样就能精准定位每个子节点的物理范围。

2. 用2D重叠检测判定子节点是否可通行

既然TilemapCollider2D是对应整个瓦片的,我们可以针对每个子节点的小范围做碰撞检测,推荐用Physics2D.OverlapBox来实现,因为它可以检测指定矩形区域内的碰撞体:

// 提前定义墙体图层掩码,在Inspector中选择你的墙体图层
public LayerMask wallLayerMask;
public Tilemap tilemap;

void CalculateSubNodePassability()
{
    Vector2 tileSize = tilemap.cellSize;
    Vector2 tileHalfSize = tileSize / 2f;
    Vector2 subNodeSize = tileSize / 2f;
    Vector2 subNodeHalfSize = subNodeSize / 2f;

    // 遍历Tilemap内的所有瓦片
    foreach (Vector3Int tilePos in tilemap.cellBounds.allPositionsWithin)
    {
        // 跳过没有瓦片的位置
        if (!tilemap.HasTile(tilePos)) continue;

        // 计算当前瓦片的世界中心坐标
        Vector2 tileWorldCenter = tilemap.CellToWorld(tilePos) + tileHalfSize;

        // 四个子节点的中心偏移量
        Vector2[] subNodeOffsets = new Vector2[]
        {
            new Vector2(-subNodeHalfSize.x, subNodeHalfSize.y), // 左上子节点
            new Vector2(subNodeHalfSize.x, subNodeHalfSize.y),  // 右上子节点
            new Vector2(-subNodeHalfSize.x, -subNodeHalfSize.y),// 左下子节点
            new Vector2(subNodeHalfSize.x, -subNodeHalfSize.y)  // 右下子节点
        };

        foreach (Vector2 offset in subNodeOffsets)
        {
            Vector2 subNodeCenter = tileWorldCenter + offset;
            // 检测该子节点区域是否与墙体碰撞体重叠
            Collider2D collision = Physics2D.OverlapBox(subNodeCenter, subNodeSize, 0f, wallLayerMask);
            
            // 标记该子节点是否可通行:无碰撞则可通行
            bool isPassable = collision == null;
            // 这里将isPassable赋值给你的A*节点对象即可
        }
    }
}

3. 额外注意事项

  • 确保Tilemap的坐标转换正确:有些Tilemap的锚点可能设置为中心或其他位置,要确认CellToWorld返回的是你预期的瓦片位置
  • 动态更新节点状态:如果游戏运行中瓦片会被破坏或生成,记得监听Tilemap.tileChanged事件,重新计算对应区域的子节点可通行性
  • 性能优化:如果Tilemap很大,可以只计算玩家周围一定范围内的子节点,避免一次性遍历所有瓦片消耗过多资源

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 08:58:01