DIRECTOR 之游戏碰撞学二

《碰撞检测》阶段性小结报告

 

时间:2002.11.28

 

第一部分:论坛资料整理

①第一贴

②第二贴

③第三贴

第二部分:研究心得

第三部分:研究范例

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

第一部分:论坛资料整理

 

话题名称:关于碰撞问题的探讨

话题发起人:sbljx

发起时间:2002-9-23 10:20:24

第一总贴:http://www.mobiusclub.com/bbs/dispbbs.asp?boardID=12&ID=12

 

(01)sbljx:-------------------------------------------------------------------------------------------------------

大家现在都用的什么碰撞原理?认为现有的碰撞原理合理吗?存在漏洞或缺陷吗?我认为这个问题已经到了要解决的时候了。怎样用计算机高效地模拟现实世界中的碰撞?

(04)sbljx:-------------------------------------------------------------------------------------------------------

首先,先看看一般的碰撞原理有什么缺陷。

    我以前用的最平常的碰撞是这样的。

拿两个像素点的一维运动和碰撞来举例,分别称之为Point1、Point2。假设我们赋予Point1的水平移动速度为1,而赋予Point2的水平移动速度为10,假设Point1的初位置为(0,0),Point2的初位置为(30,0)

    两个点相向运动,假设我们的位置更新和碰撞检测的频率为1秒,那么,我们很容易预计,在第2秒钟时,Point1的位置为(2,0),而Point2的位置为(10,0),此时两个点相距仅8个像素,还没有相遇,让我们看看看看下一秒后会发生什么。到第三秒时,Point1的位置为(3,0),而Point2的位置为(0,0),就这样错过去了,没有发生任何碰撞。我想把这种现象称为“瞬间穿透”。

    也许你会说,那我们把检测频率提高呢,不防让我们把这个频率提高到1豪秒,那么同以前一样,在第3毫秒时,他们依然无缘相遇。所以,无论检测频率提多高,都不会有用。因为这个运动机制就存在问题。这个运动机制有什么问题呢?现实世界中物体的运动机制是什么呢?以我们现有的眼界来看,在现实世界中,两个物体也许永远无法发生“瞬间穿透”现象。像黑客帝国那样,把整个现实世界想象成一个计算机模拟的虚拟世界(呵呵,用DR做的),那么这个模拟体系的所有事件的触发频率是无限大,可以想象成0秒(这怎么可以?^_^)。而且可以这么想象,他的运动机制绝不是单位时间的改变位移那么简单。我们平时所提的速度是用来描述物体运动快慢的,绝不能说,一个物体的运动速度为10米/秒,那么物体就会每秒钟位置突然改变一次。也就是说,物体的运动决定速度,速度只能描述运动,绝不是根据速度来使物体运动。

    (绕啊绕,绕口令听的好头疼。)

     现实世界的运动是这样的(其实也未必是这样,我们可以这样想象)。物体运动时,每次改变的位移是不变的,而且这个位移是现实世界的最小长度单位(有多小呢,我也不知道,反正比电子的半径小^_^),我们不妨称之为“绝对距离”。记得,每次改变的位移大小是不变的,就是这个最小距离单位,这时你会问,那么物体运动的快慢怎么改变呢。呵呵,想象一下,就是靠改变物体位移变换的频率来改变的。嘿嘿,比如说,假设物体的速度方向不变,一个物体每1秒位移变换一次,另一物体每10秒位移变换一次,那么,你说谁快呢?显然,第一个物体快,这是我们可以用速度来描述一下两个物体的运动快慢,第一个物体的运动速度是1绝对距离/秒,而第二个物体的运动速度是0.1绝对距离/秒。这只是描述,0.1绝对距离是不存在的,因为前面说绝对距离已经是最小长度了,最小长度怎么分成10份?

    好,现实世界的运动,我的理解就是这样。所以回到我们的计算机,解决碰撞时的“瞬间穿透”有两种大致方向。

    1.改变运动机制,模拟现实世界的运动机制。但这种方式显然目前的计算机是心有余而力不足,因为目前的计算机的cpu时钟频率与现实世界的最小时间单位相差太远,现实世界的cpu频率是无限大呵呵。所以用计算机模拟的话,物体的运动速度的上限很快达到,不够用了。

    2.保持运动机制,通过复杂的几何数学计算来进行碰撞判断。只能这样了,目前。这也许就是我们要探讨的,怎样编写一个合理高效的碰撞检测机制呢??

