P2可以实现物体碰撞模拟,同时在碰撞过程中派发一些事件实现碰撞检测,将碰撞信息及时反馈,以添加相应的特效。
P2中,当两个刚体的最小包围盒AABB发生重叠,碰撞就开始了;然后刚体的形状发生重叠,同时P2会对重叠进行修复,使刚体朝对方的反方向移动,来消除形状重叠;当形状不再有重叠时,整个碰撞过程结束。可以把碰撞过程分为4个阶段: ·postBroadphase:AABB开始发生重叠,但形状并没有发生接触 ·beginContact:刚体形状开始发生重叠,刚体继续保持原有速度移动 ·preSolve:刚体形状发生了重叠,但P2还未进行碰撞处理 ·endContact:P2已经完成了碰撞处理,并为碰撞刚体重新分配了速度,同时刚体形状分离,不再有重叠 1)碰撞事件:碰撞过程会产生4个事件,postBroadphase、preSolve、beginContact、endContact。在碰撞事件派发后,可以通过world类的on方法来监听事件,并在监听处理函数中进行对应的处理。on方法的结构为: function on(type:String, listener:functtion) 其中,type为监听事件名,为一个字符串,取值为对应的事件名称;listener为事件监听函数,当监听到碰撞事件后,会自动调用监听函数,并将碰撞事件对象作为参数传递给监听处理函数。碰撞监听函数的参数event是一个Object对象,对应碰撞事件对象,其中保存碰撞信息。 在on事件处理函数中,this指的是派发事件的对象context,也就是world对象,而不再是主类中的this。因此,需要在on函数之前,将this指针保存到一个局部变量中,然后才能在事件处理函数中通过这个局部变量访问主类中的变量和方法。 on()方法监听碰撞事件时,会将对应的碰撞事件对象作为参数传递给监听处理函数,这些碰撞事件对象为:postBroadphaseEvent、preSolveEvent、beginContactEvent、endContactEvent。 ①postBroadphaseEvent:当两个刚体的AABB发生重叠时,不断派发postBroadphase事件,并将碰撞信息保存到对应的postBroadphaseEvent对象中,该对象包含属性pairs,即保存碰撞刚体对的数组。因为尚未进行刚体形状的碰撞检测,所以此时对pairs数组中的碰撞进行删减可以取消对应碰撞刚体之间的碰撞模拟。但删除pairs后,将不再进行beginContact和endContact事件派发。 ②preSolveEvent:在刚体形状发生重叠时,P2会根据动量守恒定律,对碰撞对象的速度和角度重新计算,实现碰撞模拟,这个过程称为solve。preSolve事件在碰撞模拟过程前派发,在preSolve事件处理函数中进行一些处理可以取消或干预碰撞的模拟。 preSolveEvent对象的属性有: ·contactEquations:保存当前碰撞产生的所有contactEquation对象的数组 ·frictionEquations:保存当前碰撞产生的所有frictionEquation对象的数组 preSolve事件会随step()方法不断派发,在刚体形状之间没有重叠前,contactEquations属性中并不包括contactEquation对象,所以代码中要先进行判断:contactEquations.length>0。 ③beginContactEvent:当刚体形状发生重叠时会派发beginContact事件,并将碰撞信息保存在对应的beginContact Event对象中,其中属性有: ·shapeA:发生碰撞的形状A ·shapeB:发生碰撞的形状B ·bodyA:形状shapeA对应的刚体 ·bodyB:形状shapeB对应的刚体 ·contactEquations:保存当前碰撞产生的所有contactEquation对象的数组 ④endContactEvent:当前两个碰撞刚体的形状分离而不再重叠时会派发endContact事件,并将碰撞信息保存在对应的endContactEvent对象中,包含的属性有: ·shapeA:发生碰撞的形状A ·shapeB:发生碰撞的形状B ·bodyA:形状shapeA对应的刚体 ·bodyB:形状shapeB对应的刚体 2)碰撞信息Equation:在P2引擎中,Equation类用来保存碰撞发生时的碰撞点、碰撞向量等信息。一般用其两个子类ContactEquation和FrictionEquation来保存不同类型的信息。 ①ContactEquation:碰撞过程中,因接触而产生的碰撞信息,如碰撞点、碰撞向量、碰撞刚体等,都保存在ContactEquation对象中。在preSolve和beginContact阶段,会产生多个ContactEquation对象,并分别保存在preSolveEvent和beginContactEvent事件对象的ContactEquation属性中。 ·shapeA:发生碰撞的形状A ·shapeB:发生碰撞的形状B ·bodyA:形状shapeA对应的刚体 ·bodyB:形状shapeB对应的刚体 ·contactPointA:自bodyA的坐标起,到碰撞点的全局向量 ·contactPointB:自bodyBA的坐标起,到碰撞点的全局向量 ·enabled:是否对当前的ContactEquation对象进行碰撞模拟,默认true,如果在preSolve阶段将其设为false可以取消碰撞模拟 ·firstImpact:是否为第1次碰撞,当第1次碰撞step()完成后,firstImpact立即设为false ·normalA:垂直于刚体碰撞边的法向量,这是一个全局的单位向量 ·restitution:碰撞刚体之间的碰撞弹性系数,取值0~1。该系数只影响当前碰撞的模拟,如果对shapeA和shapeB设置contactMaterial,其restitution属性不受影响。 ②FrictionEquation:碰撞过程中,因刚体相对运动而产生的摩擦等碰撞信息,保存在FrictionEquation对象中。在碰撞的preSolve阶段会产生FrictionEquation对象,并保存在preSolveEvent事件对象的FrictionEquation属性中。FrictionEquation对象包含的属性有: ·shapeA:发生碰撞的形状A ·shapeB:发生碰撞的形状B ·bodyA:形状shapeA对应的刚体 ·bodyB:形状shapeB对应的刚体 ·frictionCoefficient:碰撞时刚体之间的碰撞系数,取值越大速度衰减越快,只影响当前碰撞模拟。如果有对shapeA和shapeB设置contactMaterial,其friction属性不受影响。 ·t:碰撞边的切线方向向量 需要注意,frictionCoefficient属性需要在world.solver.frictionIterations>0情况下才起作用,frictionIterations默认是0,需要在创建world时设置其值。