飞行射击游戏:飞行射击游戏中的碰撞检测



在游戏中物体碰撞是经常发生怎样检测物体碰撞是个很关键技术问题在RPG游戏中般都将场景分为许多矩形单元碰撞问题被大大简化了只要判断精灵所在单元是不是有其它东西就可以了而在飞行射击游戏(包括象荒野大镖客这样射击游戏)中碰撞却是最关键技术如果不能很好解决会影响玩游戏者兴趣飞行射击游戏说白了就是碰撞游戏——躲避敌人子弹或飞机同时用自己子弹去碰撞敌人

  碰撞这很简单嘛只要两个物体中心点距离小于它们半径的和就可以了确实而且我也看到很多人是这样做但是这只适合圆形物体——圆形半径处处相等如果我们要碰撞物体是两艘威力巨大太空飞船它是 3角形或矩形或其他什么形状就会出现让人尴尬情景:两艘飞船眼看就要擦肩而过却出人意料发生了爆炸;或者敌人子弹穿透了你飞船右弦你却安然无恙这不是我们希望发生于是我们需要种精确检测思路方法

  那么怎样才能达到我们要求呢?其实我们前辈们已经整理总结了许多这方面经验如上所述半径检测法 3维中标准平台方程法边界框法等等大多数游戏员都喜欢用边界框法这也是我采用思路方法边界框是在编程中加进去不可见边界边界框法顾名思义就是用边界框来检测物体是否发生了碰撞如果两个物体边界框相互干扰则发生了碰撞用什么样边界框要视区别情况而定用最近似几何形状当然你可以用物体准确几何形状作边界框但出于效率考虑我不赞成这样做游戏中物体般都很复杂用复杂边界框将增加大量计算尤其是浮点计算而这正是我们想尽量避免但边界框也不能和准确几何形状有太大出入否则就象用半径法样出现奇怪现象

  在飞行射击游戏中我们飞机大多都是 3角形我们可以用 3角形作近似边界框现在我们假设飞机是个正 3角形(或等要 3角形我想如果谁把飞机设计成左右不对称怪物那他审美观定有问题)飞机是正着、向上飞 3角形敌人飞机是倒着\" width=205 align=left border=0>、向下飞 3角形且飞机不会旋转(大部分游戏中都是这样)我们可以这样定义飞机:中心点O(Xo,Yo), 3个顶点P0(X0,Y0)、P1(X1,Y1)、P2(X2,Y2)中心点为正 3角形中心点即中心点到 3个顶点距离相等接下来问题是怎样确定两个 3角形互相干扰了呢?嗯现在我们接触到问题实质了如果你学过平面解析几何我相信你可以想出许多思路方法解决这个问题判断个 3角形各个顶点是否在另个 3角形里面看起来是个不错思路方法你可以这样做但我却发现个小问题:个 3角形顶点没有在另个 3角形里面\" width=200 align=right border=0>可能发生了碰撞个 3角形顶点在这个 3角形里面所以要判断两次这很麻烦有没有次判断就可以思路方法?我们把 3角形放到极坐标平面中中心点为原点水平线即X轴为零度角我们发现 3角形成了这个样子:在每个角度我们都可以找到个距离用以描述 3角形既然我们找到了边到中心点距离那就可以用这个距离来检测碰撞如图两个 3角形中心点坐标分别为(Xo,Yo)和(Xo1,Yo1),由这两个点坐标求出两点距离及两点连线和X轴夹角θ再由θ求出中心点连线和 3角形边交点到中心点距离用这个距离和两中心点距离比较从而判断两 3角形是否碰撞 3角形左右对称所以θ取-90~90度区间就可以了现在问题有趣多了-90~90度区间\" width=200 align=left border=0>正是正切定义域求出θ的后再找对应边到中心点距离就容易多了利用几何知识如图 2将 3角形边分为 3部分,即图2中红绿蓝 3部分根据θ在那部分而分别对待用正弦定理求出边到中心点距离即图2中浅绿色线段长度但是如果飞机每次移动都这样判断效率仍然很低我们可以结合半径法来解决先用半径法判断是否可能发生碰撞如果可能发生碰撞再用上面思路方法精确判断是不是真发生了碰撞这样基本就可以了如果飞机旋转了如何办呢例如如图 3所示飞机旋转了个角度α仔细观察图 3会发现用(θ-α)就可以求出边到中心点距离这时你要注意边界情况即(θ-α)可能大于90度或小于-90度啰罗嗦嗦说了这么多不知道大家明白了没有我编写了个简单例程用于介绍说明我意图在例子中假设所有飞机大小都并且没有旋转 ///////////////////////////////////////////////////////////////////////example.cpp//碰撞检测演示//作者 李韬///////////////////////////////////////////////////////////////////////限于篇幅这里只给出了碰撞检测///////////////////////////////////////////////////////////////# NUM_VERTICES 3# ang_30 -0.5236# ang60 1.0472# ang120 2.0944//deftype////////////////////////////////////////////////////////////struct object{ float xo, yo; float radio; float x_vel, y_vel; float vertices[NUM_VERTICES][2];}//faction///////////////////////////////////////////////////////////////根据角度求距离float AngToDis(struct object obj, float angle){ float dis, R; R = obj.radius; (angle <= ang_30) dis = R / (2 * sin(-angle)); (angle >= 0) dis = R / (2 * sin(angle + ang60)); dis = R / (2 * sin(ang120 - angle)); dis;}//碰撞检测 CheckHit(struct object obj1, struct object obj2){ float deltaX, deltaY, angle, distance, bumpdis; deltaX = abs(obj1.xo - obj2.xo); deltaY = obj1.yo - obj2.yo; distance = sqrt(deltaX * deltaX + deltaY * deltaY); (distance <= obj.radio) { angle = atan2(deltaY, deltaX); bumpdis1 = AngToDis(obj1, angle); (distance <= 2 * bumpdis); } ruturn 0;}//End//////////////////////////////////////////////////////////////



  上面只是用于演示并不适合放在游戏中但你应该明白它意思以便写出适合你自己碰撞检测游戏中情况是多种多样没有哪种思路方法能适应所有情况定能根据自己情况找到最适合自己思路方法




Tags: 

延伸阅读

最新评论

发表评论