游戏AI实现-寻路算法(Dijkstra)

戴克斯特拉算法(英语:Dijkstra's algorithm),又称迪杰斯特拉算法、Dijkstra算法,是由荷兰计算机科学家艾兹赫尔·戴克斯特拉在1956年发现的算法。

算法过程:

1.首先设置开始节点的成本值为0,并将开始节点放入检测列表中。

2.将检测列表中的所有点按到目标点所需的成本值排序,选择成本最小的节点作为当前节点,并将其移出检测列表。

3.将当前点周围的点中不包含在检测列表中的点加入到检测列表,将周围点加入到已检测列表中。

4.更新检测列表中的节点到当前节点的成本值。

5.重复2,3,4直到找到目标点。

代码实现:

cs 复制代码
public class Dijkstra : FindPathAlgorithm
{
    public Dijkstra(int[,] mapData, int xCount, int zCount) : base(mapData, xCount, zCount){}

    public override List<Vector2Int> FindPath(Vector2Int startPos, Vector2Int goalPos)
    {
        DataNode dataNode = this.DijkstraFind(startPos, goalPos);
        if (dataNode == null)
        {
            Debug.LogError("寻路有误,请检查参数是否正确");
            return null;
        }
        return Utils.GetPath(dataNode);
    }

    DataNode DijkstraFind(Vector2Int startPos, Vector2Int goalPos)
    {
        //存储要检测的点
        List<DataNode> frontier = new List<DataNode>();
        //存储已经检测的点
        List<Vector2Int> reached = new List<Vector2Int>();

        DataNode startNode = new DataNode(startPos, null);
        startNode.gCost = 0;
        frontier.Add(startNode);
        reached.Add(startPos);

        while (frontier.Count > 0)
        {
            DataNode currentNode = GetLowestgCostNode(frontier);
            frontier.Remove(currentNode);
            if (currentNode.pos == goalPos)
            {
                Debug.Log("完成!!!");
                return new DataNode(goalPos, currentNode.parent);
            }

            List<DataNode> neighbors = GetNeighbors(currentNode.pos, reached);
            foreach (DataNode neighbourNode in neighbors)
            {
                if (!frontier.Contains(neighbourNode))
                {
                    neighbourNode.parent = currentNode;
                    frontier.Add(neighbourNode);
                }
                reached.Add(neighbourNode.pos);
            }

            this.UpdateCost(frontier, currentNode);
        }

        return null;
    }

    //更新成本值
    void UpdateCost(List<DataNode> nodes, DataNode currentNode)
    {
        for (int i = 0; i < nodes.Count; i++)
        {
            int newCost = currentNode.gCost + CalculateDistanceCost(nodes[i].pos, currentNode.pos);
            if (nodes[i].gCost > newCost)
            {
                nodes[i].gCost = newCost;
            }
        }
    }

    List<DataNode> GetNeighbors(Vector2Int current, List<Vector2Int> reached)
    {
        List<DataNode> neighbors = new List<DataNode>();
        for (int i = 0; i < Utils.pointDir.Count; i++)
        {
            Vector2Int neighbor = current + Utils.pointDir[i];
            if (this.IsCanAdd(neighbor, reached))
            {
                neighbors.Add(new DataNode(neighbor, null));
            }
        }
        return neighbors;
    }

    bool IsCanAdd(Vector2Int current, List<Vector2Int> reached)
    {
        if (reached.Contains(current))
            return false;
        if (current.x >= 0 && current.y >= 0 && current.x < MapData.m_MapData.GetLength(1) && current.y < MapData.m_MapData.GetLength(0))
        {
            //如果是障碍物,则不能被Add
            if (MapData.m_MapData[current.y, current.x] == 1)
            {
                return false;
            }
            return true;
        }
        return false;
    }

    private int CalculateDistanceCost(Vector2Int a, Vector2Int b)
    {
        return Mathf.Abs(a.x - b.x) + Mathf.Abs(a.y - b.y);
    }

    private DataNode GetLowestgCostNode(List<DataNode> pathNodeList)
    {
        DataNode lowestFCostNode = pathNodeList[0];
        for (int i = 1; i < pathNodeList.Count; i++)
        {
            if (pathNodeList[i].gCost < lowestFCostNode.gCost)
            {
                lowestFCostNode = pathNodeList[i];
            }
        }
        return lowestFCostNode;
    }
}

结果:

参考链接:

Pathfinding in Unity - Part3: Dijkstra Algorithm Theory (youtube.com)

Pathfinding in Unity - Part4: Dijkstra Algorithm Implementation (youtube.com)

How Dijkstra's Algorithm Works (youtube.com)

戴克斯特拉算法 - 维基百科,自由的百科全书 (wikipedia.org)

相关推荐
CreasyChan6 小时前
C# 反射详解
开发语言·前端·windows·unity·c#·游戏开发
IMPYLH8 小时前
Lua 的 Coroutine(协程)模块
开发语言·笔记·后端·中间件·游戏引擎·lua
世洋Blog18 小时前
SiYangUnityEventSystem,一个Unity中的事件系统
观察者模式·unity·c#·游戏引擎·事件系统
呆呆敲代码的小Y18 小时前
【Unity实战篇】| 游戏滑动框添加特殊效果,如实时高亮显示、曲线滑动等
游戏·unity·游戏引擎·实战·u3d·免费游戏·unity实战技巧
Tatalaluola19 小时前
【Quest开发】用unity UI快速实现交互
unity·游戏引擎
技术小甜甜19 小时前
[Godot] 在 Godot 3.1 中配置 ADB 可执行文件的实用指南
游戏·adb·游戏引擎·godot
技术小甜甜19 小时前
【Godot】【入门】Godot 是什么?适合做哪些类型的游戏(附路线图+避坑清单)
游戏·游戏引擎·godot
码界奇点20 小时前
Unity WebGL输入支持终极指南解决浏览器输入难题的完整方案
unity·容器·游戏引擎·鸿蒙系统·webgl
90后小陈老师20 小时前
Unity动画控制
unity·游戏引擎
Miss_SQ1 天前
Webgl打包后删除StreamingAssets文件夹下多余资源
unity·c#·webgl