p2 若干知识

1)addBody和removeBody:
World类中的addBody()和removeBody()分别用来上P2世界添加和删除刚体。所有创建好的刚体,必须通过addBody()添加到P2世界中,才可以进行碰撞模拟: 
var body:p2.Body({mass:1, position:[1,1]}); 
this.world.addBody(body); 
当物体被子弹击中,或超出屏幕范围时,需要删除刚体,可以通过removeBody()将其从P2世界中删除,同时还可以避免不必要的计算。示例代码: 
this.world.removeBody(bodyToRemove); 
2)addShape和removeShape:
Body类中的addShape()和removeShape()分别用来向刚体中添加和删除形状。使用addShape(): 
var shape:p2.Rectangle=new p2.Rectangle(100,50); 
var body:p2.Body=new p2.Body({mass:1, position:[1,1]); 
body.addShape(shape); 
其实,addShape()中还有其他参数,构造函数为: 
function addShape(shape:p2.Shape, offset:number, angle:number) 
其中参数除了被添加的形状shape,还有两个参数,offset为形状相对于坐标原点的偏移量,angle为形状的角度,这两个参数都是相对于刚体本地坐标系而言,即会随刚体的变化而变化。 
可以通过removeShape()方法将指定的形状从刚体中删除。 
形状的添加或删除,并不会改变刚体的重心坐标,因此可用来模拟不倒翁效果。 
3)adjustCenterOfMass:
调整重心位置。刚体中增加或移去形状后,重心并不会自动改变,可以使用adjustCenterOf Mass()方法,使刚体重心重新回到中心位置。这个方法不带任何参数,也没有返回值。 
4)applyForce:
作用力可以让刚体状态改变,通过applyForce()方法,可以在指定点worldPoint对刚体施加一个作用力,形成一个加速度或扭力,改变刚体的线速度或角速度。构造函数为: 
function applyForce(force:number[], worldPoint:number[]) 
其中,force是要施加的作用力,这是一个二维向量; worldPoint是一个全局坐标点,表示force在刚体上的作用点,当此点不在刚体重心位置时,刚体角度也会发生变换。 
5)applyImpulse:
如果要瞬间改变刚体的状态,如子弹弹出膛效果,需要使用applyImpulse()对其施加冲量,使刚体的速度和角速度瞬间发生变化。 
function applyImpulse(impulse:number[], relativePoint:number[]) 
其中,impulse为要施加的冲量,冲量有大小和方向,是一个二维向量; relativePoint是一个本地坐标点,表示冲量的作用点,当作用点不在刚体中心时刚体角度也会发生变化。 
6)sleep和wakeup: 
Body的sleep()方法强制使刚体进入睡眠状态,此时除了sleepState处于Body.SLEEPING状态外,刚体的速度、角速度、受到的作用力、扭力等都会全部清零。 
function sleep(){ 
this.sleepState=Body.SLEEPING; 
this.angularVelocity=0; 
this.angularForce=0; 
vec2.set(this.velocity, 0, 0); 
vec2.set(this.force, 0, 0); 
this.emit(Body.sleepEvent); 
}; 
刚体进入睡眠状态后,通过调用wakeup()方法,可以将刚体强制唤醒,但仅仅是将sleepState设置为Body.AWAKE,睡眠状态前的速度、角度等属性不会恢复: 
function wakeup(){ 
var s=this.sleepState; 
this.sleepState=Body.AWAKE; 
this.idleTime=0; 
if(s!==Body.AWAKE){ 
this.emit(Body.wakeUpEvent); 


可以使用sleep()方法实现类似冰冻效果。 
7)emit、on、off、has:
P2物理引擎中,通过EventEmitter类实现事件派发机制,并通过emit()、on()、off()、has()方法分别实现派发、监听、取消监听,以及检测是否包含指定事件功能。 
⑴emit():派发自定义事件,事件类型使用任意字符串表示: 
function emit(event:Object) 
其中,event为要派发的自定义事件,是一个Object类型,用于包含任何需要通过事件传递的信息。在自定义事件时,event对象至少要包含名为type的字符串属性值,表示事件名称: 
body.emit({type:"movingUp"}); 
⑵on():监听对应的自定义函数 
监听到事件对象,将作为参数传递给事件监听函数,示例代码为: 
var onMyEvent=function(event){ 
console.log("onMyEvent is fired, because I am moving up."); 
}; 
body.on("movingUp", onMyEvent); 
on()方法的参数是字符串类型的事件名称,并在事件触发时调用一个处理函数。 
⑶off():取消监听 
当不需要监听某个事件时,将事件名称和事件监听函数作为参数传递给off()方法,就可以取消监听。示例代码: 
body.off("movingUp", onMyEvent); 
⑷has():检查对象是否包含指定的事件监听 
Body类因为继承了EventEmitter类,所以也拥有上面4个方法。通过这些方法,可以方便地对刚体的某些特定状态进行监听,如睡眠或苏醒。Body类内置了睡眠和苏醒事件: 
·sleepEvent:当刚体进入睡眠状态时派发该事件,对应事件名称为sleep,监听使用body. on("sleep", onMyEvent); 
·wakeupEvent:当刚体从睡眠状态恢复至苏醒状态时,派发wakeupEvent事件,事件名为wake,监听使用body.on("wake", onMyEvent); 
·sleepyEvent:当刚体进入瞌睡状态时,派发该事件。Body有一个sleepSpeedLimit属性,当刚体的速度小于sleepSpeedLimit值时就进入瞌睡状态;如果该状态持续时间超过body. sleepTimeLimit,则刚体进入睡眠状态。sleepyEvent对应的事件名为sleepy,监听使用body. on("sleepy", onMyEvent); 
除了上述内置事件,还可以自定义事件,比如在step()方法中持续判断body.velocity.y是否小于0,来检测刚体向上运动,派发自定义moveUp事件: 
public loop():void{ 
this.world.step(60/1000); 
this.debugDraw.drawDebug(); 
if(this.bodyRef.velocity[1]<0){ 
this.bodyRef.emit({type:"myEvent"}); 


8)fromPolygon:
fromPolygon用于将多边形分解成一个个小的形状,然后组合成完整的多边形。 
function fromPolygon(path:number[][], [options]):boolean 
其中,path保存了多边形顶点数组,options为可选属性,定义多边形分解的相关设置。 
options包括的选项有: 
·optimalDecomp=false:是否进行最佳分解,默认false,开启该选项会降低计算速度 
·skipSimpleCheck=false:是否进行顶点交叉的判断,如果确定不存在交叉点可设为true 
·removeCollinearPoints=false:是否剔除共线顶点,false表示不剔除 
如果多边形创建成功返回true,否则返回false。导致创建失败有几种原因,比如创建的形状中有空洞、顶点和边之间有交叉。可以编程将鼠标光标移动的轨迹中的点作为多边形的顶点。也就是随手创建刚体。 
9)hitTest:
用于实现指定坐标点与刚体的碰撞检测,并将检测到的碰撞刚体保存到数组中返回。 
function hitTest(worldPoint:number[][], bodies:Body[], precision:number):Body[] 
其中,worldPoint为要检测的坐标点,是一个全局坐标点;bodies为要检测的刚体清单,可以将需要检测的刚体保存到bodies数组中,实现有针对性的碰撞检测。如果要对所有的刚体进行检测,可以直接设置该参数为world.bodies,即:hitTest(worldPoint, world.bodies); 
参数precision为检测精度,默认为0,取值越大检测精度越高,计算效率会降低,一般使用默认值,对尺寸极小的物体,如particle和line需要设置。方法的返回值为保存了与worldPoint发生碰撞所有刚体的数组。 
hitTest()最常用用于检测鼠标光标点击、拖曳效果。P2中没有鼠标光标事件,可以通过hitTest()来判断鼠标点是否与刚体发生碰撞,然后调整刚体的position至鼠标位置,实现对刚体的拖曳。为了便于拖曳,在鼠标点击时通过sleep()方法将刚体设为睡眠状态,使其不受重力影响,可以精确地随鼠标光标移动,当拖曳完成弹起时再使用wakeUp()方法重新唤醒刚体,恢复重力的作用。 
10)getAABB:
获取刚体的最小包围盒AABB(Axis Align Bounding Box),最小包围盒AABB是指包围形状的最小矩形框。可以通过设置刚体的isDrawAABB=true,以显示出刚体的AABB。AABB对象将矩形对象的左下角和右下角坐标分别保存在属性lowerBound和upperBound中。 
11)getArea: 
获取刚体的当前所有形状的面积总和。 
12)setDensity:
设置刚体的密度,结构为: 
function setDensity(density:number) 
其中,density为要设置的密度,是取值大于0的数值。 
实际上,P2中的刚体并没有密度属性,当调用setDensity()方法后,Body会根据刚体当前的面积area计算出对应的质量并保存在mass属性中。 
13)overlaps:
检测当前刚体与指定刚体是否有重叠,并返回检测结果,结构为: 
function overlaps(body:Body):boolean 
其中,body为要检测的目标刚体。如果刚体之间有重叠则返回true,否则返回false。 
目标刚体与被检测刚体需添加到world中,才能确保overlaps()的正常运行。通常并不需要使用overlaps()进行重叠检测,因为P2在实施碰撞检测和模拟时已经完成了这些内容,只有当刚体不进行碰撞模拟时才需要使用overlaps()。比如在界面中放置一个物体,当此位置已经存在物体时不能放置。 
14)toWorldFrame和toLocalFrame:
toWorldFrame()是将刚体本地坐标系统中的坐标点转换成全局坐标点,toLocalFrame()是将全局坐标点转换成刚体本地坐标系统中的坐标点。通过这两个方法,可以实现本地坐标和全局坐标之间的转换。 
function toWorldFrame(out:number[], localPoint:number[]):void 
function toLocalFrame(out:number[],worldPoint:number[]):void 
其中,out为转换后的本地坐标或全局坐标,将保存在该属性对应的变量中; localPoint为要转换的本地坐标;worldPoint为要转换的全局坐标。 
15)raycast:
射线投射技术用于实现线段与形状的碰撞检测,通常用来模拟人物的视野、距离探测等。实现射线投射,要先从起点from到终点to构建一条射线ray,然后检测与该线段发生碰撞的刚体,并保存在一个RaycastResult对象中。raycast结构为: 
function raycast(result:RaycastResult, ray:Ray) 
其中,result是保存了碰撞刚体、碰撞点、碰撞距离等信息的一个RaycastResult对象;ray是用于检测的射线,是一个Ray类,包含起点from、终点to等属性。使用射线投射,需要用到Ray类和RaycastResult类。 
①Ray类:
Ray类的构造函数为: 
function Ray([options]) 
其中,options参数是一个Object对象,初始化Ray对象时,可以保持options缺省,然后再通过Ray属性进行设置。Options对象中包含一些参数: 
·from:number[]:线段的起点,一个二维向量 
·to:number[]:线段的终点,一个二维向量 
·mode:number:射线的碰撞检测模式,取值为3个常量,分别为Ray.ALL、Ray.CLOSEST、Ray.ANY。Ray.ALL模式下,raycast()函数会检测所有与射线ray发生碰撞的刚体;Ray.CLOSEST模式下,返回检测到的碰撞刚体中距离起点from最近的刚体;Ray.ANY模式下,当ray检测到第1个碰撞刚体时会立刻停止检测并返回该刚体,这时的第1个刚体与创建时的顺序有关。 
·callback:Function:回调函数,当raycast()检测到碰撞刚体后会立即调用回调函数,该属性只适用于rayCastAll() 
·collisionMask:number:与collisionGroup配合使用,对检测刚体进行筛选 
·collisionGroup:number:与collisionMask配合使用,对检测刚体进行筛选,只有满足条件的刚体才参与碰撞检测,检测条件为: 
(this.collisionGroup&body.collisionMask)&&(body.collisionGroup&this.collisionMask)==true 
·skipBackface:是否忽略射线ray反方向与刚体的碰撞点,值为false时只检测正方向 
·checkCollisionResponse:配合Body中的collisionResponse属性,如果刚体的属性collisionResponse和checkCollisionResponse同时为true,则不对该刚体进行检测。 
·direction:射线方向,可以缺省,取决于from和to属性 
·length:射线从起点from到终点to的间距 
②RaycastResult类:
RaycastResult类用于保存射线与刚体的碰撞信息,包括几个属性: 
·body:当前碰撞检测中,与射线ray发生碰撞的刚体 
·shape:当前碰撞刚体中,与射线ray发生重叠的形状 
·fraction:射线起点from到碰撞点之间的距离distance与射线长度length的比例 
·normal:垂直于射线碰撞边的法向量,只读属性,默认-1 
RaycastResult类还有一些方法: 
·hasHit():是否检测到与射线ray发生碰撞的刚体,当检测到时返回true 
·getHitDistance():当检测到与射线发生碰撞的刚体时,碰撞点与射线起点from间的距离 
function getHitDistance(ray:Ray):number 
·getHitPoint():获取碰撞点位置,返回结果是一个全局坐标点 
此方法的结构为function getHitPoint(out:number[], ray:Ray):void 
其中,out为用于保存碰撞点坐标的二维向量,ray为当前进行碰撞检测的射线。 
·stop():用于立即停止碰撞检测 
因为raycast()方法中的RaycastResult会重复使用,所以回调函数中获取到的是最后一次碰撞检测信息。

猜你喜欢

转载自www.cnblogs.com/honghong87/p/9891029.html
p2