转载:http://www.gopedu.com/article/735
因为项目需要做一个 A 星寻路的功能,但是又不想用 Unity3D 中的 A 星寻路插件,因为感觉插件感觉不够灵活,不能符合自己的设计,还好以前就保留了一位前辈的高效 A 星寻路链接,不过作者是用的 ActionScript 编写的,所以我就整理成了 C# 版本的了。
最终效果图如下:
测试代码如下(TestWorld.cs):
using UnityEngine; 002 using System.Collections.Generic; 003 004 public class TestWorld : MonoBehaviour 005 { 006 public GameObject cubeObject; 007 public GameObject pathObject; 008 009 public Camera mainCamera; 010 public SceneGrid sceneGrid; 011 012 private AStarUtils aStarUtils; 013 014 private AStarNode beginNode; 015 016 private int cols = 20; 017 private int rows = 20; 018 019 private IListpathList; 020 021 void Awake() 022 { 023 this.pathList = new List (); 024 this.aStarUtils = new AStarUtils (this.cols, this.rows); 025 026 // cols 027 for(int i = 0; i < this.cols; i++) 028 { 029 // rows 030 for(int j = 0; j < this.rows; j++) 031 { 032 AStarUnit aStarUnit = new AStarUnit(); 033 034 if(i != 0 && j != 0 && Random.Range(1, 10) <= 3) 035 { 036 aStarUnit.isPassable = false; 037 038 GameObject gameObject = (GameObject)Instantiate(cubeObject); 039 if(gameObject != null) 040 { 041 gameObject.transform.localPosition = new Vector3(i - this.cols * 0.5f + 0.5f, 0f, j - this.cols * 0.5f + 0.5f); 042 } 043 044 }else{ 045 aStarUnit.isPassable = true; 046 } 047 048 this.aStarUtils.GetNode(i,j).AddUnit(aStarUnit); 049 } 050 } 051 } 052 053 private void FindPath(int x, int y) 054 { 055 AStarNode endNode = this.aStarUtils.GetNode(x, y); 056 057 if (this.beginNode == null) 058 { 059 this.beginNode = endNode; 060 return; 061 } 062 063 if (this.pathList != null && this.pathList.Count > 0) 064 { 065 foreach (GameObject xxObject in this.pathList) 066 { 067 Destroy(xxObject); 068 } 069 } 070 071 if(endNode != null && endNode.walkable) 072 { 073 System.DateTime dateTime = System.DateTime.Now; 074 075 IList pathList = this.aStarUtils.FindPath(this.beginNode, endNode); 076 077 System.DateTime currentTime = System.DateTime.Now; 078 079 System.TimeSpan timeSpan = currentTime.Subtract(dateTime); 080 081 Debug.Log(timeSpan.Seconds + "秒" + timeSpan.Milliseconds + "毫秒"); 082 083 if(pathList != null && pathList.Count > 0) 084 { 085 foreach(AStarNode nodeItem in pathList) 086 { 087 GameObject gameObject = (GameObject)Instantiate(this.pathObject); 088 this.pathList.Add(gameObject); 089 gameObject.transform.localPosition = new Vector3(nodeItem.nodeX - this.cols * 0.5f + 0.5f, 0f, nodeItem.nodeY - this.cols * 0.5f + 0.5f); 090 } 091 } 092 this.beginNode = endNode; 093 } 094 } 095 096 void Update() 097 { 098 if (Input.GetMouseButtonDown (0)) 099 { 100 Ray ray = this.mainCamera.ScreenPointToRay(Input.mousePosition);
101 102 RaycastHit raycastHit = new RaycastHit(); 103 if(Physics.Raycast(ray, out raycastHit)) 104 { 105 if(raycastHit.collider.gameObject.tag == "Plane") 106 { 107 Vector3 pointItem = this.sceneGrid.transform.InverseTransformPoint(raycastHit.point) * 2f; 108 109 pointItem.x = this.cols * 0.5f + Mathf.Ceil(pointItem.x) - 1f; 110 pointItem.z = this.cols * 0.5f + Mathf.Ceil(pointItem.z) - 1f; 111 112 this.FindPath((int)pointItem.x, (int)pointItem.z); 113 } 114 } 115 } 116 } 117 } SceneGrid.cs 1 using UnityEngine; 2 using System.Collections; 3 4 public class SceneGrid : MonoBehaviour 5 { 6 7 } A 星类库代码如下(AStarCallback.cs): 01 using UnityEngine; 02 using System.Collections; 03 04 public class AStarCallback 05 { 06 // 07 public delegate void IsPassableChangeCallback(); 08 09 // 10 public delegate void HeuristicCallback(AStarNode aStarNode); 11 12 public event HeuristicCallback OnHeuristic; 13 14 public event IsPassableChangeCallback OnIsPassableChange; 15 16 public void InvokeHeuristic(AStarNode callAStarNode) 17 { 18 if (this.OnHeuristic != null) 19 { 20 this.OnHeuristic(callAStarNode); 21 } 22 } 23 24 public void InvokeIsPassableChange() 25 { 26 if (this.OnIsPassableChange != null) 27 { 28 this.OnIsPassableChange(); 29 } 30 } 31 } AtarDiagonalHeuristic.cs 01 using UnityEngine; 02 using System.Collections; 03 04 public class AStarDiagonalHeuristic : IAStarHeuristic 05 { 06 public int Heuristic(int x1, int y1, int x2, int y2) 07 { 08 int dx = x1 > x2 ? x1 - x2 : x2 - x1; 09 int dy = y1 > y2 ? y1 - y2 : y2 - y1; 10 11 return dx > dy ? AStarUtils.DIAG_COST * dy + AStarUtils.STRAIGHT_COST * (dx - dy) : AStarUtils.DIAG_COST * dx + AStarUtils.STRAIGHT_COST * (dy - dx); 12 } 13 } AStarLinkNode.cs 01 using UnityEngine; 02 using System.Collections; 03 04 ///05 /// 邻节点 06 /// 07 public class AStarLinkNode 08 { 09 ///10 /// 节点 11 /// 12 public AStarNode node; 13 14 ///15 /// 花费代价 16 /// 17 public int cost; 18 19 public AStarLinkNode(AStarNode node, int cost) 20 { 21 this.node = node; 22 this.cost = cost; 23 } 24 } AStarManhattanHeuristic.cs 01 using UnityEngine; 02 using System.Collections; 03 04 public class AStarManhattanHeuristic : IAStarHeuristic 05 { 06 public int Heuristic(int x1, int y1, int x2, int y2) 07 { 08 return ( 09 (x1 > x2 ? x1 - x2 : x2 - x1) 10 + 11 (y1 > y2 ? y1 - y2 : y2 - y1) 12 ) * AStarUtils.STRAIGHT_COST; 13 } 14 } AStarNode.cs 001 using UnityEngine; 002 using System.Collections.Generic; 003 004 public class AStarNode 005 { 006 ///007 /// 坐标 x 008 /// 009 public int nodeX; 010 011 ///012 /// 坐标 y 013 /// 014 public int nodeY; 015 016 ///017 /// 父节点 018 /// 019 public AStarNode parentNode; 020 021 ///022 /// 二叉堆节点 023 /// 024 public BinaryHeapNode binaryHeapNode; 025 026 ///027 /// 与此节点相邻的可通过的邻节点 028 /// 029 public IListlinks; 030 031 /// 032 /// 搜索路径的检查编号(确定是否被检查过) 033 /// 034 public int searchPathCheckNum; 035 036 ///037 /// 可移动范围的检查编号(确定是否被检查过) 038 /// 039 public int walkableRangeCheckNum; 040 041 ///042 /// 是否能被穿越 043 /// 044 public bool walkable; 045 046 ///047 /// 从此节点到目标节点的代价(A星算法使用) 048 /// 049 public int f; 050 051 ///052 /// 从起点到此节点的代价 053 /// 054 public int g; 055 056 ///057 /// 在此节点上的单位 058 /// 059 private IListunits; 060 061 /// 062 /// 通过回调函数 063 /// 064 private AStarCallback aStarCallback = new AStarCallback (); 065 066 ///067 /// 回调函数参数 068 /// 069 private AStarNode aStarNodeParam; 070 071 public int unitCount 072 { 073 get { return this.units.Count; } 074 } 075 076 ///077 /// 添加穿越代价被修改后的回调函数 078 /// 079 /// Callback. 080 /// A star node parameter. 081 public void AddHeuristic(AStarCallback.HeuristicCallback callback, AStarNode aStarNodeParam) 082 { 083 this.aStarNodeParam = aStarNodeParam; 084 this.aStarCallback.OnHeuristic += callback; 085 } 086 087 ///088 /// 移除穿越代价被修改后的回调函数 089 /// 090 /// Callback. 091 public void RemoveHeuristic(AStarCallback.HeuristicCallback callback) 092 { 093 this.aStarCallback.OnHeuristic -= callback; 094 } 095 096 ///097 /// 刷新穿越代价 098 /// 099 private void RefreshPassCost() 100 { 101 foreach(IAStarUnit unit in this.units) 102 { 103 if(!unit.isPassable) 104 { 105 if(this.walkable) 106 { 107 this.walkable = false; 108 this.aStarCallback.InvokeHeuristic(this.aStarNodeParam); 109 } 110 return; 111 } 112 } 113 } 114 115 ///116 /// 单位的 isPassable 属性被改变 117 /// 118 ///119 /*private void IsPassableChange() 120 { 121 this.RefreshPassCost(); 122 }*/ 123 124 /// true if this instance is passable change; otherwise,false .125 /// 添加单位 126 /// 127 ///128 /// Unit. 129 public bool AddUnit(IAStarUnit unit) 130 { 131 if(this.walkable) 132 { 133 if(this.units.IndexOf(unit) == -1) 134 { 135 //unit.AddIsPassableChange(this.IsPassableChange); 136 this.units.Add(unit); 137 RefreshPassCost(); 138 return true; 139 } 140 } 141 return false; 142 } 143 144 /// true , if unit was added,false otherwise.145 /// 移除单位 146 /// 147 ///148 /// Unit. 149 public bool RemoveUnit(IAStarUnit unit) 150 { 151 int index = this.units.IndexOf(unit); 152 if(index != -1) 153 { 154 //unit.RemoveIsPassableChange(this.IsPassableChange); 155 this.units.RemoveAt(index); 156 this.RefreshPassCost(); 157 return true; 158 } 159 return false; 160 } 161 162 /// true , if unit was removed,false otherwise.163 /// 地图节点 164 /// 165 /// Node x. 166 /// Node y. 167 public AStarNode(int nodeX, int nodeY) 168 { 169 this.nodeX = nodeX; 170 this.nodeY = nodeY; 171 172 this.walkable = true; 173 this.units = new List(); 174 } 175 } AStarUnit.cs 01 using UnityEngine; 02 using System.Collections; 03 04 public class AStarUnit : IAStarUnit 05 { 06 /// 07 /// 是否可以通过 08 /// 09 private bool _isPassable; 10 11 private AStarCallback aStarCallback = new AStarCallback(); 12 13 ///14 /// 添加通过回调函数 15 /// 16 /// Callback. 17 public void AddIsPassableChange(AStarCallback.IsPassableChangeCallback callback) 18 { 19 this.aStarCallback.OnIsPassableChange += callback; 20 } 21 22 ///23 /// 移除通过回调函数 24 /// 25 /// Callback. 26 public void RemoveIsPassableChange(AStarCallback.IsPassableChangeCallback callback) 27 { 28 this.aStarCallback.OnIsPassableChange -= callback; 29 } 30 31 ///32 /// 是否可以通过 33 /// 34 ///true 35 ///false 36 public bool isPassable 37 { 38 get { return this._isPassable; } 39 set 40 { 41 if(this._isPassable != value) 42 { 43 this._isPassable = value; 44 this.aStarCallback.InvokeIsPassableChange(); 45 } 46 } 47 } 48 } AStarUtils.cs 001 using UnityEngine; 002 using System.Collections.Generic; 003 004 ///005 /// A 星算法,公式:f = g + h; 006 /// 007 public class AStarUtils : MonoBehaviour 008 { 009 ///010 /// 直角移动的 g 值 011 /// 012 public const int STRAIGHT_COST = 10; 013 014 ///015 /// 对角移动的 g 值 016 /// 017 public const int DIAG_COST = 14; 018 019 ///020 /// 地图节点 021 /// 022 private Dictionarynodes; 023 024 /// 025 /// 地图的宽度(列数) 026 /// 027 private int numCols; 028 029 ///030 /// 地图的高度(行数) 031 /// 032 private int numRows; 033 034 ///035 /// 当前节点到结束节点的估价函数 036 /// 037 private IAStarHeuristic iAStarHeuristic; 038 039 ///040 /// 当前的寻路编号 041 /// 042 private int searchPathCheckNum; 043 044 ///045 /// 当前查找可移动范围的编号 046 /// 047 private int walkableRangeCheckNum; 048 049 ///050 /// 是否是四向寻路,默认为八向寻路 051 /// 052 private bool isFourWay; 053 054 ///055 /// 存放 "openList" 的最小二叉堆 056 /// 057 private BinaryHeapUtils binaryHeapUtils; 058 059 ///060 /// 获取节点 061 /// 062 ///The node. 063 /// Node x. 064 /// Node y. 065 public AStarNode GetNode(int nodeX, int nodeY) 066 { 067 string nodeKey = this.GetNodeKey (nodeX, nodeY); 068 if (this.nodes.ContainsKey (nodeKey)) 069 { 070 return this.nodes[nodeKey]; 071 } 072 return null; 073 } 074 075 ///076 /// 组装 Star Key 077 /// 078 ///The node key. 079 /// Node x. 080 /// Node y. 081 private string GetNodeKey(int nodeX, int nodeY) 082 { 083 return nodeX + ":" + nodeY; 084 } 085 086 ///087 /// 获取节点的相邻节点 088 /// 089 ///The adjacent nodes. 090 /// Node. 091 private IListGetAdjacentNodes(AStarNode node) 092 {
093 IListadjacentNodes = new List (); 094 095 int startX = 0; 096 int endX = 0; 097 int startY = 0; 098 int endY = 0; 099 100 startX = Mathf.Max(0, node.nodeX - 1); 101 endX = Mathf.Min(this.numCols - 1, node.nodeX + 1); 102 103 startY = Mathf.Max(0, node.nodeY - 1); 104 endY = Mathf.Min(this.numRows - 1, node.nodeY + 1); 105 106 AStarNode varNode = null; 107 for(int i = startX; i <= endX; i++) 108 { 109 for(int j = startY; j <= endY; j++) 110 { 111 varNode = this.nodes[this.GetNodeKey(i, j)]; 112 if(varNode != node) 113 { 114 if(this.isFourWay) 115 { 116 if(!(i == node.nodeX || j == node.nodeY)) 117 { 118 continue; 119 } 120 } 121 adjacentNodes.Add(varNode); 122 } 123 } 124 } 125 return adjacentNodes; 126 } 127 128 /// 129 /// 刷新节点的 links 属性 130 /// 131 /// Node. 132 private void RefreshNodeLinks(AStarNode node) 133 { 134 IListadjacentNodes = this.GetAdjacentNodes(node); 135 136 int cost = 0; 137 List links = new List (); 138 foreach(AStarNode nodeItem in adjacentNodes) 139 { 140 if(nodeItem.walkable) 141 { 142 if(node.nodeX != nodeItem.nodeX && node.nodeY != nodeItem.nodeY) 143 { 144 if(!this.nodes[this.GetNodeKey(node.nodeX, nodeItem.nodeY)].walkable || !this.nodes[this.GetNodeKey(nodeItem.nodeX, node.nodeY)].walkable) 145 { 146 continue; 147 }else 148 { 149 cost = DIAG_COST; 150 } 151 }else 152 { 153 cost = STRAIGHT_COST; 154 } 155 links.Add(new AStarLinkNode(nodeItem, cost)); 156 } 157 } 158 159 node.links = links; 160 } 161 162 /// 163 /// 刷新节点的相邻节点的 links 属性 164 /// 165 /// Node. 166 private void RefreshLinksOfAdjacentNodes(AStarNode node) 167 { 168 IListadjacentNodes = this.GetAdjacentNodes(node); 169 foreach(AStarNode adjacentNode in adjacentNodes) 170 { 171 this.RefreshNodeLinks(adjacentNode); 172 } 173 } 174 175 /// 176 /// 刷新所有节点的 links 属性 177 /// 178 private void RefreshLinksOfAllNodes() 179 { 180 for(int i = 0; i < this.numCols; i++) 181 { 182 for(int j = 0; j < this.numRows; j++) 183 { 184 this.RefreshNodeLinks(this.nodes[this.GetNodeKey(i, j)]); 185 } 186 } 187 } 188 189 ///190 /// 搜索路径 191 /// 192 ///193 /// Start node. 194 /// End node. 195 /// Now check number. 196 private bool SearchBaseBinaryHeap(AStarNode startNode, AStarNode endNode, int nowCheckNum) 197 { 198 int STATUS_CLOSED = nowCheckNum + 1; 199 200 this.binaryHeapUtils.Reset (); 201 202 startNode.g = 0; 203 startNode.f = startNode.g + this.iAStarHeuristic.Heuristic(startNode.nodeX, startNode.nodeY, endNode.nodeX, endNode.nodeY); 204 startNode.searchPathCheckNum = STATUS_CLOSED; 205 206 int g = 0; 207 AStarNode node = startNode; 208 AStarNode nodeItem; 209 210 while(node != endNode) 211 { 212 IList true , if base binary heap was searched,false otherwise.links = node.links; 213 foreach(AStarLinkNode link in links) 214 { 215 nodeItem = link.node; 216 g = node.g + link.cost; 217 218 // 如果已被检查过 219 if(nodeItem.searchPathCheckNum >= nowCheckNum) 220 { 221 if(nodeItem.g > g) 222 { 223 nodeItem.f = g + this.iAStarHeuristic.Heuristic(nodeItem.nodeX, nodeItem.nodeY, endNode.nodeX, endNode.nodeY); 224 nodeItem.g = g; 225 nodeItem.parentNode = node; 226 if(nodeItem.searchPathCheckNum == nowCheckNum) 227 { 228 this.binaryHeapUtils.ModifyNode(nodeItem.binaryHeapNode); 229 } 230 } 231 }else{ 232 nodeItem.f = g + this.iAStarHeuristic.Heuristic(nodeItem.nodeX, nodeItem.nodeY, endNode.nodeX, endNode.nodeY); 233 nodeItem.g = g; 234 nodeItem.parentNode = node; 235 236 nodeItem.binaryHeapNode = this.binaryHeapUtils.InsertNode(nodeItem); 237 nodeItem.searchPathCheckNum = nowCheckNum; 238 } 239 } 240 if(this.binaryHeapUtils.headNode != null) 241 { 242 node = this.binaryHeapUtils.PopNode(); 243 244 node.searchPathCheckNum = STATUS_CLOSED; 245 }else 246 { 247 return false; 248 } 249 } 250 return true; 251 } 252 253 /// 254 /// 寻路 255 /// 256 ///The path. 257 /// Start node. 258 /// End node. 259 public IListFindPath(AStarNode startNode, AStarNode endNode) 260 { 261 this.searchPathCheckNum += 2; 262 if(this.SearchBaseBinaryHeap(startNode, endNode, searchPathCheckNum)) 263 { 264 AStarNode currentNode = endNode; 265 IList pathList = new List (){ 266 startNode 267 }; 268 while(currentNode != startNode) 269 { 270 currentNode = currentNode.parentNode; 271 pathList.Add(currentNode); 272 } 273 274 return pathList; 275 } 276 return null; 277 } 278 279 /// 280 /// 返回节点在指定的代价内可移动的范围 281 /// 282 ///The range. 283 /// Start node. 284 /// Cost limit. 285 public IListWalkableRange(AStarNode startNode, int costLimit) 286 { 287 this.walkableRangeCheckNum ++; 288 289 int maxStep = (int)(costLimit / STRAIGHT_COST); 290 291 int startX = Mathf.Max(startNode.nodeX - maxStep, 0); 292 int endX = Mathf.Min(startNode.nodeX + maxStep, this.numCols - 1); 293 int startY = Mathf.Max(startNode.nodeY - maxStep, 0); 294 int endY = Mathf.Min(startNode.nodeY + maxStep, this.numRows - 1); 295 296 IList rangeList = new List (); 297 for(int i = startX; i <= endX; i++) 298 { 299 for(int j = startY; j <= endY; j++) 300 { 301 AStarNode nodeItem = this.nodes[this.GetNodeKey(i, j)]; 302 if(nodeItem.walkable && nodeItem.walkableRangeCheckNum != walkableRangeCheckNum) 303 { 304 IList pathList = this.FindPath(startNode, nodeItem); 305 if(pathList != null && pathList[pathList.Count - 1].f <= costLimit) 306 { 307 foreach(AStarNode node in pathList) 308 { 309 if(node.walkableRangeCheckNum != walkableRangeCheckNum) 310 { 311 node.walkableRangeCheckNum = walkableRangeCheckNum; 312 rangeList.Add(node); 313 } 314 } 315 } 316 } 317 } 318 } 319 return rangeList; 320 } 321 322 public AStarUtils(int numCols, int numRows, bool isFourWay = false) 323 { 324 this.numCols = numCols; 325 this.numRows = numRows; 326 this.isFourWay = isFourWay; 327 this.iAStarHeuristic = new AStarManhattanHeuristic (); 328 //this.iAStarHeuristic = new AStarDiagonalHeuristic (); 329 330 AStarNode node = null; 331 this.nodes = new Dictionary (); 332 for(int i = 0; i < this.numCols; i++) 333 { 334 for(int j = 0; j < this.numRows; j++) 335 { 336 node = new AStarNode(i, j); 337 node.AddHeuristic(this.RefreshLinksOfAdjacentNodes, node); 338 this.nodes.Add(this.GetNodeKey(i, j), node); 339 } 340 } 341 this.RefreshLinksOfAllNodes(); 342 this.binaryHeapUtils = new BinaryHeapUtils(numCols * numRows / 2); 343 } 344 }
BinaryHeapNode.cs 01 using UnityEngine; 02 using System.Collections; 03 04 ///05 /// 二叉堆节点 06 /// 07 public class BinaryHeapNode 08 { 09 ///10 /// 父节点 11 /// 12 public BinaryHeapNode parentNode; 13 14 ///15 /// 左子节点 16 /// 17 public BinaryHeapNode leftNode; 18 19 ///20 /// 右子节点 21 /// 22 public BinaryHeapNode rightNode; 23 24 ///25 /// 节点数据 26 /// 27 public AStarNode data; 28 29 public BinaryHeapNode(AStarNode data, BinaryHeapNode parentNode) 30 { 31 this.data = data; 32 this.parentNode = parentNode; 33 } 34 } BinaryHeapUtils.cs 001 using UnityEngine; 002 using System.Collections.Generic; 003 004 ///005 /// 最小二叉堆 006 /// 007 public class BinaryHeapUtils 008 { 009 ///010 /// 数组,用于保持树的平衡 011 /// 012 public IListnodes; 013 014 /// 015 /// 数组中正在使用的元素数目 016 /// 017 private int nodeLength; 018 019 ///020 /// 头节点 021 /// 022 public BinaryHeapNode headNode; 023 024 ///025 /// 节点对象池(缓存节点) 026 /// 027 private IListcacheNodes = new List (); 028 029 /// 030 /// 获得一个节点 031 /// 032 ///The node. 033 /// Data. 034 /// Parent node. 035 private BinaryHeapNode GetNode(AStarNode data, BinaryHeapNode parentNode) 036 { 037 BinaryHeapNode binaryHeapNode = null; 038 039 if(this.cacheNodes.Count > 0) 040 { 041 binaryHeapNode = this.cacheNodes[this.cacheNodes.Count - 1]; 042 043 binaryHeapNode.data = data; 044 binaryHeapNode.parentNode = parentNode; 045 046 this.cacheNodes.RemoveAt(this.cacheNodes.Count - 1); 047 } 048 else 049 { 050 binaryHeapNode = new BinaryHeapNode(data, parentNode); 051 } 052 return binaryHeapNode; 053 } 054 055 ///056 /// 存储节点 057 /// 058 /// Node. 059 private void CacheNode(BinaryHeapNode node) 060 { 061 node.parentNode = node.leftNode = node.rightNode = null; 062 node.data = null; 063 064 this.cacheNodes.Add (node); 065 } 066 067 ///068 /// 向下修正节点(向树叶方向修正节点) 069 /// 070 ///The to leaf. 071 /// Node. 072 private BinaryHeapNode ModifyToLeaf(BinaryHeapNode node) 073 { 074 AStarNode currentNodeData = node.data; 075 int currentNodeValue = currentNodeData.f; 076 077 BinaryHeapNode leftNode = null; 078 BinaryHeapNode rightNode = null; 079 080 while(true) 081 { 082 leftNode = node.leftNode; 083 rightNode = node.rightNode; 084 085 if(rightNode != null && leftNode != null && rightNode.data.f < leftNode.data.f) 086 { 087 if(currentNodeValue > rightNode.data.f) 088 { 089 node.data = rightNode.data; 090 node.data.binaryHeapNode = node; 091 node = rightNode; 092 } 093 else 094 { 095 break; 096 } 097 }else if(leftNode != null && leftNode.data.f < currentNodeValue) 098 { 099 node.data = leftNode.data; 100 node.data.binaryHeapNode = node; 101 node = leftNode; 102 }else 103 { 104 break; 105 } 106 } 107 node.data = currentNodeData; 108 node.data.binaryHeapNode = node; 109 110 return node; 111 } 112 113 ///114 /// 向上修正节点(向树根方向修正节点) 115 /// 116 ///The to root. 117 /// Node. 118 private BinaryHeapNode ModifyToRoot(BinaryHeapNode node) 119 { 120 AStarNode currentNodeData = node.data; 121 int currentNodeValue = currentNodeData.f; 122 123 BinaryHeapNode parentNode = node.parentNode; 124 while(parentNode != null) 125 { 126 if(currentNodeValue < parentNode.data.f) 127 { 128 node.data = parentNode.data; 129 node.data.binaryHeapNode = node; 130 131 node = node.parentNode; 132 parentNode = node.parentNode; 133 }else 134 { 135 break; 136 } 137 } 138 node.data = currentNodeData; 139 node.data.binaryHeapNode = node; 140 141 return node; 142 } 143 144 ///145 /// 修正节点 146 /// 147 ///The node. 148 /// Node. 149 public BinaryHeapNode ModifyNode(BinaryHeapNode node) 150 { 151 if(node.parentNode != null && node.parentNode.data.f > node.data.f) 152 { 153 return this.ModifyToRoot(node); 154 }else{ 155 return this.ModifyToLeaf(node); 156 } 157 } 158 159 ///160 /// 添加新节点 161 /// 162 ///The node. 163 /// Data. 164 public BinaryHeapNode InsertNode(AStarNode data) 165 { 166 if(this.headNode != null) 167 { 168 BinaryHeapNode parentNode = this.nodes[this.nodeLength >> 1]; 169 BinaryHeapNode node = this.GetNode(data, parentNode); 170 node.data.binaryHeapNode = node; 171 172 if(parentNode.leftNode == null) 173 { 174 parentNode.leftNode = node; 175 }else 176 { 177 parentNode.rightNode = node; 178 } 179 this.nodes[this.nodeLength] = node; 180 this.nodeLength ++; 181 return this.ModifyToRoot(node); 182 }else 183 { 184 this.nodes[1] = this.headNode = this.GetNode(data, null); 185 this.nodes.Add(this.headNode); 186 this.headNode.data.binaryHeapNode = this.headNode; 187 188 this.nodeLength = 2; 189 return this.headNode; 190 } 191 } 192 193 ///194 /// 取出最小值 195 /// 196 ///The node. 197 public AStarNode PopNode() 198 { 199 AStarNode minValue = this.headNode.data; 200 201 BinaryHeapNode lastNode = this.nodes[--this.nodeLength]; 202 203 if(lastNode != this.headNode) 204 { 205 BinaryHeapNode parentNode = lastNode.parentNode; 206 if(parentNode.leftNode == lastNode) 207 { 208 parentNode.leftNode = null; 209 }else{ 210 parentNode.rightNode = null; 211 } 212 this.headNode.data = lastNode.data; 213 this.headNode.data.binaryHeapNode = this.headNode; 214 215 this.ModifyToLeaf(this.headNode); 216 }else 217 { 218 this.headNode = null; 219 } 220 this.CacheNode(this.nodes[this.nodeLength]); 221 this.nodes[this.nodeLength] = null; 222 223 return minValue; 224 } 225 226 ///227 /// 重置 228 /// 229 public void Reset() 230 { 231 for(int index = 1; index < this.nodeLength; index++) 232 { 233 this.CacheNode(this.nodes[index]); 234 this.nodes[index] = null; 235 } 236 this.nodeLength = 1; 237 this.headNode = null; 238 } 239 240 // 小二叉堆 241 public BinaryHeapUtils(int cacheSize) 242 { 243 this.nodes = new List(cacheSize); 244 for(int index = 0; index < cacheSize; index ++) 245 { 246 this.nodes.Add(null); 247 this.cacheNodes.Add(new BinaryHeapNode(null, null)); 248 } 249 } 250 } IAStarHeuristic.cs 1 using UnityEngine; 2 using System.Collections; 3 4 public interface IAStarHeuristic 5 { 6 int Heuristic(int x1, int y1, int x2, int y2); 7 } IAStarUnit.cs view sourceprint? 01 using UnityEngine; 02 using System.Collections.Generic; 03 04 /// 05 /// 单位接口 06 /// 07 public interface IAStarUnit 08 { 09 ///10 /// 添加通过回调函数 11 /// 12 /// Callback. 13 void AddIsPassableChange(AStarCallback.IsPassableChangeCallback callback); 14 15 ///16 /// 移除通过回调函数 17 /// 18 /// Callback. 19 void RemoveIsPassableChange(AStarCallback.IsPassableChangeCallback callback); 20 21 ///22 /// 是否可以通过 23 /// 24 ///25 bool isPassable { get; set; } 26 } true if is passable; otherwise,false .