Unity A*寻路算法

前言:为什么要使用A*寻路算法,不直接使用unity自带的Navigation组件呢?

  1. 灵活性高

    • A*算法允许开发者根据具体游戏需求调整和优化算法实现,比如通过改变启发式函数来适应不同的地图和寻路条件。
    • Unity的Navigation组件虽然强大,但在一些特殊场景或需要高度定制的路径计算中可能不够灵活。
  2. 效率高

    • A*算法结合了Dijkstra算法的最短路径搜索和贪心算法的启发式搜索,能有效减少不必要的搜索,从而提高寻路效率。
    • 尽管Unity的Navigation系统也进行了优化,但在某些复杂场景下,自定义的A*算法可能会提供更好的性能表现。
  3. 可拓展性强

    • A*算法易于扩展和维护,开发者可以根据项目的实际需要添加新的功能或者进行调试。
    • Unity的Navigation系统虽然提供了可视化工具和诸多功能,但在进行特定扩展时可能需要更多的工作。
  4. 支持二维与三维环境

    • Unity的Navigation组件主要针对3D环境设计,对于2D游戏的路径寻找支持不如A*算法直接和高效。
  5. 适应多种场景的需求

    在不同的游戏开发项目中,地图和场景的设计差异较大,A*算法因其灵活性和适应性被广泛采用

Navigation组件的局限性:

  1. 烘焙时间和资源消耗:对于大型或复杂场景,Navigation组件的烘焙过程可能会非常耗时且消耗大量资源。

  2. 动态环境的处理:尽管新版Unity Navigation系统支持动态烘焙,但在处理频繁变化的场景时仍可能面临性能挑战。

  3. 易用性与控制权衡:Navigation组件虽然简化了寻路设置,但同时也牺牲了某些高级功能和自定义选项,这在需要精确控制的游戏设计中可能是一个缺点

A*寻路的算法估价

在A算法中核心的寻路依据就是估量代价,在A*寻路算法中通常用F表示。

F=G+H
其中G表示当前点到起始点的估量代价,表示当前点到终点的代价。

G的计算方式:最开始,以起点为中心开始计算周边的八个格子,然后在以这算出来的八个
格子为中心,继续计算他们周边的八个格子的G值,在计算的时候区域有所覆盖,如果计算出来的值小于格子目前的G值,该格子的G值就要更新为较小的G值。以此类推,直到找到终点,遍历完所有的格子。G值的计算结果为:中心点的G值+距离值【10or14】

设定每个格子之间的距离为10,那么从中心的格子到对角线之间的距离就是两个格子中心之间的连线,也就是14,G值为左下角的数值,H值为右下角的数值,F值为左上角数值,默认起点的G值为0

 H的计算方式:H值是从当前点到终点的预估代价。这个值的计算通常基于某种启发式方法,以估算剩余距离。一个简单的启发式方法是使用欧几里得距离,即在二维空间中,两点间的直线距离可以通过勾股定理来计算。

A*寻路算法的具体步骤及代码

每次计算G和H的时候建立下面这样的表格,找到F值最小的格子,然后再通过该格子找到周围的8个格子再次建立,这样的表格,找到F值最小的格子,以此递归,直到找到终点为止,每次当过中心点的格子会被记录起来来防止下次再次经过这个格子。A*寻路算法的本质就是通过终点回溯来找到最短路径。

序号GHF
1101020
2101424
3101020

步骤

  1. 设置开放列表OpenList和关闭列表CloseList
  2. 将起点放到OpenList
  3. 开启循环While(OpenList.count > 0)

        3.1 将OpenList按照F值从小到大排序

        3.2 OpenList[0]的值必是最小的,命名为center

                3.2.1发现Centeri就是终点,回溯找到导航路径
 

        3.3 以这个点为中心去计算周边的8个格子的三个值

        3.4 如果这个格子没有被计算过或者原来的G值比这次计算的还要大

                3.4.1 此时设置新的FGH值给该格子,并设置该格子的发现者为center

        3.5 如果这个格子被计算过,且原G值比这次计算的要小

                3.5.1 此时就不能替换原来的FGH值

        3.6 将发现的每个格子放入OpenList

                3.6.1 放入的时候要检测【该格子不在OpenList,该格子不在CloseList】

        3.7 将此次的发现者Center放入CloseList中

        3.8 判断OpenList为空

                3.8.1 说明所有的可发现的格子都被遍历过了,始终没有找到中,说明无法到达终点

  • 14
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我会尝试回答你的问题。 首先,要使用Unity脚本实现A*算法,需要在Unity中创建一个脚本,并将其添加到场景中的游戏对象上。 以下是实现A*算法Unity脚本示例代码: ```csharp using UnityEngine; using System.Collections; using System.Collections.Generic; public class AStarPathfinding : MonoBehaviour { public Transform seeker, target; //起点和终点 Grid grid; //所需的网格 void Awake() { grid = GetComponent<Grid>(); } void Update() { FindPath(seeker.position, target.position); } void FindPath(Vector3 startPos, Vector3 targetPos) { Node startNode = grid.NodeFromWorldPoint(startPos); Node targetNode = grid.NodeFromWorldPoint(targetPos); List<Node> openSet = new List<Node>(); HashSet<Node> closedSet = new HashSet<Node>(); openSet.Add(startNode); while (openSet.Count > 0) { Node currentNode = openSet[0]; for (int i = 1; i < openSet.Count; i++) { if (openSet[i].fCost < currentNode.fCost || (openSet[i].fCost == currentNode.fCost && openSet[i].hCost < currentNode.hCost)) { currentNode = openSet[i]; } } openSet.Remove(currentNode); closedSet.Add(currentNode); if (currentNode == targetNode) { RetracePath(startNode, targetNode); return; } foreach (Node neighbour in grid.GetNeighbours(currentNode)) { if (!neighbour.walkable || closedSet.Contains(neighbour)) { continue; } int newMovementCostToNeighbour = currentNode.gCost + GetDistance(currentNode, neighbour); if (newMovementCostToNeighbour < neighbour.gCost || !openSet.Contains(neighbour)) { neighbour.gCost = newMovementCostToNeighbour; neighbour.hCost = GetDistance(neighbour, targetNode); neighbour.parent = currentNode; if (!openSet.Contains(neighbour)) { openSet.Add(neighbour); } } } } } void RetracePath(Node startNode, Node endNode) { List<Node> path = new List<Node>(); Node currentNode = endNode; while (currentNode != startNode) { path.Add(currentNode); currentNode = currentNode.parent; } path.Reverse(); grid.path = path; } int GetDistance(Node nodeA, Node nodeB) { int dstX = Mathf.Abs(nodeA.gridX - nodeB.gridX); int dstY = Mathf.Abs(nodeA.gridY - nodeB.gridY); if (dstX > dstY) { return 14 * dstY + 10 * (dstX - dstY); } return 14 * dstX + 10 * (dstY - dstX); } } ``` 该脚本中的A*算法会在每次Update()函数调用时找从起点到终点的最短径,并将其保存在网格的径中。 实现A*算法需要一个网格,该网格由一系列节点组成。每个节点包含了该节点在网格中的位置、该节点到起点的距离(gCost)、

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值