好,开始讨论!!!

(05)admin:------------------------------------------------------------------------------------------------------

很多时候我们是依靠精灵的运动然后获得精灵位置来判断碰撞检测。但是这里有两个过程:

1.director内部处理精灵的位置移动。

2.我们获得精灵的位置属性。

显然第二个是非常费时间的。

我想可以(已经有人这样提示过,cjx2000)用变量运算来替代前述的第一个环节!

所有的位置变动驱动都是直接针对这个变量。

然后第二步就是将变量反馈给精灵属性。

这样无疑速度会提供很多!

这个过程中director始终没有参与精灵位置的运算。仅仅是更新以及基于变量的运算(这个因为和舞台图象无关,所以速度提供很多吧!?)。

好!继续1

接下来我想的是如何仅仅依靠相关的变量来实现碰撞问题的检测!

因为处理变量的检测要快的多!...

好了!只是想法!具体还没来得及实验!

(06)stiff:--------------------------------------------------------------------------------------------------------

Dir是基于时间轴,以帧的事件来触发行为。但究竟是多少时间执行一次呢?是我们设置的帧速率吗?如果帧速率是25F/S,那么是每1/25秒执行一次当前帧下的lingo脚本吗?碰撞根据什么进行呢?我想应该是基于时间的吧。也许有人会说是基于Windows的消息机制,但Windows的消息多长时间执行一次呢?这个时间到了Dir中又会变成多少呢?如果在当前帧下有两个行为:

1.on exitFrame me

  go to the frame

 end

2.on exitFrame me

  repeat with...

 end

那么,这两个脚本同时执行时是什么情况呢?是不是第二个exitframe在执行repeat的时候第一个exitframe就停止不动啦?当然不是,第一个exitframe照样执行他的代码。但如果两个exitframe中都有repeat循环语句,那怎么检测呢?实际实验结果就是先把第一个exitframe执行完,然后执行第二个exitframe。所以,你要想在两个行为中对同一物体的属性进行检测是得不到正确结果的。因为他会在外界因素干扰完的情况下才会响应你的操作。

因此,用一个行为检测要碰撞物体的属性,用另一个行为进行相关设置,我认为是有时间差异存在的!即,要想实现检测,最好在一个行为中进行,或者在同一段代码中执行,不要为碰撞的两个物体设置类似的检测代码,不要说看谁先碰到谁,而要以第三者的身份同时对目标进行检测。

如果上述文字成立的话,应该可以扩展到所有的行为检测中去。

(08)sbljx:-------------------------------------------------------------------------------------------------------

你们两位对我的启发非常之大,真的是非常大。头一次这么明显地感觉倒,团结也可以使思考产生更耀眼的火花!!!

three-m的变量计算可以前面提到的计算机所能够达到的速度上限大大提高。

stiff的第三方检测变量不仅能够使碰撞检测做到同时,而且能够大大节省系统资源。

呵呵,我试着结合两位高手的精华做个简单的碰撞检测机制看看。

另外,鉴于three-m的变量算法,我决定物体运动机制完全模拟现实世界的运动!!!也就是说,按照我上面提到的第一个方向来研究。呵呵,好像看到曙光了。

(09)sbljx:-------------------------------------------------------------------------------------------------------

是依次顺序执行的。任何事情都有先后的。不可能同时执行。

(10)stiff:--------------------------------------------------------------------------------------------------------

我的意思是两个exitframe有时是执行完一个后才会去执行另一个。如果你在一个exitframe中用循环设置物体的位置,在另一个行为中用循环检测其属性,得到的应该永远是最后一个位置,即第一个exitframe执行完后的结果,中间改变位置后的结果可能检测不到。

(11)sbljx:-------------------------------------------------------------------------------------------------------

没错!

(12)sbljx:-------------------------------------------------------------------------------------------------------

研究编写了一个基于不同机制的运动碰撞,大家下载后看看,我想说的都在源文件中。

              http://www.mobiusclub.com/bbs/uploadImages/20029259291472452.zip

(13)sbljx:-------------------------------------------------------------------------------------------------------

