前端的同学都用什么物理引擎开发项目呢?我给大家推荐一款小众引擎——P2。易上手、结构轻是我选择P2的原因。尤其是Egret官方嵌入了P2,让我在使用Egret的时候效率倍增!


stefan

p2.js是stefan——一个瑞士的杀马特开发出来的,然后由拉登大叔集成到Egret中。拉登大叔的原话是:“在JavaScript物理引擎中,P2的执行效率要比Box2D等引擎要高。”。

一句话概括P2是什么: 回答:基于Javascript编写、HTML5、2D、物理引擎。

流程:世界->形状->刚体->渲染贴图->更新

  1. 世界:P2的入口。

    //创建世界
    private createWorld(): void {
        var wrd:p2.World = new p2.World();
        wrd.gravity = [0,-10];//重力
        this.world = wrd;
    }
    
  2. 形状:做碰撞检测的外形。请跳到页尾查看属性。

    //创建矩形
    var boxShape: p2.Box = new p2.Box({ width: shapeWidth / factor,height: shapeWidth / factor });//传入矩形宽高 
    
  3. 刚体:碰撞对象的原型。shape必须添加在body上,才能物理模拟。

    //创建刚体:
    private createBody(): void {        
        var boxBody: p2.Body = new p2.Body({ mass: bodyMass,position: [x ,y ] });//传入刚体质量和坐标
        boxBody.addShape(boxShape);
        boxBody.velocity = [velocityX,velocityY];//初始化刚体速度
        this.world.addBody(boxBody);
    }
    
  4. 渲染:p2本身不具备渲染功能,必须借助如Canvas、Cocos2dx、Egret等渲染引擎,通过绘制或贴图来渲染物理模拟结果。

    //使用P2DebugDraw调试视图
    private createDebug(): void {
        var sprite: egret.Sprite = new egret.Sprite();
        this.addChild(sprite);
        this.debugDraw = new p2DebugDraw(this.world,sprite);
    }
    
  5. 在帧频事件loop()中更新p2世界。

    private loop(): void {
        this.world.step(60 / 1000);//更新频率
    }
    

进阶篇,在虚拟世界里脑洞大开:

碰撞才有火花,当两个刚体碰撞在一起时,会有什么化学反应发生?P2里有很多类,模拟不同的物理活动。具体方法请跳到页尾,点开传送门。

  • LockConstraint 锁定约束

lock

作用:两物体叠加锁定。
用途:玩过愤怒的小鸟吧,鼠标拉紧小鸟,再放手就发射成功了。这里鼠标跟小鸟的锁定就可以用LockConstraint解决。
  • DistanceConstraint 距离约束

distance

作用:物体间的引力和互斥。
用途:神奇的引力看不见摸不到,可以模拟磁铁的强大功能;更完美的是玻璃珠串成的门帘,一根一根的晃动特效。
  • RevoluteConstraint 旋转约束

revolute

作用:物体可以绕着所设置的锚点作旋转运动。
用途:公主的旋转木马不行,但是旋转风车的功能绝对能实现。
  • PrismaticConstraint 活塞约束或者移动约束

prismatic

作用:物体只能在单一方向作运动。
用途:复古的时钟钟摆,或者不倒翁。
  • LinearSpring 线性弹簧

linear

作用:物体之间弹性规律运动。
用途:软绵绵的弹簧床。

说一说我遇到的坑:

  1. 不同的坐标系问题?

    P2原点是屏幕左下角:向右为X正,向上为Y正。重力默认值[0,-9.78],即地心引力向下。
    在Egret的舞台中,原点是屏幕左上角。p2DebugDraw是基于Egret写出来的,却没有根据Egret的习惯把坐标调整到左上角。
    我直接说结论吧:蒙圈的我在Egret中用p2DebugDraw调试,发现重力向上,所有东西都惊悚的飘起来。
    
  2. 当你射箭到箭靶上的时候,我想要的效果是箭头刚刚好粘在上面而不是全都扎进去!

    产品妹子的要求是丝毫不差,我自坦然应对。
    碰撞检测的精度是引擎写死的,刚体的大小也是调节好的,我只能去改变贴图的大小尺寸啦。Egret的锚点用的是绝对坐标,比较坑,需要手动调节贴图的锚点和缩放,剩下的只是体力活的问题。
    
  3. 还是射箭的问题

    如果不想干体力活,那就去挑战极限吧——DIY碰撞检测。
    P2的碰撞检测用的是AABB包围盒,或者说大部分的引擎用的都是这种方法。
    AABB是离散碰撞检测,优点是:方法简单,速度快;缺点是:子弹穿透到盾牌里,才能检测出来。如果子弹速度无敌快,说不定子弹已经穿透盾牌飞走了。
    连续碰撞检测法可以完美解决这个问题。连续的优点是:任意两个时刻,都可以返回第一碰撞点的位置和法线;缺点是:手机会卡死,开销太大!
    一句话概括:AABB包围盒仅适用于精度不高的游戏中。如果需求精确的子弹穿透问题,这种离散碰撞检测算法将不再适用。
    
  4. 中文资料太少!

    如果无法翻墙,想查阅中文资料简直太难了!方法名需要猜,类名需要猜,版本控制好乱,想找几个例子更是难上加难。
    这才是P2最大的坑!
    

我手头的P2资料:

- Egret版本P2

- 拉登大叔的传送门

- p2物理引擎github首页

- P2中文维基

- p2物理引擎api文档

常用属性:

  • angle :角度。
  • angularVelocity :角速度。
  • position :坐标。
  • damping :速度阻尼。刚体在线性速度方向上受到的阻力。
  • force :作用力。刚体在线性速度方向上收到的扭力。
  • velocity :速度。
  • type :刚体类型。Dynamic、Kinematic或Static
  • mass :刚体质量。

常用形状:

shape

  • Capsule:胶囊形状。
  • Circle:标准圆型。
  • HeightFeild:地面形状。这种形状由一组y坐标组成,用来模拟高低不平的地面,如Tiny wing中的地面。
  • Line:线段形状,用来创建高度为1个像素,长度为length的线段。
  • Particle:粒子形状。粒子形状的尺寸均为零,没有质量和惯性。
  • Plane:平面形状。
  • Rectangle:矩形。
  • convex:自定义的形状。


blog comments powered by Disqus

Published

12 May 2016

Tags