钢体可以控制沿x方向移动,沿y方向移动, 不旋转等. fixedX, fixedY, fixedRotaion
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会重复使用,所以回调函数中获取到的是最后一次碰撞检测信息。