1. 首页 > 游戏攻略秘籍

游戏动态碰撞实现 动态碰撞检测

作者:admin 更新时间:2025-02-17
摘要:一、3D游戏是怎么检测碰撞的首先假设你对与碰撞检测相关的几何和数学知识已经有了基本的了解。在文章的最后,我将提供一些这方面的参考资料,以免你对它们感觉有点生疏。另外我还假设你已经读过 Jeff Lander的图形专栏里关于碰撞检测文章(“Crashing into the New Year,”“When Two Hearts Collide,”和“Collision Response: Bou...,游戏动态碰撞实现 动态碰撞检测

 

一、3D游戏是如何检测碰撞的

首先假设你对和碰撞检测相关的几何和数学姿势已经有了基本的了解。在文章的最后,我将提供一些这方面的参考资料,以免你对它们感觉有点生疏。另外我还假设你已经读过 Jeff Lander的图形专栏里关于碰撞检测文章(“Crashing into the New Year,”;“When Two Hearts Collide,”;和“Collision Response: Bouncy, Trouncy, Fun,”)。我将首先进行壹个大概的描述,接着快速地切入到核心内容里,通过这两步从上至下地深入到碰撞检测中。我将讨论两种类型的图形引擎中的碰撞检测:基于 portal的和基于 BSP的。每种引擎中多边形的组织各不相同,因此在 world-object型的碰撞检测上存在很大的差异。而object-object型的碰撞检测绝大多数地方在上述两种引擎里的是一样的,主要看你是怎样实现的了。当大家接触到多边形的碰撞检测时,大家还会实验怎样将其扩展到大家学过的凸型物体上。

为了创建壹个理想的碰撞检测程序,大家不得不在开发壹个游戏的的图形管道的同时就开始规划并创建它的框架。在项目的最后加入碰撞检测是等于困难的。想在开发周期的末尾创建快速的碰撞检测将很有也许会使整个游戏被毁掉,由于大家不也许使它能高效地运行。在好的游戏引擎中,碰撞检测应该是精确、有效而且特别快速的。这些标准意味着碰撞检测将要和场景的多边形管理管道紧紧地联系起来。这也意味着穷举法将无法职业??今天的3D游戏中每帧处理的数据量很也许导致打格,当你还在检测壹个物体的各多边形是否和场景中的其它多边形碰撞时,时刻已经过去了。

让大家从基本的游戏引擎循环开始吧(列表1)。快速浏览这些代码来得到碰撞检测的相关策略。大家先假设碰撞没有发生,接着更新物体的位置,如果发现发生了碰撞,大家将把物体移回原来的位置不允许它穿梭边界(或将物体销毁或执行一些预防措施)。然而,这个假设太过简单由于大家无法得知物体原来的位置是否仍然有效。你必须为这种情况设计壹个方法(否则你也许会尝试到坠机或被子弹击中的感觉??就是前面举的例子)。如果你一个热心的玩家,你也许已经注意到了在一些游戏当中,当你挨着墙壁并试图穿过去的时候,摄像机就开始震动。你正故事的就是将主角移回原位的情况。震动是由于取了较大的时刻片引起的。

Listing 1. Extremely Simplified Game Loop

while(1){

process_input();

update_objects();

render_world();

}

update_objects(){

for(each_object)

save_old_position();

calc new_object_position

{based on velocity accel. etc.}

if(collide_with_other_objects())

new_object_position= old_position();

{or if destroyed object remove it etc.}

Figure 1. Time gradient and collision tests.

然而大家的方式有缺陷,大家忘了在等式中加入时刻。图1告知大家时刻太重要了不能忘了它。即便物体在 t1或 t2时刻没有发生碰撞,它仍有也许在 t时刻穿过边界(t1

大家可以把时刻看成是第四维并将全部运算在4维空间中进行。然而这也许会让运算变得特别复杂,因此大家会避开这些。大家还可以创建壹个以 t1、t2时刻的物体为起始点的实心体,接着用它来和墙进行测试(见图2)Figure 2. Solid created from the space that an object spans over a given time frame.

壹个简单的方式就是创建壹个凸壳来罩住两个不同时刻的物体。这种方式效率低下也许会明显地降低你的游戏速度。以其创建壹个凸壳,还不如创建壹个围绕实心体的包围盒。大家进修其它的技术后再过来讨论这个难题。

有另一种相对容易执行但精度较低的方式,就是把给定的时刻段分为两分,接着测试时刻中点的相交关系。大家还可以递归地依次测定各段的时刻中点。这个方式比先前的方式要快得多,但不能保证能捕捉到全部的碰撞情况。

另壹个暗藏着的难题是collide_with_other_objects()方式的实现??即判断壹个物体是否和场景中的其它物体相交。如果场景中有很多的物体,这个方式也许消耗很大。如果要判断各物体和场景中其它物体是否相交,大家将不得不进行大概N选2次相对。因此相对次数会是N的平方次?(或表示成O(N2))。但大家可以用几种方式来避免进行O(N2)对的相对。举个例子,大家可以把场景中的物体分成静态的(被撞物)和动态的(碰撞物??即使它的速度为0也行)。就好象房间中的墙壁是被撞物,而壹个扔给墙壁的小球是碰撞物。大家可以创建两棵独立的树(每一棵对应一类物体),接着测试那些物体也许会碰撞的树。大家甚至可以对环境进行约定让一些碰撞物之间不发生碰撞??比如大家不需要在两颗子弹之间进行判断。现在在继续之前,(经过改进之后)大家可以说处理经过变得更加清晰了。(另壹个减少场景中成对的相对的方式就是建立八叉树。这已经超出了这篇文章的范围,你可以在Spatial Data Structures: Quadtree, Octrees and Other Hierarchical Methods文章中的For Further Info一节里读到更多关于八叉的信息)。现在让大家来看一下基于 Portal引擎,了解何故在这类引擎中一提到碰撞检测就会那么痛苦。

Portal引擎和Object-Object型碰撞

基于 Portal的引擎把场景或全球分割成较小的凸方形区域。凸方形区域很适合图形管道由于它们能避免重绘现象。不幸的是,对碰撞检测来说,凸方形区域会给大家带来一些困难。在我最近的一些测试中,壹个引擎中平均大约有400到500个凸方形区域。当然,这个数字会随着不同的引擎而有所变化,由于不同的引擎运用不同的多边形技术。而且多边形的数目也会因场景的大致而有所不同。

判断壹个物体的多边形是否穿过了场景中的多边形产生的运算量也许会很大。壹个最简单的碰撞检测法就是用球形来近似地表示物体或物体的一部分,接着再判断这些包围球是否相交。这样大家仅仅需要测试两个球体中心的距离是否小于它们的半径合(这表示发生了碰撞)。如果大家是用中心点距离的平方和半径合的平方进行相对,那更好,这样大家可以在计算距离时除去拙劣的开方运算。然而,简单的运算也导致了精确度的降低(见图3)。

Figure 3. In a sphere-sphere intersection, the routine may report that collision has occurred when it really hasn’t.

但大家仅仅是将这个不太精确的方式做为大家的第一步。大家用壹个大的球体代表整个对象,接着检测它是否和其它的球体相交。如果检测到发生了碰撞,那么大家就要进一步进步精度,大家可以将大的球体分割成一系列小的球体,并检查和各小球体是否发生碰撞。大家不断地分割检查直到得到满意的近似值为止。分层并分割的基本想法就是大家要尽也许达到适合需要的理想的情况。

Figure 4. Sphere subdivision.

用球体去近似地代表物体运算量很小,但在游戏中的大多数物体是方的,大家应该用方盒来代表物体。开发者一直用包围盒和这种递归的快速方式来加速光线追踪算法。?谑导手校�庑┧惴ㄒ丫�园瞬婧虬ABB(axis-aligned bounding boxes)的方法出现了。图5展示了壹个AABB和它里面的物体。Figure 5. An object and its AABB.

坐标轴平行(“Axis-aligned”)不仅指盒体和全球坐标轴平行,同时也指盒体的每个面都和一条坐标轴垂直。这样壹个基本信息就能减少转换盒体时操作的次数。AABBs在当今的许多游戏中都得到了应用,开发者经常用它们作为模型的包围盒。再次指出,进步精度的同时也会降低速度。由于 AABBs总是和坐标思平行,大家不能在旋转物体的时候简单地旋转 AABBs---它们应该在每一帧都从头计算过。如果大家了解每个对象的内容,这个计算就不算困难并不会降低游戏的速度。然而,大家还面临着精度的难题。假如大家有壹个3D的细长刚性直棒,而且要在每一帧动画中都重建它的AABB。大家可以看到每一帧中的包围盒的都不一样而且精度也会随之改变。

二、如何实现2D游戏的碰撞判定

无论是模型还是切片式骨骼动画都可以做。模型就普通碰撞体,切片式骨骼动画就用Box2D。

序列帧动画就相对麻烦了,由于是2d精灵图片,接着加碰撞体或者用Box2D都不现实。由于你想要的实际上是像素级碰撞检测。

序列帧动画又分为两种情况:第一种是一张张图片垒起来的,播放时就一张张切换。一种是一张大图,播放时切换精灵UV。无论哪种情况,主角在一帧中的的攻击判定实际上就只有武器的白刃部分。手动标出白刃部分的包围盒,接着通过配置文件记录下来。这样假设播放到第一帧,通过配置的碰撞盒文件得到这一帧碰撞盒在全球范围的坐标。接着,难题就转换成2d平面内的几何体碰撞检测难题。假如敌人一个简单包围盒,就是两个制度几何体的碰撞检测。如果武器很细,就转换为线段和OBB相交测试。如果武器很厚,就是两个OBB相交测试,这个就麻烦了。如果武器是个球,就是球体和OBB相交测试。

三、android游戏中碰撞消失如何实现

需要有『碰撞池』,专门用来放置框体。

比如『碰撞池1』里放人物A的『攻击框』,『碰撞池2』里放人物A的『受击框』,『碰撞池3』里放人物B的『攻击框』,『碰撞池4』里放人物B的『受击框』。

那么在人物碰撞计算时,只要计算『碰撞池1』和『碰撞池4』的碰撞情况,以及『碰撞池2』和『碰撞池3』的碰撞情况就足够了。

实际上在代码中,有很多更为精细的碰撞方法,比如圆形碰撞,路线矩形碰撞,物理引擎之类的。

根据实际情况选择合适的碰撞代码即可。

游戏碰撞的大致可以分为这几种类

1.主角和边界的碰撞,限制主角不能走出手机屏幕外。

2.主角和物理层的碰撞,和地图中的房子桌子椅子等等。

3.主角和游戏人物之间的碰撞,这里指NPC等。

4.主角和脚本框发生的碰撞,例如走进房间出线一段剧情对话等等。

由此可见游戏中的碰撞主要是可以分为

1.点和矩形之间的碰撞

2.矩形和矩形之间的碰撞

3.圆形和圆形之间的碰撞

4.圆形和矩形之间的碰撞

主要说明一下以上中最独特的壹个碰撞方法主角和物理层之间的碰撞。如图所示:每个小方块中储存着地图块的信息,在二位数组中如果为-1表示属于物理层不可通过,其它均可通过。也就是说-1这个地图块的位置绘制这物理层的物品。主角在行走的时候通过自己的坐标原点计算出自己在二位数组中的索引,接着根据索引找到数组中的数值判断自己是否可以通过。

绘制地图

根据地图编辑器生成出来的数组,一定是先绘制背景层地图,接着在绘制第物理地图等等。

物理碰撞层生成的数组是不用绘制的,只需要每次主角移动坐标的时候检测是否和物理层发生碰撞。

说到这里也许有些兄弟会问何故第一层要和第二层分开?这两层不能合二为一吗?

如图所示:用两个图层主要是为了化解物理层图片不能全部显示,好比下面这个荷花,它的绘制区域在矩形中周围白色的则是透明的区域,因此大家需要先绘制地图背景层在绘制物理层这样就可以遮盖透明区域。

代码的实现方法

首先大家需要利用onKeyDown()和onKeyUp()方式确定当前手机那个按键被按下,根据按键信息更新人物动画,检测是否碰撞。

mIskeyDown= true表示按下路线键下

mIskeyLeft= true表示按下路线键左

mIskeyRight= true表示按下路线键右

mIskeyUp= true表示按下路线键上

mHeroPosX表示人物的X坐标

mHeroPosY表示人物的Y坐标

mAnimationState表示播放动画的ID由于人物行走有4组路线的动画因此 mAnimationState可以修改播放那组动画

主角应该有两个坐标点

如图所示:何故主角要有2个坐标点的缘故是左上角的00点程序是不能进行逻辑判断的比如检测主角给右移动走超出屏幕,由于坐标点在左上角因此整个图片都走出屏幕以后程序才能判断出人物出屏,因此不能用左上角的点来作为主角的坐标原点,须要用下面的点来计算人物的逻辑坐标我的提议是大家只计算下面这个点接着根据这个点在算出来图片左上角的原点,接着在通知图像绘制。

判断碰撞检测

mCollision[][]这个二维数是地图编辑器生成出来的,用来组保存碰撞层的全部信息-1表示不能通过

mHeroIndexX、mHeroIndexY代表当前人物在二位数组中的索引位置,根据索引找到二维数组中的值判断是否碰撞

mBackHeroPosX、mBackHeroPosY备份发生碰撞前人物的坐标一旦碰撞以后将运用备份的坐标避免人物碰撞后不能返回。