A*尋路算法代碼實現


A*尋路的原理,網上很多,可以看這里

  1 var A_STAR_DISTANCE = 7; //像素大小,越小越精確,同時越耗時
  2 var A_STAR_G_EXPEND_MIN = 10; //上下左右G值消耗數
  3 var A_STAR_G_EXPEND_MAX = 14; //斜角G值消耗數
  4 
  5 var HelloWorldLayer = cc.Layer.extend({
  6 sprite:null, //角色
  7 aStarPathArray:[], //最終角色要行走的路徑
  8 aStarBarrierArray:[], //地圖障礙物
  9 testNumber:1,
 10 ctor:function () {
 11 //////////////////////////////
 12 // 1. super init first
 13 this._super();
 14 /////////////////////////////
 15 // 2. add a menu item with "X" image, which is clicked to quit the program
 16 // you may modify it.
 17 // ask director the window size
 18 var size = cc.director.getWinSize();
 19 
 20 this.sprite = cc.Sprite.create(res.Plane_png); //角色初始化
 21 this.sprite.attr({
 22 x: 150,
 23 y: 50,
 24 rotation: 90
 25 });
 26 this.addChild(this.sprite, 0);
 27 
 28 var barrier1 = cc.rect(200,50,50,350); //繪制障礙物
 29 var barrier2 = cc.rect(250,50,350,50);
 30 var barrier3 = cc.rect(250,350,350,50);
 31 this.aStarBarrierArray.push(barrier1);
 32 this.aStarBarrierArray.push(barrier2);
 33 this.aStarBarrierArray.push(barrier3);
 34 
 35 var drawBarrier = cc.DrawNode.create(); //在屏幕上顯示障礙物
 36 this.addChild(drawBarrier, 10);
 37 var vertices = [cc.p(200,50),cc.p(600,50),cc.p(600,100),cc.p(250,100),cc.p(250,350),cc.p(600,350),cc.p(600,400),cc.p(200,400)];
 38 drawBarrier.drawPoly(vertices,null,2,cc.color(255,0,0,255));
 39 
 40 if ('mouse' in cc.sys.capabilities)
 41 cc.eventManager.addListener({
 42 event: cc.EventListener.MOUSE,
 43 onMouseUp:function(event){
 44 if(event.getButton() != undefined)
 45 {
 46 var t = new Date().getTime();
 47 event.getCurrentTarget().getStartAndEndPoint(event); //A*算法開始
 48 cc.log("算法耗時:"+(new Date().getTime() - t)+"ms"); //計算起點到終點的算法耗時
 49 }
 50 }
 51 }, this);
 52 
 53 
 54 return true;
 55 },
 56 getStartAndEndPoint:function (event) { //得到起始點和終點坐標
 57 var sp = {coordX:parseInt(this.sprite.x,10),coordY:parseInt(this.sprite.y,10)};
 58 var ep = {coordX:parseInt(event.getLocation().x,10),coordY:parseInt(event.getLocation().y,10)};
 59 var endPointIsObstacle = false; //判斷終點是否在障礙物上,是的話就提示路徑走不了
 60 for (var theBarrierIndex=0; theBarrierIndex<this.aStarBarrierArray.length; theBarrierIndex++){
 61 if(cc.rectContainsPoint(this.aStarBarrierArray[theBarrierIndex],cc.p(ep.coordX,ep.coordY)))
 62 {
 63 endPointIsObstacle = true;
 64 cc.log("你要去的位置有障礙物,請換條路線");
 65 break;
 66 }
 67 }
 68 if(!endPointIsObstacle)
 69 this.findingPath(sp,ep);
 70 },
 71 findingPath:function(startPoint,endPoint){ //A*算法
 72 var openList = []; //初始化開啟列表
 73 var closeList = []; //初始化關閉列表
 74 startPoint.ag = 0;
 75 startPoint.ah = 0;
 76 startPoint.af = startPoint.ag + startPoint.ah; //起點的G,H,F值為0
 77 openList.push(startPoint); //起點加入開啟列表
 78 var findTheWay = false;
 79 do{
 80 var centerNode = this.findMinNode(openList); //尋找F值最低的節點
 81 openList.remove(centerNode); //將此節點從開啟列表中刪除,為了下次遍歷開啟列表的時候不再出現此節點
 82 closeList.push(centerNode); //並將此節點加入到關閉列表
 83 for(var i=0;i<8;i++) //遍歷此節點周圍的節點,並給這些節點加入坐標屬性和G值
 84 {
 85 var aroundNode = {};
 86 switch (i){
 87 case 0:
 88 aroundNode.coordX = centerNode.coordX+A_STAR_DISTANCE; //坐標屬性
 89 aroundNode.coordY = centerNode.coordY+A_STAR_DISTANCE;
 90 break;
 91 case 1:
 92 aroundNode.coordX = centerNode.coordX+A_STAR_DISTANCE;
 93 aroundNode.coordY = centerNode.coordY;
 94 break;
 95 case 2:
 96 aroundNode.coordX = centerNode.coordX+A_STAR_DISTANCE;
 97 aroundNode.coordY = centerNode.coordY-A_STAR_DISTANCE;
 98 break;
 99 case 3:
100 aroundNode.coordX = centerNode.coordX;
101 aroundNode.coordY = centerNode.coordY-A_STAR_DISTANCE;
102 break;
103 case 4:
104 aroundNode.coordX = centerNode.coordX-A_STAR_DISTANCE;
105 aroundNode.coordY = centerNode.coordY-A_STAR_DISTANCE;
106 break;
107 case 5:
108 aroundNode.coordX = centerNode.coordX-A_STAR_DISTANCE;
109 aroundNode.coordY = centerNode.coordY;
110 break;
111 case 6:
112 aroundNode.coordX = centerNode.coordX-A_STAR_DISTANCE;
113 aroundNode.coordY = centerNode.coordY+A_STAR_DISTANCE;
114 break;
115 case 7:
116 aroundNode.coordX = centerNode.coordX;
117 aroundNode.coordY = centerNode.coordY+A_STAR_DISTANCE;
118 break;
119 }
120 for (var barrierIndex=0; barrierIndex<this.aStarBarrierArray.length; barrierIndex++){
121 aroundNode.isOb = cc.rectContainsPoint(this.aStarBarrierArray[barrierIndex],cc.p(aroundNode.coordX,aroundNode.coordY)); //判斷當前節點是否在障礙物形成的方框里
122 if(aroundNode.isOb)
123 break;
124 }
125 if (aroundNode.isOb){ //如果是障礙物,跳過
126 
127 }
128 else if(closeList.hasObject(aroundNode)){ //如果在關閉列表里,跳過
129 
130 }
131 else if(!openList.hasObject(aroundNode)){ //如果不在開啟列表里,加入到開啟列表
132 aroundNode.parentPath = centerNode;
133 if (Math.abs(aroundNode.coordX-endPoint.coordX)<=A_STAR_DISTANCE/2 && Math.abs(aroundNode.coordY-endPoint.coordY)<=A_STAR_DISTANCE/2) //如果節點和終點的值相近,那么A*算法結束,得到路徑
134 {
135 findTheWay = true;
136 var pathArry = [];
137 this.gettingAStarPath(aroundNode,pathArry); //尋找路徑
138 pathArry.splice(0,0,{starX:endPoint.coordX,starY:endPoint.coordY}); //加終點到數組頭部
139 pathArry.splice(pathArry.length-1,1); //刪一項數組底部的起點數據,此時的數組是最終的路徑數組
140 
141 this.aStarPathArray = [];
142 this.aStarPathArray = pathArry;
143 this.aStarPathArray.theIndex = this.aStarPathArray.length;
144 
145 this.unschedule(this.thePathSelector);
146 this.schedule(this.thePathSelector,null,pathArry.length-1);
147 break; //找到最短路徑並跳出循環
148 }
149 if (aroundNode.coordX!=centerNode.coordX && aroundNode.coordY!=centerNode.coordY) //確定中心節點和周圍節點形成的角度,正交G值消耗10*像素,斜角G值消耗14*像素
150 aroundNode.ag = centerNode.ag + A_STAR_G_EXPEND_MAX*A_STAR_DISTANCE;
151 else
152 aroundNode.ag = centerNode.ag + A_STAR_G_EXPEND_MIN*A_STAR_DISTANCE;
153 aroundNode.af = this.getAF(aroundNode,endPoint);
154 openList.push(aroundNode);
155 }
156 else if(openList.hasObject(aroundNode)){ //如果在開啟列表里
157 var newExpend = A_STAR_G_EXPEND_MIN*A_STAR_DISTANCE;
158 if (aroundNode.coordX!=centerNode.coordX && aroundNode.coordY!=centerNode.coordY) //確定中心節點和周圍節點形成的角度,正交G值消耗10*像素,斜角G值消耗14*像素
159 newExpend = A_STAR_G_EXPEND_MAX*A_STAR_DISTANCE;
160 if (centerNode.ag + newExpend < aroundNode.ag){ //如果新的g值小於周圍節點本身的g值,那么周圍節點的父節點改為當前中心節點,並重新計算其F值
161 aroundNode.parentPath = centerNode;
162 aroundNode.ag = centerNode.ag + newExpend;
163 aroundNode.af = this.getAF(aroundNode,endPoint);
164 }
165 }
166 }
167 }while(!findTheWay)
168 
169 },
170 findMinNode:function(openListArray){
171 var minNode = openListArray[0];
172 for (var i=0;i<openListArray.length;i++)
173 {
174 if (minNode.af>openListArray[i].af) minNode=openListArray[i];
175 }
176 return minNode;
177 },
178 getAF:function(thisNode,endNode){
179 var aHExpend = (Math.abs(thisNode.coordX-endNode.coordX) + Math.abs(thisNode.coordY-endNode.coordY))*A_STAR_G_EXPEND_MIN;
180 return aHExpend+thisNode.ag;
181 },
182 gettingAStarPath:function(laseNode,array){
183 if(laseNode.parentPath != null)
184 {
185 array.push({starX:laseNode.parentPath.coordX,starY:laseNode.parentPath.coordY});
186 this.gettingAStarPath(laseNode.parentPath,array);
187 }
188 },
189 thePathSelector:function(){
190 this.roleRunThePath(this.aStarPathArray);
191 },
192 roleRunThePath:function(array){
193 this.sprite.x = array[--array.theIndex].starX;
194 this.sprite.y = array[array.theIndex].starY;
195 }
196 });
197 
198 var HelloWorldScene = cc.Scene.extend({
199 onEnter:function () {
200 this._super();
201 var layer = new HelloWorldLayer();
202 this.addChild(layer);
203 }
204 });
205 
206 //這里給Array數組添加3個實例方法
207 Array.prototype.aStarIndexOf = function(val) { //通過對象尋找index值
208 for (var i = 0; i < this.length; i++) {
209 if (this[i].coordX==val.coordX && this[i].coordY==val.coordY) return i;
210 }
211 return -1;
212 };
213 Array.prototype.remove = function(val) { //刪除相應的對象
214 var index = this.aStarIndexOf(val);
215 if (index > -1) {
216 this.splice(index, 1);
217 }
218 };
219 
220 Array.prototype.hasObject = function(val){ //判斷是否是同一個對象
221 for (var i = 0; i < this.length; i++){
222 if (this[i].coordX==val.coordX && this[i].coordY==val.coordY)
223 return true;
224 }
225 return false;
226 };

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM