前阵子突然发现原来网上好象比较少介绍fllash游戏的跟踪法的,而且尽管有也一如A*法那样比较让人难明...
于是自己就决定写一个flash的跟踪法经过一个星期的时间也也把他写了出来了....并
给它起了个不怎么好听的名字:"四角点阵法寻路法".
现在把整个原理跟流程给大家共享下.
/*
原理及流程讲解:
程序组成: 一.点阵坐标处理函数部分 和 二.跟踪回放函数部分;
---<--------<<---------<--
| |
流程介绍: 主要流程1.先通过点阵坐标处理函数确定坐标点阵;---> 2.再把点阵数据传递到跟踪回放函数进行播放
原理: 说到寻路,他最原始的基础也就是跟踪移动;而且很多实际问题上我们还得必须考虑到阻碍的情况.这些废话我就不多说了~~
言归正传现在说说我是怎么处理一般情况跟阻碍情况的吧;
首先是对于一般情况,也就是移动物从点移动到另一点的基础情况
我的做法是:
每次先在移动物的与目的地所连成的那直线路径上打上一定数目的点并将坐标值赋值给相应的实,例。(而为什么我要用这种方法呢?呵呵~~~那当然是有根据的~~大家都知道flash里有个hitTest()函数但这个函数有一个很致命的缺点就是它只能根据检测对象的外框进行判断。这样当检测对象是一条斜线时得出的结果就很不如人意了,而我之所以选用小点实例连成一条直线的理由就如:一条比较长的斜线元件跟一条比较短的斜线元件比较检测时小的斜线元件得出的结果要比较小,同理如果更短的一条斜线呢?那样得出的结果将会更小。。。根据这样的根据微观分原理我用小点组成直线的理由就不言而寓了)
就如:A……………………B
然后通过跟踪回放函数将A一个点一个点的移动到B点;
但当有阻碍时又是怎么怎么个判断法呢?相信这也是最难的部分了下面继续简单说说我的处理过程
大家都知道flash里每个实例元件都有4个顶角(这4个顶角其实就是一个元件的外区域,也就是说这四个顶角是划分元件内外的一个简单区别在我的寻路法里饶开阻碍就主要根据这四个顶角进行的)而这4个顶角的坐标值这个我门可以通过getBounds()
函易得到。数的方法就很容当我们经过阻碍时要就是利用这4个点将实时的改变检测到与阻碍碰撞的原点实例坐标把那些与阻碍碰撞小点实例的坐标划分到那些顶角上从而绕过阻碍物重新确定坐标位置然后将整理后的坐标传递给跟踪回放函数一个点一个点的移动到目的地
具体的过程看看我下面的脚本分析~~~(这里说下题外话我下边的脚本是我的一个预缆版的内容用的方法也是比较简单易名的编程方法,至于可能你看后会说路径不是最短。。。之类的bug; 其实这些我都在脚本解释时提到了解决的方法的了;还有就是实际中的阻碍问题是很复杂的我提供的只是一个简单的方法而已;当我们做地图或别的游戏时就要根据需要自己想或者一起讨论了;在这我也可以给做游戏的朋友们一个建议,面对一些比较大型点的游戏我建议采取小地图跟大地图分开的方法决绝问题我在想预缆版时考虑的主要是大地图的~~至于小地图我们也可以采取我的方法中主要用到的预打点标记的方法做这里就不多说了`~欢迎大家一起讨论。。。)
这里再发下我在做这个寻路法时分步做的一些例子供大家参考扩展下吧~~
美工不怎么好大家见谅~~~~
*/
//第一帧部分:点阵坐标处理
fr=random(4);
stop();
m=["m1","m2","m3","m4","m5"];//场景阻碍总个数
m_=m.length;
qp=new Array();
ga=new Array();
gb=new Array();
gga=new Array();
ggb=new Array();
gga2=new Array();
ggb2=new Array();
zz=new Array();
vv=new Array();
qq2=new Array();
bb2=new Array();
ff1=new Array();
ffff=new Array();
zzz1=new Array();
zzz2=new Array();
zzz3=new Array();
zzz4=new Array();
zzzx1=new Array();
zzzx2=new Array();
zzzx3=new Array();
zzzx4=new Array();
ddd=new Array();
dddd=new Array();
/*此段提要:1.确定每阻碍的四顶角坐标并记录进数组;2.为每个阻碍的四顶角坐标放一个顶点实例方便下面操作;
这段也可以在检测到阻碍时才写,那样计算速度会更快~~效率更高,方便讲解就不多说了~~
*/
for(iii=0;iii<m_;iii++){mmm=["m"+(iii+1)];
cc=_root[mmm].getBounds(_root);
zs1=Array(cc.xMin,cc.yMin);
ys1=Array(cc.xMax,cc.yMin);
zx1=Array(cc.xMin,cc.yMax);
yx1=Array(cc.xMax,cc.yMax);
zzz1.push(zs1);
zzz2.push(ys1);
zzz3.push(zx1);
zzz4.push(yx1);
//筛选记录即时四顶角坐标;
zzzx1=zzz1.slice(-1);
zzzx2=zzz2.slice(-1);
zzzx3=zzz3.slice(-1);
zzzx4=zzz4.slice(-1);
//为每个场景实例添加四顶角实例
var jj0=5;
attachMovie("dian2",rr1=(mmm+"d"+(jj0-4)),500+iii);
_root[rr1]._x=zzzx1[0][0];
_root[rr1]._y=zzzx1[0][1];//将数据记录数组下面同理
attachMovie("dian2",rr2=(mmm+"d"+(jj0-3)),1000+iii);
_root[rr2]._x=zzzx2[0][0];
_root[rr2]._y=zzzx2[0][1];
attachMovie("dian2",rr3=(mmm+"d"+(jj0-2)),1500+iii);
_root[rr3]._x=zzzx3[0][0];
_root[rr3]._y=zzzx3[0][1];
attachMovie("dian2",rr4=(mmm+"d"+(jj0-1)),2000+iii);
_root[rr4]._x=zzzx4[0][0];
_root[rr4]._y=zzzx4[0][1];
}
/*
此段提要: 检测核心部分.主要用于调整及优化移动路径中的点阵坐标;
原理是先以移动物与目的地的直线为初始化路径进行打点,然后根据需要调整点的坐标从而更新移动路径坐标集合;
再传给移动跟踪函数
*/
//注册鼠标侦听对象
var mouseListener:Object = new Object();
mouseListener.onMouseDown = function() {
var oo=0; op=0
//初始化移动物对象~~
mc2._x=_xmouse;mc2._y=_ymouse;
mc3._x=_xmouse;mc3._y=_ymouse;
//点阵坐标记录开关集合初始化
qq=new Array(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,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,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,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0);
//阻碍记录开关集合,本预缆版预留扩展用
bb=new Array(0,0,0);
//打点
for(i=0;i<50;i++){
import flash.geom.Point;
var point_1:Point = new Point(mc2._x, mc2._y);
var point_2:Point = new Point(mc1._x, mc1._y);
var it:Point = Point.interpolate(point_1, point_2, i*0.02);
attachMovie("dian",qp=("p"+i),55555+i);
_root[qp]._x=it.x;_root[qp]._y=it.y;
xx=Array(_root[qp]._x,_root[qp]._x)
zz.push(xx);
}
vv=zz.slice(1);
for(i1=0;i1<50;i1++){qp=["p"+i1];;
//检测碰撞,初步调整点阵坐标; 为方便大家看 用了穷举法;也可以写成函数再调用
if(_root[qp].hitTest(_root.m1)){bb[0]=1;qq[i1]=1;//点阵开关记录,下同理
if((_root[qp]._x<m1._x)&&(_root[qp]._y<m1._y)){_root[qp]._x=m1d1._x-5;_root[qp]._y=m1d1._y-5}
if((_root[qp]._x>=m1._x)&&(_root[qp]._y<=m1._y)){_root[qp]._x=m1d2._x+5;_root[qp]._y=m1d2._y-5}
if((_root[qp]._x>m1._x)&&(_root[qp]._y>m1._y)){_root[qp]._x=m1d4._x+5;_root[qp]._y=m1d4._y+5}
if((_root[qp]._x<=m1._x)&&(_root[qp]._y>=m1._y)){_root[qp]._x=m1d3._x-5;_root[qp]._y=m1d3._y+5}
}
if(_root[qp].hitTest(_root.m2)){bb[1]=1;qq[i1]=2;
if((_root[qp]._x<m2._x)&&(_root[qp]._y<m2._y)){_root[qp]._x=m2d1._x-5;_root[qp]._y=m2d1._y-5}
if((_root[qp]._x>=m2._x)&&(_root[qp]._y<m2._y)){_root[qp]._x=m2d2._x+5;_root[qp]._y=m2d2._y-5}
if((_root[qp]._x>m2._x)&&(_root[qp]._y>m2._y)){_root[qp]._x=m2d4._x+5;_root[qp]._y=m2d4._y+5}
if((_root[qp]._x<=m2._x)&&(_root[qp]._y>=m2._y)){_root[qp]._x=m2d3._x-5;_root[qp]._y=m2d3._y+5}
}
if(_root[qp].hitTest(_root.m3)){bb[2]=1;qq[i1]=3;
if((_root[qp]._x<m3._x)&&(_root[qp]._y<m3._y)){_root[qp]._x=m3d1._x-5;_root[qp]._y=m3d1._y-5}
if((_root[qp]._x>=m3._x)&&(_root[qp]._y<=m3._y)){_root[qp]._x=m3d2._x+5;_root[qp]._y=m3d2._y-5}
if((_root[qp]._x>m3._x)&&(_root[qp]._y>m3._y)){_root[qp]._x=m3d4._x+5;_root[qp]._y=m3d4._y+5}
if((_root[qp]._x<=m3._x)&&(_root[qp]._y>=m3._y)){_root[qp]._x=m3d3._x-5;_root[qp]._y=m3d3._y+5}
}
if(_root[qp].hitTest(_root.m4)){bb[2]=1;qq[i1]=4;
if((_root[qp]._x<m4._x)&&(_root[qp]._y<m4._y)){_root[qp]._x=m4d1._x-5;_root[qp]._y=m4d1._y-5}
if((_root[qp]._x>=m4._x)&&(_root[qp]._y<=m4._y)){_root[qp]._x=m4d2._x+5;_root[qp]._y=m4d2._y-5}
if((_root[qp]._x>m4._x)&&(_root[qp]._y>m4._y)){_root[qp]._x=m4d4._x+5;_root[qp]._y=m4d4._y+5}
if((_root[qp]._x<=m4._x)&&(_root[qp]._y>=m4._y)){_root[qp]._x=m4d3._x-5;_root[qp]._y=m4d3._y+5}
}
if(_root[qp].hitTest(_root.m5)){bb[2]=1;qq[i1]=5;
if((_root[qp]._x<m5._x)&&(_root[qp]._y<m5._y)){_root[qp]._x=m5d1._x-5;_root[qp]._y=m5d1._y-5}
if((_root[qp]._x>=m5._x)&&(_root[qp]._y<=m5._y)){_root[qp]._x=m5d2._x+5;_root[qp]._y=m5d2._y-5}
if((_root[qp]._x>m5._x)&&(_root[qp]._y>m5._y)){_root[qp]._x=m5d4._x+5;_root[qp]._y=m5d4._y+5}
if((_root[qp]._x<=m5._x)&&(_root[qp]._y>=m5._y)){_root[qp]._x=m5d3._x-5;_root[qp]._y=m5d3._y+5}
}
}//for
var di=0;di2=0;
/*此处用于细化最断路径~~原理主要用查找最断路径;(本预缆版只对开始于结束的分段进行调整;
要确定最短路径可继续地其他分段进行调整)*/
//检测点阵记录开关状况并调整
for(ok=0;ok<50;ok++){
if((qq[ok]==0)&&(qq[ok+1]!=0)){gga.push(ok+1);di++;};
if((qq[50-ok]==0)&&(qq[50-(ok+1)]!=0)){ggb.push(50-(ok+1));di2++}
}
gga2=gga.slice(-di);
ggb2=ggb.slice(-di2);
ga=gga2.slice(0,1);
gb=ggb2.slice(0,1);
av=ga[0];
bv=gb[0];
for(ty=0;ty<av;ty++){qp=["p"+ty];
_root[qp]._x=_root.p1._x;
_root[qp]._y=_root.p1._y
}
for(ty2=50;ty2>bv;ty2--){
qp=["p"+ty2];
_root[qp]._x=_root.mc2._x;
_root[qp]._y=_root.mc2._y
}
//跳转跟踪函数
gotoAndStop(2);
}
Mouse.addListener(mouseListener);
/*第二帧内容
//////////////////////////跟踪回放函数部分/////////////////////////// */
stop();
txt=["终于找到了 好累人哦..^0^","喜喜..跑得够我快不?O_O","来,来,来,我的笨小孩...","可惜这里没苹果..!_!","没吃饭么?呵呵~~没我快也..U_U"]
mc3.trt.text="";
//调用跟踪回放函数
huifang()
var j=1;uu=0;i2=0;
/* 本节提要:跟踪函数主要组成部分
基本组成:1.转向跟踪函数部分(主要);2.回放函数部分
*/
///////////////////////////....回放函数部分......./////////////////////////////
//此部分主要通过实时反复改变跟踪函数部分的移动物及目标坐标实现回放功能;;也可以写成递归函数形式//
function huifang(){
pop=["p"+ir];
//当没碰到阻碍时初始化传调整后的点阵坐标数据
for(ir=0;ir<50;ir++){if(pox[ir]==undefined)
{pop._x=mc2._x;pop._y=mc2._y}
}
k();
function k(){ onEnterFrame=function(){; direction(mc1,mc2);de._x=mc1._x;de._y=mc1._y;
};}
for(i=0;i<pox.length+1;i++){p=["p"+i];
_root[p]._x=pox[i];_root[p]._y=poy[i]; _root[p].txt.text=i;
}}
var speed=2;
///////////////////////////....转向跟踪函数部分......./////////////////////////////
function direction(mc1,mc2) {
; p=["p"+j];po=["p"+(uu)]
//每次两个点阵坐标为函数所用
mc2._x=_root[p]._x;mc2._y=_root[p]._y
mu=_root[po];
//两点距离函数
var degree, dx, dy, center_x, center_y;
center_x = mc1._x;
center_y = mc1._y;
mx = _root.mc2._x;
my = _root.mc2._y;
dx = mx-center_x;
dy = center_y-my;
if (dy == 0) {
if (dx>0) {
degree = 90;
} else {
degree = 270;
}
} else {
if (dy>0) {
degree = Math.atan(dx/dy)*180/Math.PI;//利用3角函数关系,分别根据角的所在象限;实时调整移动物方向,下同
} else {
degree = Math.atan(dx/dy)*180/Math.PI+180;
}
}
mc1._rotation = degree;//将角度附值给移动物
if (Math.sqrt((dx*dx)+(dy*dy))>speed) {
//利用3角函数关系,使移动物实时移动;
mc1._y -= speed*Math.cos(degree*(Math.PI/180));
mc1._x += speed*Math.sin(degree*(Math.PI/180));
}
//结束完一次移动后将点阵坐标向下移动一位配合回放函数调用~~
if(Math.sqrt((dx*dx)+(dy*dy))<speed){;tt=true; pd[j-1]=1;;
if(tt){j+=1;uu+=1;if(j>=50)
{j=50;mc3.trt.text=txt[fr];gotoAndStop(1)}
}}}