呵呵,three-m终于上道了。你说的完全正确!!!呵呵,我做的那个例子就是基于速度仅为1的运动机制。体现速度的方法也可以从我那个大长贴中找到。在我那个例子中所有物体的运动速度无论如何都是1。但要想体现物体运动的快慢,就得改变触发物体运动的频率。

我那个例子就是这样的。继续研究。

(14)stiff:--------------------------------------------------------------------------------------------------------

如此说来,你的核心思想就是要改变 “模拟世界中的最小时间单位” 这个时间单位,以获得最小的执行时间吗?three-m也说你是用on idle来处理,但我对idle没有多少太明确的概念:(

(15)stiff:--------------------------------------------------------------------------------------------------------

sbljx是利用intersect判断,three-m是利用rect重合判断,对吗?

(16)sbljx:-------------------------------------------------------------------------------------------------------

three-m的例子看过了。那个例子很简单啊。可是我要问几个问题

1.我要改变物体运动快慢怎么办

2.物体的垂直方向上的速度怎么控制

3.呵呵,这个问题以后再问

(18)sbljx:-------------------------------------------------------------------------------------------------------

物体的垂直方向上的速度怎么控制?我是说你那个例子只能支持物体的水平运动,我想要垂直运动,或者水平与垂直叠加的效果。

(19)sbljx:-------------------------------------------------------------------------------------------------------

以下是引用Three-m在2002-9-27 11:51:28的发言:

...

 if the milliSeconds -RunTimer>20 then

 ....

 

 修改这个20的数值,就可以控制运行周期。

 这个就是cxj2000的计时方法。

 

这样确实可以,但要想在程序中动态控制物体运动速度怎么办?不能每次都用手工改吧。呵呵,等你的程序满足了我的一系列要求后,就会发现,跟我的程序一样复杂了。

(20)sbljx:-------------------------------------------------------------------------------------------------------

以下是引用Three-m在2002-9-27 15:33:22的发言:

垂直运动一样的啊!在offset中设置即可。但是如果是一成非45度角度的,就要复杂一些

http://www.mobiusclub.com/bbs/uploadImages/200292715331646931.rar

 

当然要所有角度的。也就是说,垂直速度和水平速度是不同的。

(21)sbljx:-------------------------------------------------------------------------------------------------------

大家,我正在做一个运动系统,包括物体运动,碰撞,力的作用等等。呵呵,蛮有趣的,如果做得好说不定会有些价值

(23)sbljx:-------------------------------------------------------------------------------------------------------

对。所以针水平和垂直要有各自的计时器。我那个OBTimeup句柄之所以复杂,就是因为这个原因,另外还需要一个计时器,那就是控制物体刷新位置的频率。所以OBTimeup句柄中一共有三个计时器工作,所以看起来当然复杂。

另:我的运动系统是基于面向对象的。所以有一堆函数方法可以调用。呵呵,到时,我会给出相关文档。

(00)第一贴截止时间:2002-10-30 17:42:42

 

 

 

 

 

 

 

 

 

 

 

 

 

第二总贴:关于<关于碰撞问题的探讨>的探讨

发起人:truka

发起时间:2002-11-6 17:40:11

网站链接:http://www.mobiusclub.com/bbs/dispbbs.asp?boardID=12&ID=577

 

(01)truka:-------------------------------------------------------------------------------------------------------

大家好,我第一次来学术讨论区。

 

看过大家的<关于碰撞问题的探讨>一贴,觉得焦点问题是集中在如何解决瞬间穿透上面。

之前我做过一个桌球游戏,也碰到过类似的一些问题,我想就我的一点经验谈谈我的看法。

 

任何游戏都是基于帧的形式来运作的,就是说游戏中的事物是跳动式进行的(无论它多么接近于连续进行,但用远不可能达到),而自然界的事物则是无限连续的。在检测碰撞这个问题上确实可以用提高检测频度来获得更精确的碰撞点位置,但是我觉得这样做的代价太大,一个游戏必须有稳定的帧速率,提高检测频度无疑会使游戏速度直线下降。所以我在制作桌球的时候放弃了这种思路,取而代之是另一种思路,我称它为穿透纠正。

如果要检测两个物体之间有没有发生碰撞,必须实时监测两者之间的距离(这个代价是很小的)。在两物体发生碰撞之前,它们的边缘距离(对于两个球来说就是它们的圆心距离减去它们的半径之和)必然是在逐渐缩小(否则就不会发生碰撞),在它们发生碰撞之后边缘距离必然是逐渐扩大。如果我们实时监测着这个边缘距离增量值,当检测到增量值由负变为正的一刻,程序就转入穿透纠正模块。

此时可以确定碰撞发生点肯定在物体此刻的位置和它的上一个位置(上一帧的位置)之间。如果要计算出足够精确的碰撞发生点,我们需要几个值:物体此刻的位置和速度,物体在前面一帧时的位置和速度。这4个值很容易得到。

接下来是计算足够精确的碰撞发生点。思路是这样的,让物体从上一帧的位置放慢速度慢慢前进到此刻的位置。当然这个过程需要放大,才能得到足够的精度,也就是说水平方向和垂直方向的速度必须分别取上一帧时的值后再按比例缩小。在这个过程中需要检测两物体之间的距离,当它们边缘距离的绝对值在一个允许的范围之内时便停止这个过程并认为此时物体的位置就是碰撞发生位置(对于不规则外形的物体可以用检测重叠函数代替检测边缘距离的过程)。当然在这个过程中如果两物体都在运动的话,两物体的穿透纠正需要同时进行。穿透纠正这个过程是快速的数值推算,是不可见的。另外说明一下,非直线非匀速运动同样适用。

 

以上方法在我的游戏中有应用,效果很满意。

(05)sbljx:-------------------------------------------------------------------------------------------------------

但是这个算法仍然有问题。

试想这样的情况,两个物体做追踪运动,A在前,B在后,一开始B的速度大于A,则他们之间的距离不断减小,但在B未追上A之前,A突然加速,且速度大于B,这是他们之间的距离就变大了,那么如何区分这不是碰撞呢?

 

再有,两个物体的运动轨迹如下图1所示,那么我肯定这两个物体的距离增量值曾经由负变为正,但是很显然,这两个物体很可能从来都没相遇过,那又怎么判断这种情况也不是碰撞呢?

 

还有一些类似的问题,不过等大家一起解决了这两个问题再说。我以为是不是可以这样,就是即使发生了一上的两种情况,依旧做穿透纠正运算,但真金不怕火炼,如果没有相遇过,那么运算结束后肯定不能得到相遇点,这样就可以判断了,truka还有好方法么?

靠,忘了传图了,等会补上


(06)sbljx:-------------------------------------------------------------------------------------------------------

图一

(07)truka:-------------------------------------------------------------------------------------------------------

第一个问题容易解决,如果由于发生突然加速或其他原因在整个穿透纠正的计算过程中两物体边缘距离的绝对值从未在一个允许的范围之内,碰到这种情况就认为碰撞没有发生,此过程结束,运动继续进行.

 

第二个问题,对不起,是我的一个笔误,现纠正一下.原来的"由正变为负"应该是"由负变为正"才对,感谢sbljx指正.

 

当然要让这个方法的使用范围更大还需要大家一起来优化它.

(08)sbljx:-------------------------------------------------------------------------------------------------------

第二个问题中,这两个物体的距离增量值肯定也有由负变为正的一刻。

另外,一般来讲,绝对值从未在一个允许的范围之内,这个范围是多少呢?与物体大小有关?

(09)truka:-------------------------------------------------------------------------------------------------------

1)许多时候确实会发生一些不必要的穿透纠正,也就是说穿透纠正的过程中得不到碰撞点的情况,如果不采取任何措施,程序一样可以正常运行,只是会增加一些不必要的运算量消耗资源。这可能是sbljx关心的问题。

如果把满足穿透纠正的条件改一下,增加一项检测就可以在很大程度上减少不必要的穿透纠正发生。这项检测就是两物体间边缘距离是否在满足发生碰撞的最大范围之内(对于两个圆形物体来说,这个范围略大于它们的半径之和,对于不规则物体还需要再扩大一点范围),如果不是则认为是一次不必要的穿透纠正。

 

2)这个范围与物体大小有关。对于不规则物体,这个范围不太好确定,此时采用重合函数检测比较可取,因为此时物体的移动可以认为是连续的(推算时的"移动速度"不大于1像素/帧)。

(10)sbljx:-------------------------------------------------------------------------------------------------------

明白,回来我总结一下,写成教程,呵呵。

(11)truka:-------------------------------------------------------------------------------------------------------

确实需要不断地完善,这种思路起源于桌球游戏中的碰撞点纠错算法。

但是桌球游戏的运动相对是比较单调的。永远是减速运动,运动路径多数是直线,全部是圆形物体。

我觉得sbljx的问题很有建设性,对完善具有普遍通用性的穿透纠正算法很有帮助:)

(12)sbljx:-------------------------------------------------------------------------------------------------------

呵呵,我算是明白了,你们敢情在底下已经研究了很多的东西,怪不得那么厉害,佩服中,希望以后多多把东西拿出来大家一起讨论啊,对于你们这样的高手来说,很可能平时的一点心得就能成为这里研究发生实质性突破的关键啊,记得常来哦。

