下面图老师小编要向大家介绍下俯视视角游戏碰撞检测:限定移动类型和不限定移动类型-Flash actionscript,看起来复杂实则是简单的,掌握好技巧就OK,喜欢就赶紧收藏起来吧!
【 tulaoshi.com - FLASH 】
poluoluo核心提示:俯视视角游戏常见碰撞检测方法全解(4) 360度不限定移动类型.
(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/flash/)(3)4或8方向限定移动类型
如果你已经看到这里,我们已经对要制作的东西做了两次分类
第一次将整个游戏分类,取了俯视的一部分
第二次将俯视分类,取了4或8方向限定移动类型(下文简称限定移动)
这样的化整为零是结构化面向过程程序设计和面向对象程序设计的正确思路,我们将继续这个思路,直到问题简化到能用具体办法解决为止。
后文会用类似下面粗体字的明确书签标志当前的划分层次,避免逻辑混乱
每个类型本人会举大量经典游戏作为例子,方便对号入座
限定移动可以分为完全限定移动和不完全限定移动。
前者的每个元素(玩家、敌人、地图元素等)必须与地图的分格一一对应
后者只是限制了玩家的操作是4方向或8方向的,但是未必对应地图的分格
3.1 游戏-俯视-限定移动-完全限定移动
特点:某游戏主要使用键盘操作,玩家只能向上下左右移动,障碍物是矩形障碍,大小和坐标非常统一,对齐到网格,等同于玩家大小的障碍。
举例:传统rpg、传统slg、吃豆精灵、推箱子、包括部分方块类。此类游戏的首选碰撞方式是数组地图,数组地图是一个二维数组:
这是一张简易的数组地图。我们可以用0来表示空地,用1来表示石头
玩家有自己在数组地图上的坐标。
玩家(player)的现坐标为(3,2),注意,数组是从0开始计数的,而不是1
如果操作玩家向左移动,那么检测(3-1,2)是否为0,该位置是0,返回false,玩家可以移动
如果该位置操作玩家向右移动,检测到(3+1,2)是1,返回true,发生碰撞,禁止玩家的移动
玩家和敌人在地图上随时写入数组,如玩家用2标识,敌人用3标识,
某单位移动时将数组地图对应该单位坐标清零,并在该单位的新坐标处把0修改为该单位标识
此类游戏存在投射性武器不写入数组
武器检测碰撞时,根据武器的坐标计算出该武器属于数组地图的哪一格
例如真实地图的每格宽度为20
炮弹真实坐标(212.5,113),以bullet.x和bullet.y表示:
得到bulletMapX = 20,bulletMapY = 10,即其在数组地图上坐标。
只检测数组地图上的(20,10)位置标识,即可判断炮弹应继续飞行还是爆炸,如果爆炸杀伤的目标是谁。
SLG游戏可能需要自动寻路。tulaoShi.com数组地图公认A*算法为先进高效的寻路方法,该算法可于百度搜索到,不再赘述。
3.2 游戏-俯视-限定移动-不完全限定移动
特点:某游戏主要使用键盘操作,玩家只能向上下左右移动,障碍物是矩形障碍,大小和坐标可能不统一,没有小于玩家大小的障碍。
举例:赤色要塞、魂斗罗2的第二关等ACT游戏,大部分手柄操作的ARPG如黄金太阳(GBA)、赛达尔传说(NDS前的版本)。
此类游戏可以使用点描述方法检测碰撞,用顶点作为碰撞点,其点碰描述整个物体碰撞的方法。
图中红色点即为顶点,其坐标为(player.x±20,player.y±20)
在地图没有小于玩家的物体条件下,玩家碰撞物体等价于不少于1个顶点碰撞了物体
使用DisplayObject/hitTestPoint前,需将所有地图上固定的物体放入一个容器内,而不要用for循环检测与每个物体的碰撞。
运动物体虽然可以放入这个容器,但是运动物体往往是玩家自身或者需要运动碰撞检测的敌人自身,放入容器会导致和自身的碰撞检测,恒为true,没有意义。
解决办法是将碰撞点向外侧移动。略微放大碰撞区域,这样就不会与自身碰撞。
如碰撞区域必须小于等于运动物体实际图形大小,那么必须单独在运动物体之间检测碰撞(运动物体数量少使用for循环,如果运动物体过多需较高的解决方法,参加4楼使用BitmapData/hitTest的办法),不能使用这个方法。
如地图上的固定元素有小于玩家宽高大小,但是不小于玩家宽高大小一半的大小,请适当增加碰撞点数量
(4):360度不限定移动类型
特点:可能使用键盘或鼠标操作,玩家可以向任意方向移动,障碍物形状未必固定,大小和坐标未必统一,所有元素自由度非常高。
举例:赛车类游戏,大部分战争题材纵版游戏
此类游戏可以使用位图碰撞、点描述和函数描述的办法检测碰撞。
4.1 游戏-俯视-不限定移动-位图碰撞
使用BitmapData/hitTest
具体办法是将玩家用BitmapData.draw方法转成位图数据(注意,这个方法不会考虑玩家的缩放)
地图可能非常大(比如2000x1500)这个转换成位图效率非常低下。
正确的做法是根据玩家坐标,只描绘玩家周围的一小部分位图。
描绘区域高度有 玩家高度+玩家速度x2 即可
此方法效率很高,能立刻检测玩家是否碰撞了地图障碍,缺点也比较明显,就是不知道玩家的哪一点碰撞了地图障碍。一个赛车游戏如果用这个的话,只能做成碰到墙立刻爆炸或碰到墙立刻减速为0再或碰到墙立刻速度变成相反的等很绝对的判定。
BitmapData/hitTest的检测比较万能。
前面提到的所有碰撞都可以用它来检测,考虑缓存大小和效率问题,如果运动物体很多的话不能完全依赖。
4.2 游戏-俯视-不限定移动-点描述
比起4方向移动的点描述,360度点描述相对需要计算,必须大量使用三角函数
(三角函数是常规解决方案。个别高手使用矩阵或者向量乘法表示角度,尤其是向量乘法表示角度能减少计算量,提高速度)
设上图剪辑为mc。
mc的箭头指向为mc注册时的y轴方向,现在mc右旋转了rotation度
设剪辑注册时的宽度(即短边长度)为og_width;
设剪辑注册时的高度(即长边长度)为og_height;
如果不使用极坐标,碰撞点相对mc的坐标可以通过三角函数算出
本人推荐熟练的程序员自行制作极坐标类,在360度移动的俯视视角游戏中作用很大
hitTestPoint检测的是一个全局坐标和某剪辑的碰撞
使用mc的localToGlobal方法获得点的全局坐标
之后即可检测其与碰撞区是否碰撞。
此方法优点在于能较清楚地知道剪辑究竟哪里与外界碰撞。
例如,一台汽车与房子碰撞,我们检测到了一辆前进的车碰撞点是车的左前,那么可以在这个点播放一个碰撞火花动画并根据这个碰撞作出车应该被动向右转向和减速的判断。
上例给了车4个碰撞点。碰撞点越多,对这次碰撞的描述越清晰。
如果同时有两个以上的点发生碰撞,取其中点作为这次碰撞的实际发生点。
例如此方块向箭头方向运动,红点和绿点同时检测到碰撞,可以认为是此方块前方正中发生了碰撞,并作出方块直接速度反向并在前方正中播放碰撞火花动画的判定。
4.3 游戏-俯视-不限定移动-函数描述
特点:障碍物形状未必相同,但是规则的几何图形,或者能近似考虑成几何图形,注册点严谨在几何中心,总数量较少。或项目出现难以用点描述的情况。
举例:台球为代表的球类平面游戏,停车场等要求非常精准碰撞的游戏
停车场虽然用BitmapData/hitTest也可以制作,但是找不到碰撞点,不如后面方法。
此类碰撞不使用flash自带的碰撞接口,使用的是高中数学知识。
首先定义几个基础类:
Line
//线段类,属性有a,b,c,P1,P2,其中P1,P2为端点,线段上的坐标为(x,y)的点满足a*x+b*y+c==0
Box
//矩形,属性有P1,P2,P3,P4即四个顶点,get方法能得到任意两点间的线段L12,L23,L34,L41: Line
Ball
//圆形,属性有x,y,r,即圆心横、纵坐标,半径
最长应用的数学公式如下:
点之间距离公式(勾股):Math.sqrt((P1.x-P2.x)*(P1.x-P2.x)+(P1.y-P2.y)*(P1.y-P2.y))
点到直线距离公式:Math.abs(a*x+b*y+c)/Math.sqrt(a*a+b*b);
线段联立方程://求解过程略
a1*x+b1*y+c1 == 0;
a2*x+b2*y+c2 == 0;
过后补出AS3.0类
我们可以通过检测方程联立解是否在线段上判断两条线段碰撞。
可以用圆心距离是否小于半径和判断两个圆形碰撞。
可以用圆心到直线距离是否小于圆半径判断球和直线的碰撞
可以综合分析四条边分别有无碰撞,以及是否出现一个矩形包含另一个,来判定两个矩形的碰撞
上述检测方法都能将具体碰撞的位置求出
试举一个用函数碰撞优化的例子:
此图中,玩家的炮台发射了一道长度1000的直激光。敌人有3个,要检测是否命中敌人。
hitTestObject首先被排除掉了,理由略。
接着排除的是BitmapData.hitTest。因为BitmapData的效率极大取决于位图大小,这道激光斜着发射的话将会被缓存1000/1.414 x 1000/1.414的很大的位图。
hitTestPoint可以作碰撞检测。在激光上定比分点,根据敌人大小。如敌人大小是20宽度,那么每20个像素长度取一个点检测碰撞,共取50个点。每个点检测3次碰撞,循环共150次。
如果此图情况用点到直线距离小于圆半径作为判断条件,将大大地减少计算量。只需要3个敌人各自使用这个公式检测一次就够了。
待续。。。
来源:http://www.tulaoshi.com/n/20160318/1886257.html
看过《俯视视角游戏碰撞检测:限定移动类型和不限定移动类型-Flash actionscript》的人还看了以下文章 更多>>