astar寻路算法优化
/** A星算法: @param startX,startY 起点 @param endX,endY 终点 @param distance 小于等于这个距离则寻路成功 @author aerror */ private static const STATE_NULL:uint = 0; private static const STATE_CLOSE:uint = 1; public function findPath(startX:int, startY:int, endX:int, endY:int, distance:int ):ByteArray { var ret:ByteArray = new ByteArray(); ret.endian = Endian.LITTLE_ENDIAN; var width:uint = iwidth; var height:uint = iheight; var nodelist:PathNodeFactoryVector = new PathNodeFactoryVector(width * height); var key:uint; var opneListSortedArr:Array = new Array(); var opneNum:int=0; var minIndex:uint = 0; var stateMap:Vector.<uint>= new Vector.<uint>(width * height); var startPoint:uint = nodelist.createNode(startX,startY,0,0,PathNodeFactoryVector.NULL); key = x + width * y; opneListSortedArr.push(startPoint); stateMap[key]=startPoint; opneNum = 1; minIndex = 0; var found_end_point:uint = PathNodeFactoryVector.NULL; var x:int; var y:int; var g:int; var h:Number; var f:int; var i:int; var min:uint = PathNodeFactoryVector.NULL; while(true) { var min_key:uint; var min_x:uint; var min_y:uint; var min_f:uint; var min_g:uint; //find the min g+h point // if(opneNum >0) { //remove from openlist; min = opneListSortedArr.shift(); min_x = nodelist.getNodeX(min); min_y = nodelist.getNodeY(min); min_g = nodelist.getNodeG(min); min_key = min_x + width * min_y; opneNum--; } else { trace("FIND PATH FAILED"); break; } //add to close list; stateMap[min_key] = STATE_CLOSE;// = min; //add nearby point to openlist for( i = 0;i<8;i++) { x = min_x + nearby[i*3]; y = min_y + nearby[i*3+1]; key = x + width * y; //calc h // h = ((endX<x)?(x-endX):(endX-x)) + ((endY<y)?(y-endY):(endY-y)); //we find the path when openlist contains the endpoint // if(h<=distance) { found_end_point = nodelist.createNode(x,y,0,0,min); break; } h = h*10; if(x >= width || x < 0 //out of bounds ? || y >= height || y < 0//out of bounds ? || obstacles[key]!=0 //is obstacle ? ) { continue; } // if in close list? var state:uint = stateMap[key]; if(state==STATE_CLOSE) { continue; } //calc g // g = (nearby[i*3+2]+min_g); f = g+h; //check if new point or old // var newPt:uint; //the old point //key key its g value,update if new g is less // if(state==STATE_NULL) { //the new point // newPt = nodelist.createNode(x,y,g,f,min); stateMap[key] = newPt; nodelist.sortInsert(opneListSortedArr,newPt,0,opneNum); opneNum++; } else if(g<nodelist.getNodeG(state)) { newPt = nodelist.createNode(x,y,g,f,min); nodelist.sortRemove(opneListSortedArr,state,0,opneNum); stateMap[key] = newPt; nodelist.sortInsert(opneListSortedArr,newPt,0,opneNum-1); } } //just break the upper loop // if(found_end_point !=PathNodeFactoryVector.NULL) { break; } } //encode it to bytearray. // if(found_end_point !=PathNodeFactoryVector.NULL) { var pt:uint = found_end_point; var num:int=0; while(pt!=PathNodeFactoryVector.NULL) { num++; pt =nodelist.getNodeParent(pt); } ret.length = num*4; pt = found_end_point; i =0; while(pt!=PathNodeFactoryVector.NULL) { ret.position = (num-i-1)*4; ret.writeShort(nodelist.getNodeX(pt)); ret.writeShort(nodelist.getNodeY(pt)); i++; pt = nodelist.getNodeParent(pt); } ret.position = 0; } //clear used memory // trace("used length :" + nodelist.getUsedLength() + " open num " + opneListSortedArr.length); nodelist.clear(); stateMap.length = 0; opneListSortedArr.length =0; return ret; } 路点内存管理器: public class PathNodeFactoryVector { public static const NULL:uint = 0; private var mem:Vector.<uint>; private var writePosition:uint =0; public function PathNodeFactoryVector(max:uint) { mem = new Vector.<uint>(max*4+4); writePosition = 4; } public function getNodeX(id:uint):uint { return mem[id]&0xffff; } public function getNodeY(id:uint):uint { return mem[id]>>16 &0xffff; } public function getNodeG(id:uint):uint { return mem[id+1]; } public function getNodeF(id:uint):uint { return mem[id+2]; } public function getNodeParent(id:uint):uint { return mem[id+3]; } public function createNode(_x:uint,_y:uint,_g:uint, _f:uint,_linkParent:uint):uint { mem[writePosition + 0] = (_x | _y<<16 ); mem[writePosition + 1]= _g; mem[writePosition + 2]= _f; mem[writePosition + 3]= _linkParent; writePosition += 4; return writePosition-4; } public function checkOK(arr:Array):Boolean { for(var i:int=0;i < arr.length-1;i++) { if(getNodeF(arr[i]) >getNodeF(arr[i+1])) { return false; } } return true; } public function sortInsert(arr:Array, newPt:uint, begin:int, end:int):void { //optimize for empty array if(arr.length==0) { arr.push(newPt); return; } var new_F:uint = getNodeF(newPt); var cur_F:uint = getNodeF(arr[begin]); //optimize for sorted inserting with less if(new_F <= cur_F ) { arr.splice(0,0,newPt); return; } //optimize for sorted inserting with larger cur_F = getNodeF(arr[end-1]); if(new_F >cur_F) { arr.splice(end,0,newPt); return; } else if(new_F == cur_F) { arr.splice(end-1,0,newPt); return; } while(true) { if(begin==end) { cur_F = getNodeF(arr[begin]); if(new_F > cur_F) arr.splice(begin+1,0,newPt); else arr.splice(begin,0,newPt); return ; } //find a place var mid:int = begin+(end-begin)/2; cur_F =getNodeF(arr[mid]); if(new_F < cur_F) { end = mid; } else if(new_F > cur_F) { begin = mid +1; } else { arr.splice(mid,0,newPt); return; } } } public function sortRemove(arr:Array, oldPt:uint, begin:int, end:int):void { var old_f:uint = getNodeF(oldPt); var i:int; while(true) { //find a place var mid:int = begin+(end-begin)/2; var cur_f:uint = getNodeF(arr[mid]); if(old_f < cur_f) { end = mid; } else if(old_f > cur_f) { begin = mid +1; } else { for(i =mid; i<end ; i++) { if(oldPt==arr[i]) { arr.splice(i,1); return ; } } for(i = mid-1; i>=0 ; i--) { if(oldPt==arr[i]) { arr.splice(i,1); return ; } } return ; } } } public function clear():void { this.mem.length = 0; } public function getUsedLength():uint { return this.writePosition; } public function dumpArray(opneListSortedArr:Array):void { for(var j:int =0;j<opneListSortedArr.length;j++) { trace(getNodeF(opneListSortedArr[j])); } } }
优化思路:
a.开包(open list)算法优化:
线性查找-->
二叉堆(binary heap 容器:Array->Vector)->
二分排序插入/删除(容器:Array) b. 障碍点容器优化:
dictionary(1维) ->dictionary(2维)-- array(1维)->array(2维)->bitmapdata->bytearray(8位对齐)->byteArrayarray(32位对齐)->vector. <int> c. 闭包(close list)容器优化:
dictionary(1维) -> array(1维)->bitmapdata->vector. <int> d. 过程生成的路点对象内存管理优化:
AS动态对象(Object)->非动态对象(自定义PathNode对象)->使用bytearray自己管理内存分配对象-->使用Vector自已管理内存分配对象. e. 评估函数:
标准(F = G+H, G=Parent.G+DIR_G, H = (ABS(X1-X)+ABS(Y1-Y) )*10 )
上述优化基本上是 左->右 == 慢->快
测试结果部分 单位:毫秒
地图大小:500x500地图:
从41条测试线路的平均值结果, 足足快3倍, 比较未优化但是快了25倍以上
未优化 10886 ms 所谓终极优化 1361.414634 ms 二分插入排序 ByteArray做内存管理 (32bit对齐 ) 479.195122 ms 二分插入排序Vector做内存管理 447.2439024 ms
startX |
startY |
endX |
endY |
距离 |
未优化 |
所谓 终极 优化 |
二分插入排序ByteArray做内存管理(32bit对齐) |
二分插入排序 Vector做内存管理 |
36 |
32 |
113 |
125 |
120.7394 |
17 |
8 |
10 |
11 |
113 |
125 |
34 |
29 |
124.3262 |
16 |
7 |
11 |
11 |
34 |
29 |
469 |
463 |
614.4762 |
9133 |
1338 |
544 |
493 |
469 |
463 |
152 |
155 |
441.9876 |
超时 |
8536 |
2810 |
2560 |
152 |
155 |
169 |
165 |
19.72308 |
17763 |
2743 |
957 |
894 |
169 |
165 |
465 |
463 |
420.0238 |
1159 |
219 |
101 |
97 |
465 |
463 |
165 |
143 |
438.6342 |
超时 |
8385 |
2594 |
2470 |
165 |
143 |
220 |
146 |
55.08176 |
19685 |
2958 |
1031 |
965 |
220 |
146 |
229 |
139 |
11.40175 |
725 |
234 |
124 |
116 |
229 |
139 |
111 |
477 |
358.0056 |
827 |
168 |
72 |
70 |
111 |
477 |
327 |
350 |
250.5694 |
1705 |
364 |
164 |
158 |
327 |
350 |
319 |
340 |
12.80625 |
210 |
71 |
38 |
38 |
319 |
340 |
464 |
477 |
199.4843 |
51 |
20 |
18 |
17 |
464 |
477 |
71 |
26 |
598.2057 |
20912 |
2370 |
801 |
774 |
71 |
26 |
465 |
468 |
592.1149 |
6158 |
922 |
362 |
348 |
465 |
468 |
119 |
188 |
445.1022 |
超时 |
7749 |
2499 |
2372 |
119 |
188 |
219 |
314 |
160.8602 |
3625 |
804 |
309 |
286 |
219 |
314 |
79 |
401 |
164.8302 |
28 |
11 |
10 |
12 |
79 |
401 |
229 |
309 |
175.9659 |
141 |
35 |
24 |
23 |
229 |
309 |
91 |
432 |
184.8594 |
41 |
13 |
13 |
12 |
91 |
432 |
65 |
446 |
29.52965 |
2 |
1 |
7 |
6 |
65 |
446 |
227 |
310 |
211.5183 |
100 |
21 |
16 |
14 |
227 |
310 |
62 |
444 |
212.5582 |
78 |
15 |
13 |
14 |
62 |
444 |
354 |
26 |
509.8902 |
644 |
89 |
38 |
36 |
354 |
26 |
479 |
27 |
125.004 |
32 |
14 |
14 |
13 |
479 |
27 |
27 |
469 |
632.193 |
352 |
48 |
29 |
29 |
27 |
469 |
10 |
18 |
451.3203 |
3733 |
936 |
384 |
354 |
10 |
18 |
473 |
463 |
642.1791 |
9152 |
1331 |
534 |
493 |
473 |
463 |
100 |
260 |
424.6622 |
5947 |
782 |
268 |
255 |
100 |
260 |
234 |
152 |
172.1046 |
2182 |
531 |
241 |
226 |
234 |
152 |
248 |
135 |
22.02272 |
超时 |
0 |
113 |
0 |
234 |
152 |
249 |
137 |
21.2132 |
598 |
193 |
113 |
104 |
249 |
137 |
120 |
234 |
161.4001 |
5200 |
951 |
401 |
377 |
120 |
234 |
154 |
203 |
46.01087 |
1557 |
418 |
214 |
201 |
154 |
203 |
404 |
237 |
252.3014 |
4173 |
882 |
357 |
335 |
404 |
237 |
11 |
15 |
451.3679 |
8876 |
1331 |
572 |
543 |
11 |
15 |
230 |
409 |
450.7738 |
55030 |
7070 |
2308 |
2179 |
230 |
409 |
240 |
97 |
312.1602 |
1541 |
325 |
161 |
152 |
240 |
97 |
25 |
19 |
228.7116 |
1819 |
375 |
181 |
167 |
25 |
19 |
148 |
156 |
184.1141 |
29 |
10 |
12 |
9 |
148 |
156 |
169 |
188 |
38.27532 |
23085 |
3540 |
1179 |
1103 |
平均ms |
|
|
|
|
10886 |
1361.415 |
479.2 |
447 |
代码: