FLEXAS3做FlashGame地图寻路实例.docx
- 文档编号:29868322
- 上传时间:2023-08-03
- 格式:DOCX
- 页数:19
- 大小:21.79KB
FLEXAS3做FlashGame地图寻路实例.docx
《FLEXAS3做FlashGame地图寻路实例.docx》由会员分享,可在线阅读,更多相关《FLEXAS3做FlashGame地图寻路实例.docx(19页珍藏版)》请在冰豆网上搜索。
FLEXAS3做FlashGame地图寻路实例
FLEXAS3做FlashGame地图寻路实例
1.总结目的
在地图中,通过鼠标或者由程序自动运行,让一个人物自动从地图的一点走到另一点。
需要计算两点之间的最优路线,要实现这样的寻路算法。
最常规和最简单的方法,使用A*算法。
本篇总结不具体讲解A*算法的实现以及原理,主要告诉怎么用。
后面的总结中我会陆续把A*算法进行详细分析,希望大家学习。
2.开发流程
2.1.地图加载
1)在寻路过程中,地图是被分为若干个小格子,当然,根据格子数量的不同,路线长度的不同,计算寻路的时间也就不同。
上面是有一个由20*20的地图拼起来的地图,每一个地图块是有20像素*20像素元件做成。
每一个地图块是2帧构成,地图帧是人物可以行走的路线,第二帧是障碍物(桌子)。
上面的地图是路线和障碍物8比2的概率生成,参考代码:
Block是地图块元件类。
用Flashcs3已经做好。
this.mass_x_count是指地图X轴上板块数量
this.mass_y_count是指地图Y轴上板块数量
distancex是指地图X轴离边界Left的距离
distancey是指地图Y轴离边界Top的距离
aNodeMap是一个2维数组,记录着每一个地图块当前的状态,是障碍物还是路线。
地图初始化中,根据两个For循环嵌套,生成一个表格状的地图。
这里我不在详细介绍,详细会AS3的一定可以看的懂。
2.2.地图上移动人物加载
1)路线寻路肯定要有一个元件在地图上移动,才可以正确的显示出寻路的过程。
无论是一个人物移动或多个人物移动,基本做法相同,下面我们就来加载一个人物物件到地图上来。
Waiter是一个移动的任务元件。
在这里我们叫“服务员元件”
Timer是为服务员增加一个timer事件,主要目的是为了服务员从一个地图块移动到另一个地图块,不是跳过去的,而是慢慢的移动过去的。
此方法主要在加载完地图后调用,指定人物加载的X,Y坐标,进行加载。
2.3.选择移动目的地
1)地图和服务员加载完成后,我们需要选择服务员移动的目的地,选择的方式有很多。
举个例子,人人餐厅中客人进来就餐,首先进门后,程序会自动寻找有空位的X,Y坐标,然后计算路线,客人就会沿着路线走进去。
同样服务员也会根据客人进来餐厅的循序,以及客人所做的座椅的坐标进行计算路线,然后走过去服务。
2)由于我们只是一个例子,所以就有我们鼠标确定目的地。
this.addEventListener(MouseEvent.CLICK,clickWay);
这个事件通过,用户鼠标点击地图上路线进行调用。
2.4.路线寻找,人物移动
1)在地图增加完后我们增加一个A*算法实例
AStar是A*算法的一个封装类。
我们需要把我们地图上路线和障碍物二维数组传递给算法。
这个是在地图加载后完成
2)确定移动目的地后计算路线
上面代码是在选择目的地后补充的代码
设置A*(asrar)算法的其实点和目的地。
起始点和目的地封装成ANode对象给算法的。
ANode是一个算法计算中节点的保存,记录着节点的位置X,Y,节点ID,以及使用曼哈顿方法计算F=G+HF、G、H值的保存。
从而做为路线计算中开启列表进行存储。
最后会调用DoSearch判断路线的获取是否成功。
获取的路线调用astar.aPath方法进行获取。
启动timer进行服务员移动操作。
3)服务员移动
在移动服务之前,我们确定,我们寻找到路线,此服务员的上一个路线已经完成。
代码如下:
这个方法是在寻找到路线后,timer启动执行的。
bMove表示是否移动服务员。
player代表当前移动中的服务员对象,他是在创建服务员的时候保存在全局变量中。
A*算法会在下面参考代码中会有
3.参考代码
A*寻路算法代码:
importflash.geom.Point;
/*
*A*寻路算法
*@authorliujia
*@version1.0
*/
publicclassAStar{
//垂直或水平移动一格的代价
privateconstCOST_STRAIGHT:
int=10;
//斜向移动一格的代价
privateconstCOST_DIAGONAL:
int=14;
//起始节点ANode
publicvarndStart:
ANode;
//目标节点ANode
publicvarndEnd:
ANode;
//当前节点ANode
publicvarndCurrent:
ANode;
//最大寻路步数限制
privatevarnMaxTry:
int;
//尝试次数计数器
privatevarnCrtTry:
int;
//开放表,元素为ANode类型
privatevaraOpenList:
Array;
//关闭表,元素为ANode类型
privatevaraCloseList:
Array;
//八个方向数组,从节点正上方开始,顺时针排列
privateconstaDir:
Array=[[0,-1],[1,-1],[1,0],[1,1],[0,1],[-1,1],[-1,0],[-1,-1]];
//地图节点数组
publicvaraNodeMap:
Array=[];
//地图大小
publicvarmapwidth:
int;
publicvarmapheight:
int;
//记录节点在aOpenList数组的位置
privatevarnum:
int;
//路径数组
publicvaraPath:
Array;
//是否找到路径
publicvarbPathFind:
Boolean;
//构造函数
publicfunctionAStar(amap:
Array){
nMaxTry=600;
nCrtTry=0;
Init();
mapwidth=amap[0].length;
mapheight=amap.length;
aNodeMap=amap;
}
//初始化
publicfunctionInit():
void{
bPathFind=false;
aOpenList=[];
aCloseList=[];
aPath=[];
}
//添加到open表
publicfunctionaddFirstOpen():
void{
aOpenList.push(ndStart);
}
//取得指定点周围可通过的点,从正上方开始
privatefunctionGetRound(apos:
Array):
Array{
vararr:
Array=newArray();
for(vari:
int=0;i varxp=apos[0]+aDir[i][0]; varyp=apos[1]+aDir[i][1]; if(IsOutRange([xp,yp])||IsStart([xp,yp])||! IsPass([xp,yp])||IsCorner([xp,yp])||IsInClose([xp,yp])) continue arr.push([xp,yp]); } returnarr; } //是否超出地图范围 privatefunctionIsOutRange(apos: Array): Boolean{ if(apos[0]<0||apos[0]>=mapwidth||apos[1]<0||apos[1]>=mapheight) returntrue; returnfalse; } //是否是起点 privatefunctionIsStart(apos: Array): Boolean{ if(apos[0]==ndStart.pos[0]&&apos[1]==ndStart.pos[1]) returntrue; returnfalse; } //是否可以通过 privatefunctionIsPass(apos: Array): Boolean{ if(IsOutRange(apos)){ returnfalse; }else{ return(aNodeMap[apos[1]][apos[0]]>0? false: true); } } //是否是拐角 privatefunctionIsCorner(apos: Array): Boolean{ if(IsPass(apos)){ if(apos[0]>ndCurrent.pos[0]){ if(apos[1]>ndCurrent.pos[1]){ if(! IsPass([apos[0]-1,apos[1]])||! IsPass([apos[0],apos[1]-1])) returntrue; } elseif(apos[1] if(! IsPass([apos[0]-1,apos[1]])||! IsPass([apos[0],apos[1]+1])) returntrue; } } elseif(apos[0] if(apos[1]>ndCurrent.pos[1]){ if(! IsPass([apos[0]+1,apos[1]])||! IsPass([apos[0],apos[1]-1])) returntrue; } elseif(apos[1] if(! IsPass([apos[0]+1,apos[1]])||! IsPass([apos[0],apos[1]+1])) returntrue; } } } returnfalse; } //是否在开启列表中 //获得传入参数在aOpenlist数组的位置,如不存在返回false,存在为true,位置索引保存到变量num中。 privatefunctionIsInOpen(apos: Array): Boolean{ varbool: Boolean=false; varid=apos[1]*mapwidth+apos[0]; for(vari=0;i if(aOpenList[i].id==id){ bool=true; num=i; break; } } returnbool; } //是否在关闭列表中 privatefunctionIsInClose(apos: Array): Boolean{ varbool: Boolean=false; varid=apos[1]*mapwidth+apos[0]; for(vari=0;i if(aCloseList[i].id==id){ bool=true; break; } } returnbool; } //取得F值,参数为某一节点周围的节点 privatefunctionGetF(around: Array): void{ //F,综合的距离值; //H,给定节点到目标点的距离值; //G,起点到给定节点的距离值 varF: int,H: int,G: int; varapos: Array; for(vari: int=0;i apos=around[i]; //是否与起点在同一直线上 if(apos[0]==ndStart.pos[0]||apos[1]==ndStart.pos[1]){ G=ndCurrent.G+COST_STRAIGHT; }else{ G=ndCurrent.G+COST_DIAGONAL; } //如果当前点已存在aOpenlist数组中 if(IsInOpen(apos)){ varopos: ANode=aOpenList[num]asANode; //如果当前点G值更小,更改父节点 if(G opos.F=G+opos.H; opos.G=G; opos.pid=ndCurrent.id; }else{ G=opos.G; } } //否则将当前点添加到aOpenList数组 else{ H=(Math.abs(ndEnd.pos[0]-apos[0])+Math.abs(ndEnd.pos[1]-apos[1]))*COST_STRAIGHT; F=G+H; varnewnode: ANode=newANode(apos,apos[1]*mapwidth+apos[0],0,ndCurrent.id); newnode.F=F; newnode.G=G; newnode.H=H; aOpenList.push(newnode); } } } //搜索路径 publicfunctionDoSearch(): Boolean{ aOpenList=[]; aCloseList=[]; addFirstOpen(); while(aOpenList.length){ nCrtTry++; //如果超出寻路步数限制 if(nCrtTry>nMaxTry){ destroyData(); returnfalse; } GetF(GetRound(ndCurrent.pos)); //按照F值由大到小的顺序排列开启列表 aOpenList.sortOn("F",Array.NUMERIC|Array.DESCENDING); //将开启列表最后一位元素列入关闭列表 varlastNode: ANode=aOpenList[aOpenList.length-1]; aCloseList.push(lastNode); ndCurrent=lastNode; if(aOpenList.length>1) aOpenList.pop(); //如果当前节点是目标节点,路径找到,返回true if(ndCurrent.id==ndEnd.id){ aPath=GetPath(); destroyData(); bPathFind=true; ndStart=ndCurrent; returntrue; } } bPathFind=false; destroyData(); aPath=[]; returnfalse; } //清空各数组 privatefunctiondestroyData(): void{ aOpenList=[]; aCloseList=[]; nCrtTry=0; } //取得路径数组 privatefunctionGetPath(): Array{ varapath: Array=[]; vartmpnode: ANode=aCloseList[aCloseList.length-1]asANode; apath.push(tmpnode.pos); varinc: int=0; while(inc<=aCloseList.length){ inc++ for(vari: int=0;i if(aCloseList[i].id==tmpnode.pid){ tmpnode=aCloseList[i]; apath.push(tmpnode.pos) } if(tmpnode.id==ndStart.id) break; } } returnapath; } } ANode节点对象: publicclassANodeextendsObject{ publicvarpid: int; publicvarid: int; publicvarpos: Array; publicvarG: int; publicvarH: int; publicvarF: int; publicvarblock: int;//1isblock,0ispass publicfunctionANode(_pos: Array,_id: int,_block: int=0,_pid: int=0){ id=_id; pid=_pid; pos=_pos; block=_block; G=0; H=0; F=0; } } 寻路实例主类: importflash.events.Event; importflash.events.MouseEvent; importflash.events.TimerEvent; importflash.utils.Timer; importmx.containers.Canvas; importmx.controls.Alert; publicclassSceneMainextendsCanvas { //地板离地图的边距 privatevardistancex: int=30; privatevardistancey: int=30; //地板的默认宽度和高度 privatevarfloorw: int=20; privatevarfloorh: int=20; //地板块数量 privatevarmass_x_count: int; privatevarmass_y_count: int; //服务员行走速度 privatevarinterval: int=50; //A*算法实例 privatevarastar: AStar; //移动属性 privatevarbMove: Boolean; //路径数组 privatevaraPath: Array; //路径数组指针 privatevarpathpoint: int; //地图数组 privatevaraNodeMap: Array; //服务员对象 privatevarplayer: Waiter=null; //服务员沿路线行走timer privatevartimer: Timer=newTimer(interval); publicfunctionSceneMain(x: int,y: int) { aNodeMap=newArray(); this.mass_x_count=x; this.mass_y_count=y; //初始化地图 this.initScene(); //初始化移动服务员 this.loadMoveRen(distancey,distancex); this.addEventListener(MouseEvent.CLICK,clickWay); } /** *初始化地图 */ publicfunctioninitScene(): void{ varblock: Block=newBlock(); this.width=block.width*this.mass_x_count+distancey; this.height=block.height*this.mass_y_count+distancex; for(vari: int=0;i aNodeMap[i]=newArray(); for(varj: int=0;j varblock1: Block=newBlock(); if(i==0&&j==0){ block1.gotoAndStop (1); }else{ vargailu: Number=Math.floor(Math.random()*10)+1; block1.gotoAndStop(gailu>8? 2: 1); } block1.x=j*bl
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- FLEXAS3 FlashGame 地图 实例