登录
注册
搜索
帮助
主站
会员
界面
简洁版本
在线
灵动游戏论坛
游戏专区
【游戏开发者】
【分享02】AS3实现RPG游戏地图引擎
帖子标题
灵动官方
【活动公告】
【产品发布】
【新游快报】
近期热门
【葬魂之诗专区】
【勇者之路专区】
【天空之城OL】
游戏专区
【游戏开发者】
【游戏杂谈】
【游戏资源】
休闲娱乐
【七嘴八舌】
【影视贴图】
【原创天地】
经典游戏区
【奥库兹的冒险者】
【乖乖猪世界专区】
【金庸群侠传】
【灵动喷射2专区】
【灵动嘻哈外传区】
【云之秘境专区】
【圣猫传】
站务管理
【接待大厅】
1
/ 1 页
1
跳转
页
查看:
6208
标题: 【分享02】AS3实现RPG游戏地图引擎
SKDD
头衔:
江湖老手
UID:
13
精华贴:
1
威望值:
3
魅力点:
3
功勋值:
1
经验数:
31
积分点:
12
灵动币:
0
状态:
离线
帖子:
30
最后报道:
2010-03-06
2008-03-10 00:31
|
只看楼主
树型
|
收藏
|
小
中
大
1
【分享02】AS3实现RPG游戏地图引擎
目前已经完成精确到像素的任意不规则形状的碰撞检测算法。同时也考虑将地图信息转为二维数组以便
A*
自动寻径。这样在操作上用碰撞,
AI
上用
A*
,一定能给玩家带来完美的游戏体验。
这里的碰撞检测主要依靠封装好的类
PPCD
(
perfectPixelCollisionDetection
),它的接口如下:
类
PPCD
:
1.
返回发生碰撞的矩形边界:
getCollisionRect (
target1:DisplayObject,
target2:DisplayObject,
commonParent:DisplayObjectContainer,
pixelPrecise:Boolean = true,
tolerance:Number = 0
):Rectangle
2.
返回发生碰撞的矩形边界的中心点:
getCollisionPoint (
target1:DisplayObject,
target2:DisplayObject,
commonParent:DisplayObjectContainer,
pixelPrecise:Boolean = true,
tolerance:Number = 0
):Point
3.
验证两个对象是否碰撞:
isColliding (
target1:DisplayObject,
target2:DisplayObject,
commonParent:DisplayObjectContainer,
pixelPrecise:Boolean = true,
tolerance:Number = 0
):Boolean
参数说明:
target1
,
target2
:需要做碰撞检测的两个对象;
commonParent
:两个对象所在的
共同的
容器;
pixelPreciese
:是否精确到像素。若设置为
false
,则和
DisplayObject.hitTestObject()
工作原理相同。
tolerance
:容许量,默认为
0
。这个数值设置开始进行碰撞检测的
DisplayObject
的最小
alpha
值。比如有个对象有阴影效果,其阴影的
alpha
值大概在
20
以下。那么如果在进行碰撞检测的时候不希望把阴影也包含进去,则需要将
tolerance
设置为
20
。否则另外一个物体碰到阴影也算有碰撞。
工作原理说明:
1.
找出两个对象边界矩形的交叉区域,若没有则没有发生碰撞
2.
创建一个与交叉区域同样大小的
bitmap
3.
将第一个对象相交的部分以红色绘制在
bitmap
中
4.
将第二个对象的相交部分以白色绘制在
bitmap
中,
BlendMode
(混合模式)为
DIFFERENCE
。
5.
找出颜色为
cyan
的区域并返回其边界矩形。若没有则说明没有发生碰撞
此算法快速高效,一次检测只需要花
2-3ms
的时间。详细的算法参见源文件
PPCD.fla
,另有
2
个
SWF
演示:
1.
拖动小球,当小球碰到不规则物体时碰撞区域的边界矩形会以绿色标记出来,同时
bitmap
会在左上角显示。注意物体的阴影部分没有参与碰撞检测(合理设置
tolerance
参数)。
http://www.namipan.com/d/5e623263db64892c8542d6201b58544e3767b05207070000
http://www.fs2you.com/files/98e07085-49dc-11dd-b7b8-0014221f4662/
2.
纯演示动画,看就好。
^-^
http://www.namipan.com/d/6456a50a06e021ecb4c482a4b2fa5cbda4e56ea196070000
http://www.fs2you.com/files/98f32f1c-49dc-11dd-991f-0014221f4662/
有了这样一个强大的类,像素级的碰撞检测就不成问题了。不过因为
PPCD
类返回的是边界矩形,以及人物可以在不同的方向以不同的方式碰撞,再加上人物碰到障碍物之后需要有一定的自动“滑动”的功能,碰撞检测的逻辑还是挺复杂的,下面简要介绍一下。
碰撞检测逻辑
比较长和复杂,因为碰撞情况很多,准备好@_@哦? ^^b
详细算法在5楼和6楼,帖子超长了,呵呵。
SWF
效果预览:
曲线为主:
http://www.namipan.com/d/9862425238a395c6e755e060c930dd6a5c4fd2276e1b0000
http://www.fs2you.com/files/98fb1375-49dc-11dd-998c-0014221f4662/
直线为主:
http://www.namipan.com/d/4205132b47d0c5c55c423572824d6b458a61e8386d1b0000
http://www.fs2you.com/files/98fda719-49dc-11dd-9109-0014221f4662/
源文件:
http://www.namipan.com/d/f960d7b6403f186fb3887603d6560799d0efcb500c930100
http://www.fs2you.com/files/99003323-49dc-11dd-9d8e-0014221f4662/
目前没有发现BUG,不过还没有经过仔细调试,不敢保证完美。如果有朋友不幸遇见BUG了M我一下呀,谢谢咯~~ ^-^
本帖被评分 1 次
本帖被评分 1 次
SKDD 最后编辑于 2008-07-04 23:19:21
发送短消息
查看公共资料
查找该会员全部帖子
280500117
☆冷☆宝宝
称号:㈦冷dё寶寶
头衔:
灵动管理员
UID:
544
精华贴:
1
威望值:
100000
魅力点:
100000
功勋值:
100089
经验数:
1000848
积分点:
100150
灵动币:
80
状态:
在线
帖子:
737
最后报道:
2010-03-12
2008-03-10 00:46
|
树型
|
收藏
|
小
中
大
2
回复:【分享02】AS3实现RPG游戏地图引擎
我先加你魅力...教程等你起了.再写吧..哈哈...亲亲弟弟...
发送短消息
查看公共资料
查找该会员全部帖子
mhhf01@hotmail.com
44022867
鼓惑仔
称号:Zz.
头衔:
初显锋芒
UID:
34217
精华贴:
0
威望值:
0
魅力点:
5
功勋值:
5
经验数:
974
积分点:
35
灵动币:
0
状态:
离线
帖子:
160
最后报道:
2009-12-20
2008-03-10 13:15
|
树型
|
收藏
|
小
中
大
3
回复:【分享02】AS3实现RPG游戏地图引擎
......你就海啦。。。。有魅力。。。
发送短消息
查看公共资料
查找该会员全部帖子
ghzLiu@163.com
37266757
SKDD
头衔:
江湖老手
UID:
13
精华贴:
1
威望值:
3
魅力点:
3
功勋值:
1
经验数:
31
积分点:
12
灵动币:
0
状态:
离线
帖子:
30
最后报道:
2010-03-06
2008-03-11 23:53
|
只看楼主
树型
|
收藏
|
小
中
大
4
回复 2F ☆冷☆宝宝 的帖子
哇哈哈,谢谢宝宝姐~~ ^o^
今天只赶出【03】的详细说明,这一篇的只有明天咯~~
时间真是很不经用呀.... - -||
发送短消息
查看公共资料
查找该会员全部帖子
280500117
SKDD
头衔:
江湖老手
UID:
13
精华贴:
1
威望值:
3
魅力点:
3
功勋值:
1
经验数:
31
积分点:
12
灵动币:
0
状态:
离线
帖子:
30
最后报道:
2010-03-06
2008-03-13 16:03
|
只看楼主
树型
|
收藏
|
小
中
大
5
回复: 【分享02】AS3实现RPG游戏地图引擎
首先来回忆一下人物移动在程序中的控制方法。舞台上的人物
man
具有成员
dirx
和
diry
,它们的值可以等于
-step
,
0
或
step
。
step
是每次移动的步长。
man
在发生
ENTER_FRAME
事件的时候将自己的
x
和
y
分别以
dirx
和
diry
递增,以达到移动的目的。当玩家按下键盘或鼠标后,人物需要运动的方向由
onDirEvent
或
onMouseEvent
函数解析出来并存放到
dirArr
数组,然后调用函数
setDir
来适当更改
man.dirx
和
man.diry
以改变人物的运动状态。
人物的
8
方向运动包含
4
个轴向和
4
个斜向。斜向分解开来其实就是人物同时在
x
向和
y
向运动,所以在写代码的时候是不需要单独处理的。那么只需要考虑人物在一个轴向运动时可能发生的各种碰撞情况,另一个轴向如法炮制就可以了。在具体讨论之前,先有必要介绍一下判断中需要用到的一些
MC
工具和一些变量的定义。
直接用在地图上跑动的人物图像来判断碰撞并不是一个好办法。因为如果直接让人物去碰障碍物,画面上的显示要么是人会挡住障碍物被碰到的部分,要么是障碍物挡住人被碰到的部分,而无论哪一种都是不理想的画面。我们要做的是:在发生遮挡之前就判断好人物下一步运动是否会碰到障碍物而发生重叠遮挡,如果是的话就根本不让人物再继续前进了。
要做到这个判断其实很简单。假设所有人物跑动的动画都封装在一个限定大小的
MC
里,人物跑动的步长为
step
。如下图所示:
我的人物跑动动画每一帧的大小始终都不会超出图中蓝色矩形部分。而红色矩形是一个在各个方向都比蓝色矩形宽一个
step
长度的矩形(
4
个顶点被另外的
MC
挡住了,以后说明)。现在用红色矩形(名为
blk
)代替实际人物动画来判断与场景中障碍物的碰撞情况就没有问题了。若障碍物碰到了
blk
,如情况
B
,人物停止向障碍物的方向运动。如果没有碰到,最极端的情况是
A
,障碍物刚好与
blk
擦边。但
blk
比
man
宽一个
step
,下一步人物也只会运动到
C
位置,也就是障碍物刚好与实际人物动画擦边。这样就避免了碰撞检测中的遮挡问题。实际应用时,将
blk
放到人物运动动画的一个图层里,并在人物初始化的时候设置
blk
的
visible
属性为
false
就好了。
如上两幅图所示,这里引进了几组新变量,它们的意思解释如下:
假设人物与障碍物碰撞了,并且使用
PPCD.getCollisionPoint
得到了碰撞边界矩形的中心点(如图
B
、
C
中的点和方框所示):
var
pt
:Point=PPCD.getCollisionPoint(this.blk, map, mapCon);
要知道
man
在哪个方向、多远距离碰到了障碍,只需要比较
man
的坐标
(x, y)
和
pt
的坐标
(pt.x, pt.y)
就行了。这里对这两个点的坐标作差:
var
dx
:Number=pt.x-this.x;
var
dy
:Number=pt.y-this.y;
使用
dx
和
dy
的方便之处在于它们的符号就代表着碰撞发生的方向。为了以后算法的方便,还有两个变量分别保存上一次碰撞时的
dx
和
dy
。当没有碰撞时,这两个值将被清零:
var
dxl
:Number=0;
var
dyl
:Number=0;
注意,若仅在
x
轴向做运动时,
pt.x
最多只会在
C
图的位置。换句话说,
dx
的绝对值应该大于等于
w
,其中
w
的定义为:
var
w
:Number=(width-step)/2;
同理也有
var
h
:Number=(height-step)/2;
这在后面判断“擦边”运动时会用到。另外,因为
blk
放进了
man
里,所以这里
man
的
width
和
height
属性其实就别是
blk
的宽和高。
好了,现在开始正题,碰撞检测。
原理很简单:碰撞肯定是由人物向某个方向(这里假定为
x
负方向,如情况
A
所示)运动产生的。为了检测方便,先引入两个变量来存放当前人物的运动方向:
var
dirxl
:int=sign(dirx);
var
diryl
:int=sign(diry) ;
其中
sign(n)
是符号函数,
n
为正返回
1
,为负返回
-1
,等于
0
则返回
0
。这两个变量也将在没有碰撞时被清零。
既然在这个运动方向碰撞了,则要禁止人物再向该方向运动。对于这里假定的
x
向就是:
if(dx!=0 && Math.abs(dy)<h){
停止再向这边运动!
}
之所以要加一句
Math.abs(dy)<h
是由于下列这样的情况:
如上图,虽然有碰撞点但这时
x
向并不是真正的有障碍。这种障碍碰到了人物边缘但人物仍可以“擦边”运动的情况只需要做:
if(dx!=0 && Math.abs(dy)>=h){
if(dirx){
dirxl=sign(dirx);
}
}
为什么要把运动方向存进
dirxl
稍后就清楚了。
要让人物在
x
负向停下来,这里不可以直接做操作
man.dirx=0
。因为
dirx
和
diry
是函数
setDir
运作的关键,在
setDir
外随意它们更改会导致
setDir
不能正常工作。那么这里再引进两个新的局部变量:
var
ctrx
:uint=1;
var
ctry
:uint=1;
并将
man
的位置递增语句改为:
this.x+=dirx*ctrx;
this.y+=diry*ctry;
这样若要停止人物运动,只需要将相应的
ctr
变量赋值为
0
就好了。
禁止人物再向该方向运动的办法如下:
dirxl=sign(dirx);
if(dirx*dirxl>0){
ctrx=0;
}
先将碰撞时人物的运动方向存进
dirxl
。当人物继续向该方向运动时会使
ctrx=0
,人物被停止向该方向递增。而当人物改变了运动方向后,
ctrx
依然为
1
,人物被允许以
dirx
递增
x
位置。这就是为什么特意引进
dirxl
、
diryl
的原因:使程序保存造成碰撞的运动方向,并拿它与当前人物的运动方向来对比,进而通过
ctrx
、
ctry
决定是否允许人物继续运动。
碰到障碍后仅仅让人物在舞台上停止运动并不是个好主意,这只会让这个
RPG
游戏的主人公看起来很呆。更好的做法是:让程序能够自动使人物滑离障碍物从而继续前进。有了之前定义的众多变量的帮助,其实这一点太容易办到了:
if(dirx!=0 && diry==0){
this.y+=-sign(dy)*step;
if(dy){
diryl=-sign(dy);
}
}
别忘了之前说过,使用
dx
和
dy
的方便之处在于它们的符号就代表着碰撞发生的方向。要滑离障碍物,只需要向
dy
的反方向走就行了。如果玩家没有手动控制
y
向移动,则让代码来帮他吧,只是别忘了把
y
向的运动方向保存进
diryl
,因为在向
y
向的运动途中也可能再碰到障碍,这也就带出了逻辑最复杂的地方。
6楼继续.......
SKDD 最后编辑于 2008-03-13 16:07:08
发送短消息
查看公共资料
查找该会员全部帖子
280500117
SKDD
头衔:
江湖老手
UID:
13
精华贴:
1
威望值:
3
魅力点:
3
功勋值:
1
经验数:
31
积分点:
12
灵动币:
0
状态:
离线
帖子:
30
最后报道:
2010-03-06
2008-03-13 16:05
|
只看楼主
树型
|
收藏
|
小
中
大
6
回复: 【分享02】AS3实现RPG游戏地图引擎
如下图所示,情况
A
、
B
、
C
都是代表人物向
x
负方向移动碰到障碍的情况,上面已经讲述过了。而
D
、
E
、
F
则是在
x
负向被禁止后,玩家手动(擦边运动)或代码滑动人物在
y
向的位置时可能产生的碰撞情况。
D
其实已经解决了解决:若是从手动控制人物在
y
向“擦边”走得来,
y
向运动则会在
y
轴对应的
if(dy!=0 && Math.abs(dx)<w)
判断里被停止;若是代码自动滑动得来,由于碰撞后
dy
反号了,代码会再把人物重新向上滑动。而
E
则是新情况了:手动的话虽然
y
向有
if(dy!=0 && Math.abs(dx)<w)
阻止,但此时
dx=0
!这样会造成禁止
x
负向运动的判断
if(dx!=0 && Math.abs(dy)<h)
被跳过。代码的话
dx=0
,滑动也会被跳过。而
F
更糟糕:
dx
和
dy
都等于
0
!所以现在得为这两种情况分别添写新处理方案,否则这些碰撞将不被处理,人物将可以穿墙而过!
好在
E
的
dy
还不为
0
,至少
y
向运动还有
if(dy!=0 && Math.abs(dx)<w)
阻止,这个判断也正是处理
y
向上对应的
A
、
B
、
C
情况的代码。由于禁止
x
向运动的代码被跳过了,这里需要再在这个
if
里面嵌套个
if(dx==0)
来补上,这样情况
E
就解决了:
if(dx==0){
if(dirxl && Math.abs(dy)<h){
if(dirx*dirxl>0){
ctrx=0;
} else if(dirx*dirxl<0){
dyl==100;
dirxl=0;
unHit=true;
}
}
}
其中
else
语句中的清零是为了防止
bug
,马上在下一种碰撞情况
G
里有解释,它对应的情况如下图所示:
要导致
dx=0
还有一种情况,那就是大图中最后一种情况
G
:最初向上走然后碰到一个刚好在人物
y
中轴线上的障碍,或者一个大面积的
Y
向障碍。这种情况也一并在这个
if(dy!=0 && Math.abs(dx)<w)
里的
if(dx==0)
里解决。
如果发生情况
G
了,虽然
dx=0
,但人物仍可以在
x
轴向上左右擦边运动,并且可能碰到障碍,如下图所示:
碰到障碍后的明显变化是
dy
由原来的
>h
变为
<h
,所以这里要处理由
G
擦边运动而产生的碰撞思路很简单:
1.
若在擦边运动,存运动方向
dirxl=sign(dirx);
(前文第一次提到擦边时已经这样处理了);
2.
存当前擦边时的
dy
值:
dyl=dy;
3.
若
dy
没变,则没有碰撞;若
dy
变了,撞了,则停止该
x
轴向运动;
4.
撞了若向相反的
x
向运动,则认为离开
x
向障碍,开始了新的擦边运动,
dirxl
清零;
这里要注意的是,如果反向
x
运动的话需要清零
dirxl
,这是因为只要反向走一步就一定没有再碰到了
x
向障碍了,而继续反向行走则可能遇到新的
x
向障碍,若不清零
dirxl
将导致反向
x
障碍穿墙
bug
。其中还有的
dxl
和
unHit
清零在下面的算法代码里解释。
上面的思路翻译为代码则是下面第二个
else
中的语句:
if(dx==0){
if(dirxl && Math.abs(dy)<h){
if(dirx*dirxl>0){
ctrx=0;
} else if(dirx*dirxl<0){
dyl==100;
dirxl=0;
unHit=true;
}
} else {
if(dyl==100){//
记录这时的
dy
dyl=dy;
}
if(dy!=dyl){// dy
变了,说明
x
方向也遇到障碍
if(unHit){//
记录此时
x
运动方向
dirxl=sign(dirx);
unHit=false;
}
if(dirx*dirxl>0){//
不可再向该
x
方向运动
ctrx=0;
} else if(dirx*dirxl<0){ //
反向
x
运动,认为
x
向没有碰撞了
dyl=100;
dirxl=0;
unHit=true;
}
}
}
}
引入
unHit
是因为碰到
x
向障碍后
dy
会变。但是若此时要反
x
向走离开
x
向障碍,
dy
也会变。而只有第一中情况的
dy
变化需要阻止当前
x
向运动,所以添加一个
unHit
来区分这两种情况。否则人物在擦边运动时碰到新障碍就被“黏住”走不掉了。同样要注意的是反
x
向行走后的清零防止
bug
。
好了,到这里就只有最后一种情况
F
没有处理了。其实很简单,因为导致情况
F
碰撞的
x
、
y
运动方向之前一定都已经存在
dirxl
、
diryl
里了,这里要做的只是简单的屏蔽,这表现在最后两个
if
判断:
if(dx==0 && dy==0){
var ptArr:Array=hitPoints();
if(ptArr.length==1){
dirxl=-ptArr[0].x;
diryl=-ptArr[0].y;
}
if(dirxl==0 && dirx!=0){
dirxl=sign(dirx);
}
if(diryl==0 && diry!=0){
diryl=sign(diry);
}
if(dirx*dirxl>0){
ctrx=0;
}
if(diry*diryl>0){
ctry=0;
}
}
唯一的例外是下面的情况:
解决这个问题的办法也很简单:倒数第三、第四个
if
:记录当前运动方向并阻止。
最后需要特别注意的情况是两边都全部被碰到,如下图:
虽然这种情况的得来和判断其实是和情况
F
一样的,但考虑到这种情况和其它碰撞情况之间的转换以及各种变量清零的麻烦和可能导致的
bug
,就特意写了一小段新算法来处理。
这种情况的处理思路上也很简单:有
3
个顶点都被撞到了,那找出剩下一个顶点的方向并只允许朝它的方向运动就好了。这其实就是最开始的代码段
var ptArr:Array=hitPoints();
if(ptArr.length==1){
dirxl=-ptArr[0].x;
diryl=-ptArr[0].y;
}
做的事情。而判断各个顶点是否被碰撞借用了挡住红色
blk
顶点的那
4
个绿色顶角正方形。
hitPoints
函数首先找出没有被碰撞的顶点,然后把这个顶点的方向
push
到一个数组并返回。如上图例子,
ptArr
就是一个含有一个
Point
的数组:
prArr[0]=(1, -1)
。
至此所有的碰撞检测情况就都分析完了。虽然情况繁多但逻辑并不晦涩,循序渐进仔细理清调理就好了。实际的检测代码也并不长。完整的检测代码参见源文件。(1楼)
SKDD 最后编辑于 2008-03-15 17:20:41
发送短消息
查看公共资料
查找该会员全部帖子
280500117
SKDD
头衔:
江湖老手
UID:
13
精华贴:
1
威望值:
3
魅力点:
3
功勋值:
1
经验数:
31
积分点:
12
灵动币:
0
状态:
离线
帖子:
30
最后报道:
2010-03-06
2008-03-13 16:13
|
只看楼主
树型
|
收藏
|
小
中
大
7
回复: 【分享02】AS3实现RPG游戏地图引擎
呼... 终于写完啦.. 好长哟..... +.+
发送短消息
查看公共资料
查找该会员全部帖子
280500117
coyisoso
头衔:
初来乍道
UID:
39
精华贴:
0
威望值:
0
魅力点:
3
功勋值:
0
经验数:
9
积分点:
3
灵动币:
0
状态:
离线
帖子:
6
最后报道:
2010-02-24
2008-04-10 01:17
|
树型
|
收藏
|
小
中
大
8
回复:【分享02】AS3实现RPG游戏地图引擎
哥哥顶你
发送短消息
查看公共资料
查找该会员全部帖子
<<
上一主题
|
下一主题
>>
1
/ 1 页
1
跳转
页
论坛跳转...
灵动官方
【活动公告】
【产品发布】
【新游快报】
近期热门
【葬魂之诗专区】
【勇者之路专区】
【天空之城OL】
游戏专区
【游戏开发者】
【游戏攻略】
【游戏杂谈】
【游戏资源】
休闲娱乐
【七嘴八舌】
【影视贴图】
【原创天地】
经典游戏区
【奥库兹的冒险者】
【乖乖猪世界专区】
【金庸群侠传】
【灵动喷射2专区】
【灵动嘻哈外传区】
【云之秘境专区】
【圣猫传】
站务管理
【接待大厅】
【高层议事】
【葬魂GM管理】
【掉单查询】
点这里立即冲值【灵动币】
【充值未到帐申诉点这里】
点这里立即冲值【灵动币】
【充值未到帐申诉点这里】
点这里立即冲值【灵动币】
【充值未到帐申诉点这里】
点这里立即冲值【灵动币】
【充值未到帐申诉点这里】
点这里立即冲值【灵动币】
【充值未到帐申诉点这里】
点这里立即冲值【灵动币】
【充值未到帐申诉点这里】
点这里立即冲值【灵动币】
【充值未到帐申诉点这里】
点这里立即冲值【灵动币】
【充值未到帐申诉点这里】
      
我的主题
我的帖子
我的精华
帖子标题
空间日志
相册标题
作 者