<?xml version="1.0" encoding="utf-8"?> <Data ID="map03" minMapUrl="../assets/Image/Map/3/MiniMap/0.jpg" mapWidth="2000" mapHeight="1600" tileWidth="15" tileHeight="15" col="134" row="107" Value="0_0,1_0,2_0,3_0,4_0,5_0,6_0,7_0,8_0,9_0,10_0,11_0,12_0,13_0,14_0,15_0,16_0,17_0,87_0,88_0,89_0,90_0,91_0,101_0,102_0,103_0,104_0,105_0,106_0,107_0,108_0,109_0,110_0,111_0,112_0,113_0,114_0,115_0,116_0,117_0,118_0,119_0,120_0,121_0,122_0,123_0,124_0,125_0,126_0,127_0 />
minMapUrl:小地图url
mapWidth-mapHeight:地图宽高
tileWidth-tileHeight:网格宽高(因为不能将一个像素点作为障碍物—效率问题,这里将横竖除以15)
col-row:横竖网格数
Value:障碍物数组,0_0表示(0,0)网格为障碍物
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()" backgroundGradientAlphas="[1.0, 1.0]" backgroundGradientColors="[#191919, #595959]"> <mx:Script> <!--[CDATA[ import com.events.MoveToNextTile; import com.change.ChangeArray; import com.util.PointUtil; import com.search.Node; import com.search.Find; private var tileWidth:Number;//地图网格宽高 private var tileHeight:Number; private var mapWidth:Number;//地图长宽 private var mapHeight:Number; private var col:Number;//地图列数 private var row:Number;//地图行数 private var map:Array=[];//通过ChangeArray获得的地图障碍物数组 private var mapArray:Array=[];//可用于寻路类使用的地图障碍物数组 private var currentPath:Array=[];//路线数组 public var Speed:Number=4.0; //可通过此数据改变role的移动和动作速度 private var realSpeed:Number;//实际的速度,受Timer效率的影响 private var xSpeed:Number;//x,y方向的速度 private var ySpeed:Number; private var dir:int=7;//运动方向 private var radians:Number;//目前地点与目的点的角度 private var moveTimer:Timer; private var xSet:Number=50;//通过参数重新注册role的位置,例如将位置注册到人物脚下 private var ySet:Number=80; private var xRole:Number;//角色坐标 private var yRole:Number; private var mouseTargetX:Number; private var mouseTargetY:Number; private var lastTime:Date;//通过这两个参数获取realSpeed private var thisTime:Date; private var second:Number;//一次timer循环所需时间,为speed的参数 private var distance:Number;//当前role到下一个tile的距离 private var isMoving:Boolean=false; private var isStyleMoving:Boolean=false; private var nextCell:Boolean=false;//下一个网格是否是障碍物 private var totalDistance:Number; private var totalRadians:Number; private var lastxRole:Number; private var lastyRole:Number; private var lastmouseTargetX:Number; private var lastmouseTargetY:Number; /* * 使用碰撞预测法 */ //载入xml配置文件 private function init():void{ var xmlLoader:URLLoader=new URLLoader(); xmlLoader.load(new URLRequest("../assets/Data/test12.xml")); xmlLoader.addEventListener(Event.COMPLETE,xmlInfo); this.roleContainer.addEventListener(MouseEvent.MOUSE_DOWN,onDown); //开启时钟 moveTimer=new Timer(40); moveTimer.addEventListener(TimerEvent.TIMER,moveToNext); moveTimer.start(); lastTime=new Date(); } //初始化 private function xmlInfo(evt:Event):void{ var myXml:XML=new XML(evt.target.data); var zero:String=myXml.@Value; this.mapWidth=myXml.@mapWidth; this.mapHeight=myXml.@mapHeight; this.tileWidth=myXml.@tileWidth; this.tileHeight=myXml.@tileHeight; this.col=myXml.@col; this.row=myXml.@row; //初始化位置 this.myMap.x=1120-this.mapWidth; this.myMap.y=630-this.mapHeight; this.roleContainer.x=this.myMap.x; this.roleContainer.y=this.myMap.y; //初始化大小 this.myMap.width=this.mapWidth; this.myMap.height=this.mapHeight; this.roleContainer.width=this.mapWidth; this.roleContainer.height=this.mapHeight; //初始化role位置 this.role.x=this.mapWidth-400; this.role.y=this.mapHeight-300; //将原数组转化为0,1数组,0表示可通行,1表示为障碍物 map=ChangeArray.change(zero,this.col,this.row); getPathArr(); } //获取mapArray.mapArray元素为Array,mapArray[0]为Node private function getPathArr():void{ for(var i:int=0;i<this.col;i++){ mapArray[i]=new Array(this.row); for(var j:int=0;j<this.row;j++){ var nod:Node=new Node; nod.x=i; nod.y=j; nod.isClose=(map[i][j]==1?true:false); nod.isOpen=false; nod.point=PointUtil.getPxPoint(this.tileWidth,this.tileHeight,i,j); mapArray[i][j]=nod; if(mapArray[i][j].isClose){ drawBarrier(this.tileWidth*mapArray[i][j].x,this.tileWidth*mapArray[i][j].y); } } } trace(mapArray.length,mapArray[0].length); initFind(); } //初始化寻路 private function initFind():void{ Find.setBeArray(mapArray);//设置地图障碍物数组 Find.col=this.col; Find.row=this.row; Find.TITEWIDTH=this.tileWidth; Find.TITEHEIGHT=this.tileHeight; } //点击事件 private function onDown(evt:MouseEvent):void{ //重新注册role位置,以为role.x和role.y为图片左上角坐标 xRole=role.x+this.xSet; yRole=role.y+this.ySet; //获取鼠标点击目标坐标 this.mouseTargetX=evt.currentTarget.mouseX; this.mouseTargetY=evt.currentTarget.mouseY; this.isMoving=true; this.isStyleMoving=false; //侦听HittingEvent,碰撞预测法,判断role方向上一下网格是否为障碍物,是才开始寻路,否则一直只作直线行走 this.addEventListener("HittingEvent",ChooseWalk); this.nextCell=false; //行走前HitTest this.HitTest(xRole,yRole); if(!this.nextCell){ walkLine(); } //记录上次role位置和鼠标点击位置。如果与这次相同,则不寻路(为了防止玩家在障碍物前循环点击障碍物-肯定寻路为NULL,浪费资源) this.lastxRole=this.xRole; this.lastyRole=this.yRole; this.lastmouseTargetX=this.mouseTargetX; this.lastmouseTargetY=this.mouseTargetY; } //碰撞遇到障碍物,开始walkPath private function ChooseWalk(evt:Event):void{ this.isStyleMoving=true; walkPath(); this.removeEventListener("HittingEvent",ChooseWalk); } //直线行走 private function walkLine():void{ if(!this.isStyleMoving){ //x和y方向的距离 var totalX:Number=this.mouseTargetX-this.xRole; var totalY:Number=this.mouseTargetY-this.yRole; //有x和y方向的距离获得当前role与目标点之间的距离和角度 this.totalDistance=Math.sqrt(totalX*totalX+totalY*totalY); this.totalRadians=Math.atan2(totalY,totalX); //根据角度获得role方向,用于改变图片 this.dir=this.getdir(this.totalRadians); role.source="../assets/Image/Role/Body/100/"+this.dir+"-0.png"; } } //寻路行走 private function walkPath():void{ //加入判断,包括(如果鼠标点击目标为障碍物,则不寻路行走,只直线行走,如果role位置和鼠标点位置均没变,说明role正靠在障碍物边上,玩家一直在重复点击同一个地方,也不开启寻路) if(PointUtil.getCellPoint(this.tileWidth,this.tileHeight,this.lastxRole,this.lastyRole).x!=PointUtil.getCellPoint(this.tileWidth,this.tileHeight,this.xRole,this.yRole).x|| PointUtil.getCellPoint(this.tileWidth,this.tileHeight,this.lastxRole,this.lastyRole).y!=PointUtil.getCellPoint(this.tileWidth,this.tileHeight,this.xRole,this.yRole).y|| PointUtil.getCellPoint(this.tileWidth,this.tileHeight,this.lastmouseTargetX,this.lastmouseTargetY).x!=PointUtil.getCellPoint(this.tileWidth,this.tileHeight,this.mouseTargetX,this.mouseTargetY).x|| PointUtil.getCellPoint(this.tileWidth,this.tileHeight,this.lastmouseTargetX,this.lastmouseTargetY).y!=PointUtil.getCellPoint(this.tileWidth,this.tileHeight,this.mouseTargetX,this.mouseTargetY).y) { var find:Find=new Find(); this.currentPath=find.startFindPath(new Point(xRole,yRole),new Point(this.mouseTargetX,this.mouseTargetY)); trace(currentPath); } if(this.currentPath==null||this.currentPath.length<=0){ this.isMoving=false; return; } else{ //如果获得的路径数组不为空,则添加寻路事件侦听,并自己派发事件 drawPath(); this.addMoveEvent(); this.dispatchMoveEvent(); } } //开始寻路移动(寻路移动既是将role位置与目标点之间分为拼接起来不为直线的N段,在每一段内直线行走) private function startMove(evt:MoveToNextTile):void{ if(this.currentPath==null||this.currentPath.length<=0){ this.isMoving=false; return; } else{ //取出path数组第一个元素作为第一个目标点,path数组删除第一个元素 var nextTile:Point=this.currentPath.shift(); if(nextTile==null){ this.removeEventListener(MoveToNextTile.MOVE_TO_NEXT_TILE,startMove); return; } else{ var dx:Number=nextTile.x-xRole; var dy:Number=nextTile.y-yRole; this.distance=Math.sqrt(dx*dx+dy*dy);//计算距离 this.radians=Math.atan2(dy,dx);//计算角度 this.dir=this.getdir(this.radians);//通过角度获取方向 role.source="../assets/Image/Role/Body/100/"+this.dir+"-0.png"; } } } private function moveToNext(evt:TimerEvent):void{ //由于timer不够精准,尤其在不同的计算机上,因此每个timer循环中,role的移动距离跟timer循环一次的时间相关 this.thisTime=new Date(); this.second=this.thisTime.getTime()-this.lastTime.getTime(); this.lastTime=this.thisTime; //即realSpeed,它通过Speed与每一timer循环相关(这里,Speed其实不是速度,为每timer循环所移动的距离) if(this.isMoving){ this.realSpeed=this.Speed*this.second/50; if(this.isStyleMoving){ //当临时目标点到role的距离小于一个realSpeed时,说明,role一完成一个路径段的移动,将进入下一个路径段的移动 if(this.distance<this.realSpeed){ this.dispatchMoveEvent(); } else{ this.distance=this.distance-this.realSpeed; //通过角度获取x和y方向上的移动距离 this.xSpeed = this.realSpeed*Math.cos(radians); this.ySpeed = this.realSpeed*Math.sin(radians); moveToNextTile(); } } else{ //只有在直线移动时才开启碰撞测试 this.HitTest(this.xRole,this.yRole); if(this.totalDistance<this.realSpeed){ this.isMoving=false; } else{ this.totalDistance=this.totalDistance-this.realSpeed; this.xSpeed=this.realSpeed*Math.cos(this.totalRadians); this.ySpeed=this.realSpeed*Math.sin(this.totalRadians); moveToNextTile(); } } } } //由于要使role保持在屏幕中央,就必须是的myMap,roleContainer两个容器向相反方向移动,当role靠近4个角和4条边时,2个容器移动将发生变化 private function moveToNextTile():void{ var moveTarget:int=getMoveTarget(); trace(moveTarget); if(moveTarget==0) { this.xRole=this.xRole+this.xSpeed; this.yRole=this.yRole+this.ySpeed; role.x=this.xRole-this.xSet; role.y=this.yRole-this.ySet; //使用通过role计算myMap和roleContainer的位置可以避免误差引起的role偏离 //不再直接使用roleContainer-speed this.myMap.x=560-this.xRole; this.myMap.y=345-this.yRole;//345=屏幕高度/2+注册图片ySet-图片高度/2 this.roleContainer.x=560-this.xRole; this.roleContainer.y=345-this.yRole; } else if(moveTarget==1){ this.xRole=this.xRole+this.xSpeed; this.yRole=this.yRole+this.ySpeed; role.x=this.xRole-this.xSet; role.y=this.yRole-this.ySet; this.myMap.x=560-this.xRole; this.roleContainer.x=560-this.xRole; } else if(moveTarget==2){ this.xRole=this.xRole+this.xSpeed; this.yRole=this.yRole+this.ySpeed; role.x=this.xRole-this.xSet; role.y=this.yRole-this.ySet; this.myMap.y=345-this.yRole;//345=注册图片ySet-图片高度/2 this.roleContainer.y=345-this.yRole; } else if(moveTarget==3){ this.xRole=this.xRole+this.xSpeed; this.yRole=this.yRole+this.ySpeed; role.x=this.xRole-this.xSet; role.y=this.yRole-this.ySet; } } //通过role位置获取移动目标(只role移动,还是role和map均移动) private function getMoveTarget():int{ trace(this.xRole+"///"+this.yRole) if(this.xRole<=this.mapWidth-560&&this.xRole>=560&&this.yRole<=this.mapHeight-285&&this.yRole>=345) { return 0; } else if(this.xRole>this.mapWidth-560&&this.yRole<=this.mapHeight-285&&this.yRole>=345||this.xRole<560&&this.yRole<=this.mapHeight-285&&this.yRole>=345){ return 2; } else if(this.yRole>this.mapHeight-285&&this.xRole<=this.mapWidth-560&&this.xRole>=560||this.yRole<345&&this.xRole<=this.mapWidth-560&&this.xRole>=560){ return 1; } else { return 3; } } //碰撞预测法,role开始移动后,监测role移动方向上是否存在障碍物,存在才开始寻路 private function HitTest(xRole:Number,yRole:Number):void{ var pointNow:Point=PointUtil.getCellPoint(this.tileWidth,this.tileHeight,xRole,yRole); var pointNext:Point=this.getNextTile(); if(pointNow.x+pointNext.x<mapArray.length&&pointNow.x+pointNext.x>=0&&pointNow.y+pointNext.y>=0&&pointNow.y+pointNext.y<mapArray[0].length){ if(mapArray[pointNow.x+pointNext.x][pointNow.y+pointNext.y].isClose){ this.nextCell=true; //如果下一个为障碍物。则派发事件,启动寻路walk this.dispatchEvent(new Event("HittingEvent")); } } } private function getdir(radian:Number):int{ var direction:int=0; if(radian<-2.9||radian>3.0){ direction=6; } else if(radian>-2.9&&radian<-1.8){ direction=7; } else if(radian>-1.8&&radian<-1.4){ direction=0; } else if(radian>-1.4&&radian<-0.3){ direction=1; } else if(radian>-0.3&&radian<0.1){ direction=2; } else if(radian>0.1&&radian<1.2){ direction=3; } else if(radian>1.2&&radian<1.7){ direction=4; } else if(radian>1.7&&radian<3.0){ direction=5; } else{ direction=0; } return direction; } //获得下一个tile是否是障碍物 private function getNextTile():Point{ var disX:Number=this.xRole-this.mouseTargetX; var disY:Number=this.yRole-this.mouseTargetY; if(-this.tileWidth<disX<this.tileWidth&&disY<0){ return new Point(0,1); } else if(-this.tileWidth<disX<this.tileWidth&&disY>0){ return new Point(0,-1); } else if(-this.tileWidth<disY<this.tileWidth&&disX>0){ return new Point(-1,0); } else if(-this.tileWidth<disY<this.tileWidth&&disX>0){ return new Point(1,0); } else if(disX>this.tileWidth&&disY>this.tileWidth){ return new Point(-1,-1); } else if(disX>this.tileWidth&&disY<-this.tileWidth){ return new Point(-1,1); } else if(disX<-this.tileWidth&&disY>this.tileWidth){ return new Point(1,-1); } else{ return new Point(1,1); } } private function dispatchMoveEvent():void{ var e:MoveToNextTile=new MoveToNextTile(MoveToNextTile.MOVE_TO_NEXT_TILE); this.dispatchEvent(e); } private function addMoveEvent():void{ this.addEventListener(MoveToNextTile.MOVE_TO_NEXT_TILE,startMove); } //绘制路线 private function drawPath():void{ path.graphics.clear(); for(var i:int=0;i<this.currentPath.length;i++){ path.graphics.beginFill(0x0000ff); path.graphics.drawCircle(this.currentPath[i].x,this.currentPath[i].y,2); path.graphics.endFill(); } } //绘制障碍物 private function drawBarrier(_x:int,_y:int):void{ myMap.graphics.beginFill(0xff0000,0.8); myMap.graphics.drawRect(_x,_y,this.tileWidth,this.tileWidth); myMap.graphics.endFill(); } ]]--> </mx:Script> <mx:Canvas id="myCanvas" width="1120" height="630" verticalScrollPolicy="off" horizontalScrollPolicy="off" horizontalCenter="0" verticalCenter="0" backgroundColor="#42311B"> <mx:Canvas id="myMap" verticalScrollPolicy="off" horizontalScrollPolicy="off"> <mx:Image id="mapImg" source="../assets/Image/Map/3/0.jpg" alpha="0.8" x="0" y="0"/> <mx:Canvas id="path" width="100%" height="100%"/> </mx:Canvas> <mx:Canvas id="roleContainer" verticalScrollPolicy="off" horizontalScrollPolicy="off"> <mx:Image id="role" source="../assets/Image/Role/Body/100/7-0.png"/> </mx:Canvas> </mx:Canvas> </mx:Application>
package com.change { public class ChangeArray { //使用的是深蓝色右手的地图编辑器。数组只包含障碍物 //由于地图配置文件中数组只有障碍物,此类将障碍物转为地图数组,障碍物=1,空白=0; public function ChangeArray() { } public static function change(zero:String,col:int,row:int):Array{ var _col:int=col; var _row:int=row; var _zero:String=zero; var _zeroArr:Array=[]; var _firstArr:Array=[]; var _map:Array=[]; _zeroArr=_zero.split(","); //取得(0_0)数组 for(var i:int=0;i<_zeroArr.length;i++){ _firstArr.push(_zeroArr[i].split("_")); } //初始化_map数组 for(var j:int=0;j<_col;j++){ _map[j]=new Array(_row); for(var p:int=0;p<_row;p++){ _map[j][p]=0; } } //载入障碍物 for(var k:int=0;k<_firstArr.length;k++){ var xx:int=_firstArr[k][0]; var yy:int=_firstArr[k][1]; _map[xx][yy]=1; } return _map } } }
package com.util { import flash.geom.Point; public class PointUtil { /* 此类主要包括2个静态方法,一个将网格坐标转为像素坐标 一个将像素坐标转为网格坐标; */ public function PointUtil() { } //将像素转为网格坐标 public static function getCellPoint(tileWidth:Number,tileHeight:Number,px:Number,py:Number):Point{ var cx:Number=0; var cy:Number=0; cx=Math.floor(px/tileWidth); cy=Math.floor(py/tileHeight); return new Point(cx,cy); } //将网格转为像素坐标 public static function getPxPoint(tileWidth:Number,tileHeight:Number,cx:Number,cy:Number):Point{ var px:Number=0; var py:Number=0; px=tileWidth*cx+tileWidth*0.5; py=tileHeight*cy+tileHeight*0.5; return new Point(px,py); } } }
下载地址 http://download.csdn.net/source/2123708