PreListener实现单边碰撞

作者: ladeng6666 分类: Nape 发布时间: 2014-10-27 14:07 阅读: 3,740

在《Nape刚体碰撞检测》一节中,我们认识了Nape中的4个侦听器,这一节我们来仔细研究一下PreListener碰前侦听器。

PreListener和Box2D中b2ContactListener的PreSolve()函数。当刚体之间发生碰撞时,Nape会进行相应的计算,来模拟物理碰撞。PreListener侦听的事件在这个模拟计算之前派发,你可以这么理解,想象一下两辆汽车相撞的情节,这时电影里给了一个慢放镜头,在碰撞的瞬间,两辆汽车刚刚发生接触,这时候一个神仙出现了,把两辆汽车的挪到了不同的车道,然后镜头恢复正常播放速度,两辆汽车相安无事的继续前行。

PreListener用法

PreListener就像是一个神仙,可以在物理碰撞计算之前,对碰撞进行干预,来忽略当前碰撞。首先我们来看一下PreListener的构造函数:

PreListener的参数与InteractionListener基本一致,具体说明如下:

  • interactionType:InteractionType:要侦听的碰撞行为类型。根据刚体类型的不同,刚体之家的碰撞也被分成了4类。有InteractionType的4个常量表示:
    • COLLISION:正常刚体之间的碰撞。
    • FLUID:刚体与模拟流体浮力的刚体发生的碰撞。
    • SENSOR:刚体与Sensor感应区域刚体的碰撞。
    • ANY:包含以上3中类型的任何碰撞类型。
  • options1:OptionType:Nape可以通过OptionType类对碰撞侦听的两个碰撞对象类型进行描述,只有符合该类型的对象发生了碰撞,才会被侦听都,这样可以更准确的侦听碰撞事件。OptionType描述碰撞对象类型的方法有两种,一个是直接通过CbType类的常量来设定,这些常量包括
    • ANY_BODY:每个刚体默认的类型描述
    • ANY_COMPOUND:每个刚体组合默认的类型描述
    • ANY_CONSTRAINT:每个关节默认的类型描述
    • ANY_SHAPE:每个形状默认的类型描述

除此之外,我们可以新建一个CbType对象,并通过body.cbTypes.add()将其,添加到刚体的描述中。例如下面的代码:

  • options1是对第一个碰撞对象类型的描述,和下面的options2搭配使用。Nape中只有符合这两种类型的对象发生碰撞时,才会派发相应的事件。
  • options2: OptionType:侦听碰撞的两个刚体中,第2碰撞对象类型描述。
  • handler:InteractionCallback:处理碰撞事件的函数,和Flash中addEventListener里的事件处理函数一样。
  • precedence:Int = 0:当不同的事件侦听器同时侦听相同的刚体之间相同的碰撞事件时,触发侦听器的优先权。
  • pure:Boolean:是否允许刚体在碰撞过程中睡眠。只有在handler函数返回PreFlag.IGNORE_ONCE或PreFlag.ACCEPT_ONCE时起作用。主要用来节省资源的,对PreListener的实际应用意义不是很大。

回调函数返回值

PreListener对碰撞的干预取决于handler函数中返回值。如果handler函数返回值为void,则PreListener对碰撞不产生干预。另外,PreListener如果返回PreFlag中的4个常量,则会相应的影响碰撞模拟:

  • PreFlag.ACCEPT:视此次碰撞为有效碰撞,并进行正常的物理碰撞模拟,并停止派发PreListener事件,直至两个刚体分离后再次碰撞。
  • PreFlag.IGNORE:忽略此次碰撞,不进行物理碰撞模拟,并停止派发PreListener事件,直至两个刚体分离后再次碰撞。
  • PreFlag.ACCEPT_ONCE:视此次碰撞为有效碰撞,并进行正常的物理碰撞模拟,但PreListener事件会继续派发,下一次返回值,按handler函数中的逻辑处理返回。
  • PreFlag.IGNORE_ONCE:忽略此次碰撞,不进行物理碰撞模拟,但PreListener事件会继续派发,下一次返回值,按handler函数中的逻辑处理返回。

通常模拟单边效果时,使用PreFlag.ACCEPT和PreFlag.IGNORE即可。

 PreCallback

另外需要注意的是是handler函数中的PreCallback参数,它和InteractoinCallback一样,都包含了碰撞的一些信息。我们再来一起回顾一下:

  • int1:Interactor:碰撞刚体中,符合PreListener中的第1个碰撞对象类型描述的刚体。
  • int2:Interactor:碰撞刚体中,符合PreListener中的第2个碰撞对象类型描述的刚体。
  • arbiters:保存了arbiter对象的碰撞信息列表。Nape中的arbiter类似于Box2D中的b2Contact类型,具体请参考《什么是Arbiter》。

除了这些基本的信息,PreCallback还有一个特有的属性swapped。

  • swapped:Boolean:表示arbiter中属性与int1和int2的所属关系,以及碰撞法向量normal指向。具体如下:
    • swapped = true:abiter.shape1属于int2,abiter.shape2属于int1。normal由int2指向int1。
    • swapped = false:abiter.shape1属于int1,abiter.shape2属于int2。normal由int1指向int2。

在模拟单边碰撞效果时,我们的判定方法是,如果刚体body从平台plat的上方发生碰撞,则进行正常的碰撞模拟,不允许刚体穿透plat。如果刚体body从平台plat的下方发生碰撞,则忽略此次碰撞,使刚体可以穿透plat。具体如下图所示:

PreListenerOneWayWall

图中红色箭头表示碰撞法向量normal,当箭头方向向上时,normal.y<0,结合swapped的不同取值,我们得到了上面的碰撞和忽略的判定条件,用代码表示如下:

下面的示例中,中间的平台是一个单边平台,舞台中的刚体从上方落下时,都被掉落在了平台上,试着用鼠标拖动刚体。从平台的底部碰撞,此时刚体可以畅通无阻的穿过平台。点击查看动态效果。

oneway

对应的完整源代码如下:

代码非常的简单,重点是onPre()返回值的逻辑判断,这一点前面已经详细做了介绍,这里就不再赘述了。点击下载原文件

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

2条评论
  • michael

    2014 年 10 月 30 日 下午 9:59

    勤快的拉登,这么快就写了单边碰撞教程了

    1. ladeng6666

      2014 年 10 月 31 日 下午 1:37

      不快,只要是被问到的问题,我都会尽量写一篇教程来讲解。谢谢你的关注!

发表评论

电子邮件地址不会被公开。 必填项已用*标注