using System; using System.Collections.Generic; using Cysharp.Threading.Tasks; using JetBrains.Annotations; using UnityEngine; namespace Game.Pathfinding; public class Node { public int index { get; private set; } public T data { get; private set; } public Node(int index, T data) { this.index = index; this.data = data; } } class Edge { public Node from { get; private set; } public Node to { get; private set; } public bool canTranslate { get; private set; } public Edge(Node from, Node to, bool canTranslate = true) { this.from = from; this.to = to; this.canTranslate = canTranslate; } public Node GetAnotherNode(Node node) { return node == this.from ? to : to == node ? from : throw new InvalidOperationException(); } } public class WayPointGraph : Graph { readonly struct UniqueWayPoint : IEquatable { private readonly WayPoint _wayPoint; public UniqueWayPoint(WayPoint wayPoint) { this._wayPoint = wayPoint; } public bool Equals(UniqueWayPoint other) { return _wayPoint.position == other._wayPoint.position; } public override bool Equals(object obj) { return obj is UniqueWayPoint other && Equals(other); } public override int GetHashCode() { return _wayPoint.position.GetHashCode(); } public static implicit operator WayPoint(UniqueWayPoint uniqueWayPoint) { return uniqueWayPoint._wayPoint; } public static implicit operator UniqueWayPoint(WayPoint wayPoint) { return new UniqueWayPoint(wayPoint); } } public void Initialize(GameGlobalConfig.NodeMap[] nodeMaps) { HashSet wayPoints = new HashSet(); foreach (var nodeMap in nodeMaps) { wayPoints.Add(new WayPoint(nodeMap.node1)); wayPoints.Add(new WayPoint(nodeMap.node2)); } Dictionary> position2NodeMap = new Dictionary>(); _nodes = new Node[wayPoints.Count]; using var enumerator = wayPoints.GetEnumerator(); int index = 0; while (enumerator.MoveNext()) { var enumeratorCurrent = (WayPoint)enumerator.Current; var node = new Node(index, enumeratorCurrent); this._nodes[index] = node; position2NodeMap[enumeratorCurrent.position] = node; index++; } _edges = new List>(nodeMaps.Length); this._connection = new Dictionary, List>>(_edges.Count); foreach (var nodeMap in nodeMaps) { if (position2NodeMap.TryGetValue(nodeMap.node1, out var node1)) { if (position2NodeMap.TryGetValue(nodeMap.node2, out var node2)) { var edge = new Edge(node1, node2); _edges.Add(edge); if (!this._connection.TryGetValue(node1, out var list1)) { this._connection[node1] = list1 = new List>(); } list1.Add(edge); if (!this._connection.TryGetValue(node2, out var list2)) { this._connection[node2] = list2 = new List>(); } list2.Add(edge); } } } } } public class Graph { private protected Node[] _nodes; private protected List> _edges; private protected Dictionary, List>> _connection; internal Node GetNode(int index) { if (index < 0 || index >= this._nodes.Length) { throw new IndexOutOfRangeException($"Index is {index}"); } return this._nodes[index]; } [CanBeNull] internal Node GetNode(Predicate> predicate) { foreach (var node in this._nodes) { if (predicate(node)) { return node; } } return null; } internal IReadOnlyList> GetNeighbours(Node node) { if (this._connection.TryGetValue(node, out var edges)) { return edges; } throw new ArgumentException($"GetNeighbours have error ! the id is {node.index}"); } } public class BFS { private Graph _graph; private List _closeList = new List(); private Queue _openList = new Queue(); private Dictionary, Node> _nodeMap = new Dictionary, Node>(); public BFS(Graph graph) { this._graph = graph; } [CanBeNull] public Node GetNode(Predicate> predicate) { return _graph.GetNode(predicate); } public Path FindPath(Node begin, Node end) { _openList.Clear(); _closeList.Clear(); _nodeMap.Clear(); _openList.Enqueue(begin.index); while (this._openList.Count > 0) { var nodeIndex = this._openList.Dequeue(); var currNode = this._graph.GetNode(nodeIndex); if (currNode.index == end.index) break; _closeList.Add(currNode.index); Search(currNode); } Path path = new Path(); path.AddNode(new PathNode(end.index, end.data)); this.ids.Clear(); bool isTrue = true; UniTask.Create(async () => { await UniTask.Delay(5000); if (isTrue) { isTrue = false; Debug.LogError("没找到路径卡死了,强制跳出的"); } }).Forget(); Node node = end; while (isTrue) { if (this._nodeMap.TryGetValue(node, out node)) { if (node != null) { Debug.Log($"{node.index} is null"); isTrue = false; break; } if (!this.ids.Contains(node.index)) { Debug.Log($"正在查询的点{node.index}"); this.ids.Add(node.index); path.AddNode(new PathNode(node.index, node.data)); } } if (node == begin) { Debug.Log("结束了"); isTrue = false; break; } } path.Reverse(); return path; } // add private List ids = new List(); private void Search(Node node) { var readOnlyList = this._graph.GetNeighbours(node); foreach (var edge in readOnlyList) { if (!edge.canTranslate) continue; Node another = edge.GetAnotherNode(node); if (!this._nodeMap.ContainsKey(another)) { _nodeMap[another] = node; } if (!this._closeList.Contains(another.index)) { if (!this._openList.Contains(another.index)) { _openList.Enqueue(another.index); } } } } } public class Path { private readonly List> _pathNodes = new List>(); public void Reverse() { this._pathNodes.Reverse(); } public void AddNode(PathNode node) { if (this._pathNodes.Contains(node)) { throw new ArgumentException($"{node.index}"); } this._pathNodes.Add(node); } public IReadOnlyList> GetNodes() { return this._pathNodes; } public void GetDatas(IList result) { foreach (var pathNode in this._pathNodes) { result.Add(pathNode.data); } } } public class PathNode { public int index { get; private set; } public T data { get; private set; } public PathNode(int index, T data) { this.index = index; this.data = data; } }