Nape帮我们实现了物理碰撞模拟,通过Nape我们可以实现各种游戏模型。但是就像我在
Box2D碰撞检测
里讲的一样,只是碰撞是不够的,我还喜欢碰撞后的物体可以消失、变小等等,按照游戏需求执行任何需要的动作。这就需要我们今天要讨论的话题,自定义碰撞检测处理。这篇文章比较长,深吸一口气,来吧!
跟Box2D比起来,Nape更加符合Flash开发人员的习惯,它的回调系统跟Flash的事件模型非常相似,添加事件侦听,自定义事件处理函数。而且Nape事件类型比Box2D更为强大和完善,还等什么,马上开始吧!
创建一个Nape事件侦听
虽说Nape的回调系统和Flash事件模型非常相似,但具体写起代码来还是存在不同的。
Flash中任何继承EventDispatcher类的对象都可以通过addEventListener对指定事件添加侦听,例如,要对Sprite对象的ENTER_FRAME事件添加侦听,代码应该写成: Nape中所有的事件侦听只能通过space对象来添加。另外Nape事件侦听不是通过addEventListener()这样的函数,而是通过Listener类来实现的。简单的讲,可以理解成把addEventListener()函数拆成了两步:
创建Listener对象,这个对象中包含了碰撞事件所需的所有信息,稍后会详细介绍。
将Listener对象添加到space的listeners属性中。space.listeners是一个ListenerList对象,用来保存Nape中所有的事件侦听器。
完成上面两步就实现了Nape碰撞事件侦听,下面是具体的代码: 听起来似乎是这样啊!那Nape都有哪些事件类型呢?
Nape事件类型
Nape中的事件是指对象发生碰撞或状态变更时派发的事件,用CbEvent中的常量表示,这个常量也是Listener对构造函数的第一个参数,具体有下面7种:
与Box2D仅有的BEGIN和END事件类型比起来,有没有感觉到Nape碰撞事件系统的强大?至少有那么一点点吧。别着急,继续往下看,你会发觉作者对Nape的介绍一点都没有夸大。
Nape碰撞类型
碰撞类型?不是讲过了吗?重复了吗?
No!No!上一节介绍的是Nape事件类型,是不同碰撞或状态变更时派发的事件,是事件!碰撞类型是指不同对象之间发生的碰撞。还是不明白?继续往下看。
按照刚体的特性来划分可以分为三种:1,普通的刚体,在Nape应用中最基本的模拟碰撞的刚体;2,浮力刚体,可以用来模拟水中漂浮效果的刚体;3,Sensor刚体,也就是感应刚体,这类刚体不参数碰撞模拟,但是Nape依然会对其进行碰撞检测,这和Box2D设置isSensor属性为true的刚体是一样的。
和这些不同类型的刚体相对应的,Nape提供了3中不同的碰撞类型,分别用InteractionType类的常量:COLLISION,FLUID和SENSOR表示(也是Listener构造函数的第2个参数),具体的用法分别说明如下:
Nape中每个事件侦听器只能设置一种碰撞类型,作为第2个参数,如果需要对所有的碰撞类型侦听,又觉得创建3个侦听器太麻烦,也可以用InteractionType.ANY表示。
具体的代码,我还是在介绍完事件侦听器之后再举例吧。
Nape事件侦听器
说了这么多,终于要讲到添加碰撞侦听的重点了。Listener是Nape中碰撞事件帧听的核心部分。所有的事件派发后都有Listener对象侦听,然后触发相应的事件处理函数。针对不同的事件,侦听器也不同,也就衍生出了Listener的四个子类:BodyListener、ConstraintListener、InteractionListener和PreListener。这几个侦听器的用途简单说明如下:
本节我们主要是讲碰撞检测,所以只用到InteractionListener,其他的侦听器,以后我们会慢慢学习,如果感兴趣,也可以自己尝试一下。首先看一下InteractionListener的构造函数: 总共有6个参数,看起来挺复杂,其实大部分我们都已经很熟悉了,不过还是再仔细的看一下吧:
举个简单的例子,比如现在舞台上有圆形和矩形两个形状的刚体,那么我们可以通过下面的代码创建两种不同的类型: 虽然两个对象同样没有参数,但是因为是两个不同的实例对象,所以可以表示两种不同类型的刚体。如果我们可以侦听的刚体碰撞可以分为三类,对应的在侦听器中设置options1和options2的方法分别如下:
圆形与圆形之间的碰撞: 圆形与矩形之间的碰撞: 矩形与矩形之间的碰撞: 看过代码之后是不是就明白多了。除了可以在Listener中用options1和options2参数有针对性的侦听具体的碰撞,Nape在事件处理函数的处理上也是比Box2D要强大的多。
比如上面例子中圆形与矩形之间的碰撞,在Box2D中通过b2Contact里的body1和body2获取的碰撞刚体,无法明确哪个是矩形,哪个是圆形。我们不得不对body1或body2分别进行两次判断。
在Nape的事件处理函数中,有一个InteractionCallback类型的参数,这个InteractionCallback对象有int1和int2两个属性,分别对应Listener中的options1和options2参数。在圆形和矩形之间碰撞的实例代码中,int1就是指的rectType类型的刚体,int2指的是circleType类型的刚体。具体的代码如下: 是不是很简单?但是现在又出现一个新的问题,怎么样把刚体标示成某个CbType类型呢?这个同样很简单,通过Body对象的cbTypes属性的add方法,就可以把刚体标示为相应的CbType类型,而且可以同时标记成多种类型哦!代码举例如下: 好啦,到这里Nape碰撞检测的内容就基本讲完了。好多吧,没事慢慢消化。接下来是该举出详细的例子说明一下啦。
下面的例子中有1个红色的矩形和2个蓝色的圆形,点击可以拖动刚体。当红色矩形刚体撞击蓝色圆形刚体,蓝色会变为半透明的。圆形之间的碰撞,会把蓝色改为完全不透明。动手试试看看效果吧!
完整的代码和注释如下,点击这里下载源文件。
代码中用到了我自定义的LDEasyNape类,具体请参考 这篇教程 !
跟Box2D比起来,Nape更加符合Flash开发人员的习惯,它的回调系统跟Flash的事件模型非常相似,添加事件侦听,自定义事件处理函数。而且Nape事件类型比Box2D更为强大和完善,还等什么,马上开始吧!
创建一个Nape事件侦听
虽说Nape的回调系统和Flash事件模型非常相似,但具体写起代码来还是存在不同的。
Flash中任何继承EventDispatcher类的对象都可以通过addEventListener对指定事件添加侦听,例如,要对Sprite对象的ENTER_FRAME事件添加侦听,代码应该写成: Nape中所有的事件侦听只能通过space对象来添加。另外Nape事件侦听不是通过addEventListener()这样的函数,而是通过Listener类来实现的。简单的讲,可以理解成把addEventListener()函数拆成了两步:
创建Listener对象,这个对象中包含了碰撞事件所需的所有信息,稍后会详细介绍。
将Listener对象添加到space的listeners属性中。space.listeners是一个ListenerList对象,用来保存Nape中所有的事件侦听器。
完成上面两步就实现了Nape碰撞事件侦听,下面是具体的代码: 听起来似乎是这样啊!那Nape都有哪些事件类型呢?
Nape事件类型
Nape中的事件是指对象发生碰撞或状态变更时派发的事件,用CbEvent中的常量表示,这个常量也是Listener对构造函数的第一个参数,具体有下面7种:
- BEGIN:当Nape对象之间的碰撞开始时派发CbEvent.BEGIN事件
- ONGOING:当对象之间的处在碰撞过程中时派发CbEvent.ONGOING事件。比如刚体与Sensor碰撞时,刚体与Sensor刚体之间会有重迭部份,这是会持续派发CbEvent.ONGOING事件
- END:当对象之间的碰撞结束要分离时派发CbEvent.END事件。
- PRE:是在碰撞发生之前,可以侦听这个来忽略这个碰撞。比如Nape官网中的平台示例。
- WAKE:和Box2D类似,刚体运动时,其状态会标示为WAKE,当刚体不动时,会标示为SLEEP状态,不进行模拟计算,提升效率。当刚体由SLEEP变为WAKE状态时派发这个事件。
- SLEEP:当刚体由WAKE变为SLEEP状态时派发的事件。
- BREAK:关节对象中可以设置关节的承受力,当超出这个承受力时关节可以自动断开,这时会派发CbEvent.BREAK事件。
与Box2D仅有的BEGIN和END事件类型比起来,有没有感觉到Nape碰撞事件系统的强大?至少有那么一点点吧。别着急,继续往下看,你会发觉作者对Nape的介绍一点都没有夸大。
Nape碰撞类型
碰撞类型?不是讲过了吗?重复了吗?
No!No!上一节介绍的是Nape事件类型,是不同碰撞或状态变更时派发的事件,是事件!碰撞类型是指不同对象之间发生的碰撞。还是不明白?继续往下看。
按照刚体的特性来划分可以分为三种:1,普通的刚体,在Nape应用中最基本的模拟碰撞的刚体;2,浮力刚体,可以用来模拟水中漂浮效果的刚体;3,Sensor刚体,也就是感应刚体,这类刚体不参数碰撞模拟,但是Nape依然会对其进行碰撞检测,这和Box2D设置isSensor属性为true的刚体是一样的。
和这些不同类型的刚体相对应的,Nape提供了3中不同的碰撞类型,分别用InteractionType类的常量:COLLISION,FLUID和SENSOR表示(也是Listener构造函数的第2个参数),具体的用法分别说明如下:
- InteractionType.COLLISION:普通刚体之间的碰撞
- InteractionType.FLUID:刚体与浮力刚体的碰撞
- InteractionType.SENSOR:刚体与sensor刚体的碰撞
Nape中每个事件侦听器只能设置一种碰撞类型,作为第2个参数,如果需要对所有的碰撞类型侦听,又觉得创建3个侦听器太麻烦,也可以用InteractionType.ANY表示。
具体的代码,我还是在介绍完事件侦听器之后再举例吧。
Nape事件侦听器
说了这么多,终于要讲到添加碰撞侦听的重点了。Listener是Nape中碰撞事件帧听的核心部分。所有的事件派发后都有Listener对象侦听,然后触发相应的事件处理函数。针对不同的事件,侦听器也不同,也就衍生出了Listener的四个子类:BodyListener、ConstraintListener、InteractionListener和PreListener。这几个侦听器的用途简单说明如下:
- BodyListener:用来侦听刚体在WAKE和SLEEP状态之间切换时派发的CbEvent.WAKE或CbEvent.SLEEP事件
- ConstraintListener:侦听关节(后续我们详细介绍)状态变化时派发的事件,这些事件有CbEvent.WAKE、CbEvent.SLEEP和CbEvent.BREAK
- InteractionListener:在刚体或关节发生碰撞时派发的所有事件都由InteractionListener来侦听。这些碰撞事件包括CbEvent.BEGIN、CbEvent.ONGOING和CbEvent.END
- PreListener:这个侦听器可以侦听任何碰撞的所有事件。InteractionListener同样也用来侦听碰撞事件,但是每个InteractionListener对象只能侦听其中某一个事件。PreListener可以同时侦听所有的碰撞事件,也就是说,添加了PreListener侦听后器后,碰撞在发生、进行和结束时派发的事件都会触发PreListener的事件处理函数。
本节我们主要是讲碰撞检测,所以只用到InteractionListener,其他的侦听器,以后我们会慢慢学习,如果感兴趣,也可以自己尝试一下。首先看一下InteractionListener的构造函数: 总共有6个参数,看起来挺复杂,其实大部分我们都已经很熟悉了,不过还是再仔细的看一下吧:
- event:CbEvent:要侦听的CbEvent事件类型,前面介绍过总共有BEGIN、END、ONGOING、PRE、WAKE、SLEEP和BREAK七种。
- interactionType:InteractionType:要侦听的碰撞类型,前面同样也介绍,根据碰撞的刚体不同,有COLLISION、FLUID、SENSOR和ANY四种。
- options1:CbType:侦听碰撞的两个刚体中,限定的第1刚体的类型,和下面的options2搭配使用。Nape中只有符合这两种类型的刚体发生碰撞时,才会派发相应的事件。
- options2:CbType:侦听碰撞的两个刚体中,限定的第2刚体的类型。
- handler:InteractionCallback:处理碰撞事件的函数,和Flash中addEventListener里的事件处理函数一样。
- precedence:Int = 0:当不同的事件侦听器同时侦听相同的刚体之间相同的碰撞事件时,触发侦听器的优先权。
举个简单的例子,比如现在舞台上有圆形和矩形两个形状的刚体,那么我们可以通过下面的代码创建两种不同的类型: 虽然两个对象同样没有参数,但是因为是两个不同的实例对象,所以可以表示两种不同类型的刚体。如果我们可以侦听的刚体碰撞可以分为三类,对应的在侦听器中设置options1和options2的方法分别如下:
圆形与圆形之间的碰撞: 圆形与矩形之间的碰撞: 矩形与矩形之间的碰撞: 看过代码之后是不是就明白多了。除了可以在Listener中用options1和options2参数有针对性的侦听具体的碰撞,Nape在事件处理函数的处理上也是比Box2D要强大的多。
比如上面例子中圆形与矩形之间的碰撞,在Box2D中通过b2Contact里的body1和body2获取的碰撞刚体,无法明确哪个是矩形,哪个是圆形。我们不得不对body1或body2分别进行两次判断。
在Nape的事件处理函数中,有一个InteractionCallback类型的参数,这个InteractionCallback对象有int1和int2两个属性,分别对应Listener中的options1和options2参数。在圆形和矩形之间碰撞的实例代码中,int1就是指的rectType类型的刚体,int2指的是circleType类型的刚体。具体的代码如下: 是不是很简单?但是现在又出现一个新的问题,怎么样把刚体标示成某个CbType类型呢?这个同样很简单,通过Body对象的cbTypes属性的add方法,就可以把刚体标示为相应的CbType类型,而且可以同时标记成多种类型哦!代码举例如下: 好啦,到这里Nape碰撞检测的内容就基本讲完了。好多吧,没事慢慢消化。接下来是该举出详细的例子说明一下啦。
下面的例子中有1个红色的矩形和2个蓝色的圆形,点击可以拖动刚体。当红色矩形刚体撞击蓝色圆形刚体,蓝色会变为半透明的。圆形之间的碰撞,会把蓝色改为完全不透明。动手试试看看效果吧!
完整的代码和注释如下,点击这里下载源文件。
代码中用到了我自定义的LDEasyNape类,具体请参考 这篇教程 !