import flash.geom.Point; import flash.display.Sprite; import com.qrpg.Algorithm.PathFinding; var t:int; var field:Sprite = new Sprite();//地图图层 addChild(field); var linePath:Sprite = new Sprite();//网格图层 addChild(linePath); var allNode:Array = []; //节点数据(小格子) var map:Array = []; //网格 //随机制定网格,35行60列 for (var mapy:int=0; mapy<35; mapy++) { if (map[mapy]==undefined) { map[mapy] = []; } //随机生成网格 for (var mapx:int=0; mapx<60; mapx++) { map[mapy][mapx] = Math.random()>.25 ? 0 : 1 ; } } //var map:Array=[[0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0],[0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,0],[0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,1,0,0,1,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1],[0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,0,0,1],[0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0],[1,1,0,0,0,1,1,0,0,0,1,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,1,0,1,0,0,0,0,1,1,0,0,0,0],[1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0],[0,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,1,1,1,0,1,1,0,0,0],[0,1,0,1,0,0,0,1,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1],[0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,0,1,1,0,0,1,0,0,1,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0],[1,1,0,0,0,0,1,0,0,0,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,1,1,0,1,0,1,1,0,0,1,1,0,0,0,0],[0,1,0,1,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,0,1,1,0,1,0,0,0,1,1,0,0,1,0,1,0,1,1,1,1,0,0,0,1,1,0,1,0,0],[1,1,0,0,0,0,1,1,0,0,0,1,0,0,0,1,1,1,0,1,1,0,0,1,0,1,1,0,0,0,0,0,0,1,0,0,0,1,1,1,0,1,0,1,0,1,0,0,1,0,0,0,0,0,1,1,0,0,0,0],[0,1,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,1,0,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0],[1,0,1,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,1,1,0,1,0,1,1,1,0,0,0,0,1,0,0,1,1,0,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,0,1,0,1,0,1,0,0,1,0,0,0,1,1,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1],[0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0],[1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0],[1,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,1,0,1,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,0,0,1,0,0,0,1,0],[0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0],[0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,1,0,1],[0,1,1,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,1,0,1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,1,0,1,0,0,1,0,0,0,0,0],[0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,0],[0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,1,0,0,0,1,1,0,1,0,0,1,0,1,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,1,0,0,0,0,1],[0,0,0,0,1,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,1,0,1,0,0],[0,0,1,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1],[0,0,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0],[0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,1,1,0,1,1,0,0,0,1,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0],[0,0,0,0,1,0,0,0,0,1,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0],[1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0,1,0,0,0,0,0,0,0,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,1,1,0,0,0,0,0,0,0,1],[0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,0,0,0,0,0,1,1,1,1,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,1,1,1,0,0,0,0,0,0,0,0],[1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,1,0,0,0,1,1,1,0,1,0,0,1,1,0],[0,0,0,1,0,0,1,0,0,1,1,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,1,1,0,0,1,0,0,1,0,0,0,0,0,1,0,0]]; var w:int = map[0].length; //列长度 var h:int = map.length; //行长度 var path:Array; //路径1 var path2:Array; //路径2 var startpoint:Point = new Point(); //程序启动时的始点 var findPath:PathFinding = new PathFinding(map); //创建包含网格地图的数组(元素是对象) //在界面上画出节点 for (var py:int=0; py<h; py++) { if (allNode[py]==undefined) { allNode[py] = []; } for (var px:int=0; px<w; px++) { allNode[py].push(field.addChildAt(new node(), field.numChildren)); //把新建的节点加入到每一行中,列不断增加 allNode[py][px].p = new Point(px, py); //用数据索引新建一个当前点的代表坐标点 allNode[py][px].x=px*10; //设定此节点的坐标 allNode[py][px].y=py*10; //allNode[py][px].gotoAndStop(map[py][px]==0?1:2); //原理和下面相同 if (map[py][px]==0) { //判断是否不是障碍 allNode[py][px].stop(); //如果不是障碍,则停止增加节点,增加事件监听 allNode[py][px].addEventListener(MouseEvent.CLICK, findHandler); } else { allNode[py][px].gotoAndStop(2);//障碍进入第二帧 } } } field.x = 30; //设定图层开始显示的坐标 field.y = 10; linePath.x = field.x+5; //第一个节点的中心点 linePath.y = field.y+5; function findHandler(e:MouseEvent):void { t = getTimer(); //取得当前的毫秒数 for (var y:int=0; y<h; y++) { for (var x:int=0; x<w; x++) { if (allNode[y][x].currentFrame>2) { //不允许 每个节点的帧数大于2 allNode[y][x].gotoAndStop(1); } } } //指定默认的起始点和当前点击的节点的对应P点(*10可得到准确左上角路径),返回一个数组 path = findPath.path4(startpoint, e.currentTarget.p); var len:int = path.length; //把路径的格子设为绿色 for (var i:int=0; i<len; i++) { allNode[path[i].y][path[i].x].gotoAndStop(3); } if (len==0) { trace_mc.text = "无法到达!"; //如果返回路径的长度为0,则表示路径为0 ,不能到达 } else { //path2 = findPath.optimizePath(); path2=path; //画出路径上的白色线条 var len2:int = path2.length; linePath.graphics.clear(); linePath.graphics.lineStyle(2,0xffffff,1); for (var j:int=0; j<len2; j++) { if (j==0) { linePath.graphics.moveTo(path2[j].x*10, path2[j].y*10); } else { linePath.graphics.lineTo(path2[j].x*10, path2[j].y*10); } } startpoint = e.currentTarget.p; trace_mc.text = "经过格子"+len+"个,"; } //计算寻路用了多少时间 trace_mc.appendText("所用时间:"+(getTimer()-t)+"毫秒。"); } reset_mc.addEventListener(MouseEvent.CLICK, resetHandler); function resetHandler(e:MouseEvent):void { } // package com.qrpg.Algorithm{ import flash.geom.Point; import com.qrpg.Algorithm.Diagonal; public class PathFinding { private var _map:Array;//网格地图(元素是对象) private var _w:int;//网格地图的宽 private var _h:int;//网格地图的高 private var _open:Array;//开放列表 private var _starPoint:Object; private var _endPoint:Object; public var path:Array = [];//计算出的路径 public function PathFinding(map:Array) { _map = []; //接收网格地图 _w = map[0].length; _h = map.length; for (var y:int=0; y<_h; y++) { if (_map[y]==undefined) { _map[y] = []; } //把每个节点创建成对象,再保存到数组里面 for (var x:int=0; x<_w; x++) { _map[y][x] = {x:x, y:y, value:map[y][x], block:false, open:false, value_g:0, value_h:0, value_f:0, nodeparent:null}; } } } //四方向寻路 public function path4(star:Point, end:Point):Array { path = []; _starPoint = _map[star.y][star.x]; //取得起始点和结束点 _endPoint = _map[end.y][end.x]; var __getEnd:Boolean = false; //判断是否到了结束点 initBlock(); //寻路前的初始化 var __thisNode:Object = _starPoint; //得到开始点 //循环判断是否到了结束点,直到以最优路径方式找到结束点为止 while (!__getEnd) { __thisNode.block = true; //把起始点设为障碍 var __checkList:Array = []; //检查数组 //把当前的周围的四个节点加入检查数组中,等待检查 if (__thisNode.y>0) { __checkList.push(_map[(__thisNode.y-1)][__thisNode.x]); } if (__thisNode.x>0) { __checkList.push(_map[__thisNode.y][(__thisNode.x-1)]); } if (__thisNode.x<_w-1) { __checkList.push(_map[__thisNode.y][(__thisNode.x+1)]); } if (__thisNode.y<_h-1) { __checkList.push(_map[(__thisNode.y+1)][__thisNode.x]); } //开始检测当前节点周围 var __len:int = __checkList.length; for (var i:int = 0; i<__len; i++) { //取得周围的每一个节点 var __neighboringNode:Object = __checkList[i]; //判断是否是目的地 if (__neighboringNode == _endPoint) { __neighboringNode.nodeparent = __thisNode; //设定此周围节点的父节点,即连接此的节点的上一节点 __getEnd = true; break; } //是否可通行 if (__neighboringNode.value == 0) { count(__neighboringNode, __thisNode);//计算该节点,传送周围节点和当前中间点过去 } } if (!__getEnd) { //如果未找到目的地 if (_open.length>0) { //开发列表不为空,找出F值最小的做为下一个循环的当前节点 __thisNode = _open.splice(getMin(),1)[0]; } else { //开发列表为空,寻路失败 return []; } } } drawPath(); return path; } //优化路径 public function optimizePath():Array { var __len:int = path.length; var __path:Array = []; var diagonal:Array = []; //斜线数组 var __dLen:int; var __cross:Boolean = true; var __currentNode:Point = path[0]; //起点 __path.push(path[0]); //加入到优化后的数组 for (var i:int=1; i<__len; i++) { diagonal = Diagonal.each(__currentNode, path[i]); __dLen = diagonal.length; //返回一个数组 __cross = true; for (var j:int=0; j<__dLen; j++) { if (_map[diagonal[j].y][diagonal[j].x].value == 1) { __cross = false; break; } } if (!__cross) { if (i>1) { __currentNode = path[(i-1)]; __path.push(path[(i-1)]); } } } __path.push(path[(__len-1)]); return __path; } //寻路前的初始化,设置每个节点的节点属性 private function initBlock():void { for (var y:int=0; y<_h; y++) { for (var x:int=0; x<_w; x++) { _map[y][x].open = false; //可以通过 _map[y][x].block = false; //障碍 _map[y][x].value_g = 0; _map[y][x].value_h = 0; _map[y][x].value_f = 0; _map[y][x].nodeparent = null; //寻路过程中的上一点 } } _open = []; } //计算每个节点,接收周围节点和周围节点的中间点 private function count(neighboringNode:Object, centerNode:Object):void { //是否在关闭列表里 if (!neighboringNode.block) { //不在关闭列表里才开始判断 var __g:Number= centerNode.value_g+10; //判断此点是否是障碍 if (neighboringNode.open) { //如果该节点已经在开放列表里 if (neighboringNode.value_g>=__g) { //如果新G值小于或者等于旧值,则表明该路更优,更新其值 neighboringNode.value_g = __g; ghf(neighboringNode); //计算GHF的值 neighboringNode.nodeparent = centerNode; //把周围节点的上一节点设为中心节点 } } else { //如果该节点未在开放列表里 //添加至列表 addToOpen(neighboringNode); //计算GHF值 neighboringNode.value_g = __g; ghf(neighboringNode); neighboringNode.nodeparent = centerNode; } } } //画路径 private function drawPath():void { var __pathNode:Object = _endPoint; //倒过来得到路径 while (__pathNode != _starPoint) { path.unshift(new Point(__pathNode.x, __pathNode.y)); __pathNode = __pathNode.nodeparent; } path.unshift(new Point(__pathNode.x, __pathNode.y)); } //加入开放列表 private function addToOpen(newNode:Object):void { _open.push(newNode); newNode.open = true; } //计算周围节点的ghf各值 private function ghf(node:Object):void { var __dx:Number = Math.abs(node.x-_endPoint.x); var __dy:Number = Math.abs(node.y-_endPoint.y); node.value_h = 10*(__dx+__dy); //计算周围节点到结束点的X,Y的相差距离(X相差距离+Y相差距离) node.value_f = node.value_g+node.value_h; //计算最优路径+XY的相差距离 (总距离) } //得到开放列表里拥有最小F值的节点在列表里的位置 private function getMin():int { var __len:int = _open.length; var __f:Number = 100000; var __i:int = 0; for (var i:int = 0; i<__len; i++) { if (__f>_open[i].value_f) { __f = _open[i].value_f; __i = i; } } return __i; } } }