如何在Unity中实现类似《辐射1》的六边形网格点击移动系统
六边形网格移动系统实现方案(Unity环境)
一、点击六边形的检测逻辑
要解决点击触发问题,核心是准确获取点击的六边形Tile坐标:
- 给Tilemap添加
TilemapCollider2D,并将碰撞形状设置为Polygon Collider(手动编辑适配六边形轮廓,或用工具批量生成),同时将Tilemap所在层设为单独的HexTileLayer - 在角色或管理类中实现射线检测逻辑:
public Tilemap hexTilemap; public float moveSpeed = 3f; void Update() { if (Input.GetMouseButtonDown(0)) { var ray = Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics2D.Raycast(ray.origin, ray.direction, Mathf.Infinity, LayerMask.GetMask("HexTileLayer"))) { var worldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition); worldPos.z = 0; // 2D场景下修正Z轴 var tilePos = hexTilemap.WorldToCell(worldPos); // 若使用Unity内置六边形Tilemap模式,直接用tilePos即可;否则需做坐标偏移修正 OnHexTileSelected(tilePos); } } }
二、六边形网格最短路径寻路
适配六边形的A*算法是核心,需先定义六边形坐标系统(推荐轴向坐标):
- 自定义
HexCoordinate类,处理轴向坐标与Unity Tile坐标的转换,以及6个邻居方向的偏移:public struct HexCoordinate { public int Q { get; } public int R { get; } public HexCoordinate(int q, int r) { Q = q; R = r; } // 6个六边形方向偏移 public static readonly HexCoordinate[] Directions = new[] { new HexCoordinate(1, 0), new HexCoordinate(1, -1), new HexCoordinate(0, -1), new HexCoordinate(-1, 0), new HexCoordinate(-1, 1), new HexCoordinate(0, 1) }; // 转换为Unity世界坐标 public Vector3 ToWorldPosition(Tilemap tilemap) { var cellPos = new Vector3Int(Q, R, 0); return tilemap.GetCellCenterWorld(cellPos); } // 从Tile坐标转换为轴向坐标 public static HexCoordinate FromTilePos(Vector3Int tilePos, Tilemap tilemap) { return new HexCoordinate(tilePos.x, tilePos.y); } } - 实现六边形版本的A*算法,核心是计算节点的移动成本与启发值(用六边形距离公式:
(Mathf.Abs(q1 - q2) + Mathf.Abs(q1 + r1 - q2 - r2) + Mathf.Abs(r1 - r2)) / 2),跳过标记为不可通行的Tile。
三、角色移动执行
拿到路径后,通过协程实现平滑移动:
void OnHexTileSelected(Vector3Int tilePos) { var startWorldPos = transform.position; var startHex = HexCoordinate.FromTilePos(hexTilemap.WorldToCell(startWorldPos), hexTilemap); var targetHex = HexCoordinate.FromTilePos(tilePos, hexTilemap); var path = FindShortestPath(startHex, targetHex); if (path != null && path.Count > 0) { StartCoroutine(MoveThroughPath(path)); } } IEnumerator MoveThroughPath(List<HexCoordinate> path) { foreach (var hex in path) { var targetPos = hex.ToWorldPosition(hexTilemap); while (Vector3.Distance(transform.position, targetPos) > 0.02f) { transform.position = Vector3.MoveTowards(transform.position, targetPos, moveSpeed * Time.deltaTime); yield return null; } transform.position = targetPos; } }
四、Unity Tile Mapping System适配注意事项
- 若使用Unity 2020+,直接将Tilemap的
Layout设置为Hexagonal,可自动适配六边形坐标,无需额外偏移 - 自定义Tile类(继承
Tile),添加isWalkable字段,用于标记障碍物,寻路时跳过不可通行的Tile - 确保Tile的Sprite锚点与Tilemap的Cell中心对齐,避免角色移动位置偏移
内容的提问来源于stack exchange,提问作者MagnusPhallicus
相关产品推荐
相关产品推荐

