在白鹭中使用P2物理引擎

一、引入P2引擎库

1、下载地址:

    ① github

    ② gitee

2、将physics模块放到项目根目录的同级目录

3、修改egretProperties.json → modules字段添加

{

    "name": "physics",

    "path":"../physics"

}

4、编译引擎

    egret build


二、使用P2

1、world世界

物理引擎入口,所有的物理对象都是必须通过addBody(),添加到P2的world世界中,才会进行物理模拟

//创建Word世界
private world:p2.World;
private CreateWorld(){
    this.world = new p2.World();
    //设置world为睡眠状态
    this.world.sleepMode = p2.World.BODY_SLEEPING;
    this.world.gravity = [0,1]
}

gravity是一个Vector2向量对象,表示world世界中重力加速度,默认为垂直向上的向量[0,-9.81]


将gravity设置为[0,0]可以取消重力;gravity的x分量也是有意义的,将其设置为一个非0数值后,重力就会朝向量[x,y]方向


2、shape形状

//创建一个shape形状
let planeShape:p2.Plane = new p2.Plane();


3、body刚体

//创建body刚体
this.planeBody = new p2.Body({
    //刚体类型
    type:p2.Body.STATIC,
    //刚体的位置
    position:[0,this.stage.stageHeight]
});
this.planeBody.angle = Math.PI;
this.planeBody.displays = [];
this.planeBody.addShape(planeShape);
this.world.addBody(this.planeBody);

注意坐标方向:


4、渲染Egret

实时调用step()函数,更新物理模拟计算,P2本身不具有渲染功能,需要借助渲染引擎


function step(dt:number, timeSinceLastCalled?:number=0,maxSubSteps?:number=10) 

其中,参数dt是step方法执行的时间间隔,单位秒,通常取值为游戏帧频的倒数; 当游戏帧频降低时计算两帧之间的时间差作为timeSinceLastCalled参数值,此时P2会在一次step()中进行count= timeSinceLastCalled/dt次计算,以保证物理模拟的真实性,默认值为0;参数maxSubSteps是单次step()进行物理模拟计算的最大次数,当timeSinceLastCalled不等于0时,单次step()中进行计算的次数count最大为maxSubSteps,默认值为10。

//帧事件,步函数
private update() {
    this.world.step(2.5);
    var l = this.world.bodies.length;
    for (var i:number = 0; i < l; i++) {
        var boxBody:p2.Body = this.world.bodies[i];
        var box:egret.DisplayObject = boxBody.displays[0];
        if (box) {
            //将刚体的坐标和角度赋值给显示对象
            box.x = boxBody.position[0];
            box.y = boxBody.position[1];
            box.rotation = boxBody.angle * 180 / Math.PI;
            //如果刚体当前状态为睡眠状态,将图片alpha设为0.5,否则为1
            if (boxBody.sleepState == p2.Body.SLEEPING) {
                box.alpha = 0.5;
            }
            else {
                box.alpha = 1;
            }
        }
    }
}

world中所有的刚体都保存在属性bodies数组中,通过数组的foreach()方法,可以遍历其中的每一个body,然后拿到body的显示对象,再将刚体的坐标和角度属性赋值给显示对象,实时更新即可。


三、性能优化小技巧

1、可以设置刚体一定时间后自动进入睡眠状态以提高性能:

    world.sleepMode = p2.World.BODY_SLEEPING;



参考资料:

https://bbs.egret.com/forum.php?mod=viewthread&tid=6950

https://my.oschina.net/u/3695009/blog/2051564

https://blog.csdn.net/weixin_42622324/article/details/85710545

http://developer.egret.com/cn/github/egret-docs/extension/p2/p2/index.html