(14)truka:-------------------------------------------------------------------------------------------------------

做了个例子。在这个实例中除了讨论过的穿透纠正以外,还有嵌入纠正的处理。

按下鼠标左键吸引红球,右键吸引白球。<shift>和<ctrl>可以辅助操作,建议操作时同时按下<shift>和<ctrl>。

http://www.mobiusclub.com/bbs/uploadImages/2002111112583833485.dir

(00)第二贴截止时间:2002-11-15 14:40:12

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

第三总贴:碰撞的解决方案有几种?

发起人:stiff

发起时间:2002-9-27 16:41:15

网站链接:http://www.mobiusclub.com/bbs/dispbbs.asp?boardID=12&ID=40

 

(01)stiff:--------------------------------------------------------------------------------------------------------

if sprite s intersects pGloveSprite then

if inside(sprite(s).loc, sprite(pGloveSprite).rect) then

if (sprite(s).locH - sprite(pGloveSprite).locH) <= pCatchDistance and

if sqrt(power(sprite(s).locH - sprite(pGloveSprite).locH,2)+?

看看老外,他用了好几个方法进行检测,但都没有sbljx来到专业和精确:)

http://www.mobiusclub.com/bbs/uploadImages/20029271641921617.zip  

(02)sbljx:-------------------------------------------------------------------------------------------------------

呵呵,要解决碰撞的问题,先要确定是在那种运动机制下。

(03)sbljx:-------------------------------------------------------------------------------------------------------

我的意思:先要确定运动机制,才能讨论碰撞数学模型。所谓运动机制,咱们现在就知道两种:

1.改变单位时间的移动距离来改变物体运动快慢,这种机制会发生“瞬间穿透”

如sprite(1).loch=sprite(1).loch+2

sprite(1).loch=sprite(1).loch+5

 

2.每次物体移动的距离永远是1、-1、0,通过改变物体位置改变频率来改变物体运动快慢。这种机制不会发生“瞬间穿透”。

如:

每1秒触发一次:sprite(1).loch=sprite(1).loch+1

每10秒触发一次:sprite(1).loch=sprite(1).loch+1

这样就产生了不同的运动速度

先确定用哪种运动机制。然后才能对症下药啊。

(04)sbljx:-------------------------------------------------------------------------------------------------------

交错没关系,不穿透就可以。而且,一个像素的交错可以忽略不计。或者这么想,把这种一个像素的交错想象成两物体碰撞后产生的挤压。呵呵。

但穿透现象就无法令人接受了,因为计算机根本就检测不到发生穿透后的两个物体曾经相遇过。

(05)alphachi:---------------------------------------------------------------------------------------------------

关键是碰撞的瞬间如何检测到物体的状态, 可必须要保证足够高的播放帧数才能够得到足够高的精确率,恶性循环呀...

(06)sbljx:-------------------------------------------------------------------------------------------------------

以下是引用alphachi在2002-10-24 15:11:16的发言:

关键是碰撞的瞬间如何检测到物体的状态, 可必须要保证足够高的播放帧数才能够得到足够高的精确率,恶性循环呀...

 

是的,要在相当高的播放速度下才行,最高的播放速度是直接在死循环中处理所有事件。

(00)第三贴截止时间:2002-10-24 15:14:55

第一部分:论坛资料整理

       stiff

 

 

 

第二部分:研究心得:

sbljx:碰撞检测原理.doc

 

 

 

第三部分:研究范例

       sbljx:

              ABSMoveMent.dir

              TowBalls.dir

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值