1 package
2 {
3 import flash.display.Sprite;
4 import flash.events.MouseEvent;
5 import flash.utils.clearInterval;
6 import flash.utils.getTimer;
7 import flash.utils.setInterval;
8
9 [SWF(width='600',height='600',frameRate=24)]
10 public class Astar extends Sprite
11 {
12 private var openList:Array = [];//开放列表
13 private var closeList:Object = {};//关闭列表
14 private var hGridCount:Number = 60;//横向网格数量
15 private var vGridCount:Number = 60;//水平网格数量
16 private var GridWidth:Number = 10;//网格的宽度
17 private var BlockCount:int = 512;
18 private var coordinate:Array;//全局坐标(网格坐标);
19 private var tx:int;//目标x坐标点;
20 private var ty:int;//目标y坐标点;
21 private var nx:int;//当前x坐标点;
22 private var ny:int;//当前Y坐标点;
23 private var scene:Sprite;//场景
24 private var player:Sprite;//控制对象
25 private var block:Sprite;//障碍物
26 private var path:Vector.<Object> = new Vector.<Object>();//行走路径
27 private var node:Object = {};//父节点
28 private var InID:int = 0;//intervalID
29
30 public function Astar()
31 {
32 _createScene();
33 _initCoordinate();
34 _createBlock();
35 _createPlayer();
36 stage.addEventListener(MouseEvent.CLICK,onClick);
37 }
38 /**
39 * 创建场景格子
40 *
41 */
42 private function _createScene():void
43 {
44 scene = new Sprite();
45 this.addChild(scene);
46 scene.graphics.clear();
47 scene.graphics.beginFill(0xffffff);
48 scene.graphics.lineStyle(1,0xcccccc);
49 for(var i:int = 0;i < hGridCount;i++)
50 {
51 scene.graphics.moveTo(i*GridWidth,0);
52 scene.graphics.lineTo(i*GridWidth,vGridCount*GridWidth);
53 }
54 for(i = 0;i < vGridCount;i++)
55 {
56 scene.graphics.moveTo(0,i*GridWidth);
57 scene.graphics.lineTo(hGridCount*GridWidth,i*GridWidth);
58 }
59 scene.graphics.endFill();
60 }
61 /**
62 * 初始化全局坐标 (网格坐标)
63 *
64 */
65 private function _initCoordinate():void
66 {
67 coordinate = [];
68 for (var i:int=0; i<hGridCount; i++)
69 {
70 coordinate.push([vGridCount]);
71 for (var j:int=0; j<vGridCount; j++)
72 {
73 coordinate[i][j] =true;//true为可行走点
74 }
75 }
76 }
77 /**
78 * 创建随机障碍物
79 *
80 */
81 private function _createBlock():void
82 {
83 block = new Sprite();
84 this.addChild(block);
85 block.graphics.clear();
86 block.graphics.beginFill(0x00ff00);
87 for(var i:int = 0;i < BlockCount;i++)
88 {
89 var bx:Number = int(vGridCount * Math.random());
90 var by:Number = int(hGridCount * Math.random());
91
92 block.graphics.drawRect(bx*GridWidth,by*GridWidth,GridWidth,GridWidth);
93 coordinate[bx][by] = false;
94 }
95 block.graphics.endFill();
96 }
97 /**
98 * 创建控制对象
99 *
100 */
101 private function _createPlayer():void
102 {
103 nx = int(Math.random() * hGridCount);//宽度范围内随机X坐标;
104 ny = int(Math.random() * vGridCount);//高度范围内随机Y坐标;
105 //判断坐标上是否有障碍物
106 if (!coordinate[nx][ny])
107 _createPlayer();//如有障碍物重新再来
108 else
109 {
110 player = new Sprite();
111 addChild(player);
112 player.graphics.beginFill(0x0000ff,1);
113 player.graphics.lineStyle(1,0x000000);
114 player.graphics.drawRect(0,0,GridWidth,GridWidth);
115 player.graphics.endFill();
116 player.x = nx * GridWidth;
117 player.y = ny * GridWidth;
118 }
119 }
120
121 private function onClick(e:MouseEvent):void
122 {
123 //目标点的坐标
124 tx = int(e.localX / GridWidth);
125 ty = int(e.localY / GridWidth);
126 //判断目标点是否障碍物;
127 if(coordinate[tx][ty])
128 {
129 path = new Vector.<Object>();//初始化路径
130 //获取开始点的坐标;
131 nx = player.x/GridWidth;
132 ny = player.y/GridWidth;
133 //初始化
134 node = {};//节点
135 closeList = {}; //关闭列表
136 openList = [];//开放列表;
137
138 seekRoad();
139 InID = setInterval(walk,50);
140 }
141 else
142 trace("目标点不可到达");
143 }
144
145 private function seekRoad():void
146 {
147 //创建开始节点
148 node = createNode(nx,ny,0,null);
149 //把开始节放入关闭列表;
150 closeList[node.nx + "_" + node.ny] = node;
151 //开始循环;有两种情况退出循环:一是找到目标点,另一种是控制对象本身就在死角无法达到目标点
152 while (true)
153 {
154 if (nx == tx && ny == ty)
155 { //循环取父节点;
156 while(node!=null){
157 //把节点加入到路径
158 path.push(node);
159 //取父节点
160 node = node.pNode;
161 }
162 //退出循环;
163 break;
164 }
165 //创建八方向节点加入到开放列表;
166 pushOpenList(createNode(nx ,ny+1,10,node));//下
167 pushOpenList(createNode(nx-1,ny+1,14,node));//左下
168 pushOpenList(createNode(nx-1,ny ,10,node));//左
169 pushOpenList(createNode(nx-1,ny-1,14,node));//左上
170 pushOpenList(createNode(nx ,ny-1,10,node));//上
171 pushOpenList(createNode(nx+1,ny-1,14,node));//右上
172 pushOpenList(createNode(nx+1,ny ,10,node));//右
173 pushOpenList(createNode(nx+1,ny+1,14,node));//右下
174 //如果开放列表为空,退出循环,说明本身就在死角里面
175 if (openList.length == 0)
176 break;
177 //排序取出f值最小的节点;
178 openList.sortOn("f",Array.NUMERIC);
179 node = openList.shift();
180 //把当前节点坐标设为下次循环的开始点坐标;
181 nx = node.nx;
182 ny = node.ny;
183 closeList[node.nx + "_" + node.ny] = node;//把节点放到关闭列表;
184 }
185
186 path.reverse(); //倒序排列
187 //清空释放内存;
188 node = null;
189 closeList = null;
190 openList = null;
191 }
192 /**
193 * 加入开放列表
194 * @param nd
195 * @return
196 *
197 */
198 private function pushOpenList(nd:Object):void
199 {
200 if (nd != null)
201 {
202 openList.push(nd);
203 openList[nd.nx+"_"+nd.ny] = nd;
204 }
205 }
206
207 private function createNode(ix:int,iy:int,ng:int,pnd:Object):Object
208 {
209 //判断是否出格,是否障碍物,是否关闭或已开启;
210 if (ix < 0 || iy < 0 || ix >= hGridCount || iy >= vGridCount || !coordinate[ix][iy]|| closeList[ix + "_" + iy]||openList[ix+"_"+iy])
211 return null;
212
213 var node:Object = {};
214 node.h = (Math.abs(tx-ix)+Math.abs(ty-iy))*10;
215 if(pnd)
216 {
217 //判断走斜角时上下左右是否有障碍物;
218 if(ng == 14)
219 if(!coordinate[pnd.nx][iy]||!coordinate[ix][pnd.ny])
220 return null
221 node.g = ng + pnd.g;
222 node.f = node.g + node.h;
223 }
224 else
225 {
226 node.g = 0;
227 node.h = 0;
228 node.f = 0
229 }
230
231 node.nx = ix;
232 node.ny = iy;
233 node.pNode = pnd;
234
235 return node;
236 }
237
238 private function walk():void
239 {
240 if (path.length == 0)
241 clearInterval(InID);
242 else
243 {
244 var obj:Object = path.shift();
245 player.x = obj.nx * GridWidth;
246 player.y = obj.ny * GridWidth;
247 obj = null
248 }
249 }
250 }
251 }
修改自:http://bbs.9ria.com/thread-84171-1-1.html
主要做了一些精简并稍做优化,添加了少许注释,以后会详细写一篇帖子来讲解这段代码。