cocos2d - JS 物理引擎 - chipmunk

物理引擎 - chipmunk :

生成物理世界 :

第一步 :

新建项目打开 project.json 将chipmunk模块导入 .

    "modules" : ["cocos2d", "chipmunk"],

这里写图片描述

第二步 :

在 app.js 的 ctor 函数中里添加3个函数

    ctor:function () {
        this._super();

        //初始化物理世界
        this.initPhysics();

        //开启计时器
        this.scheduleUpdate();

        //显示碰撞框体
        this.showDebug();
    },

初始化物理世界 :

initPhysics: function(){
    var width = cc.winSize.width;
    var height = cc.winSize.height;

    this.space = new cp.Space();
    this.space.gravity = cp.v(0, -200);     //设置重力  重力向下为 200

    var staticBody = this.space.staticBody;


    var walls = [
        new cp.SegmentShape(staticBody, cp.v(0, 0), cp.v(width, 0), 0),    //最后一个参数是墙的厚度 , 很重要 , 没有厚度的墙体容易被穿透.
        new cp.SegmentShape(staticBody, cp.v(0, height), cp.v(width, height), 0),
        new cp.SegmentShape(staticBody, cp.v(0, 0), cp.v(0, height), 0),
        new cp.SegmentShape(staticBody, cp.v(width, 0), cp.v(width, height), 0)
    ];

    for (var i = 0; i < walls.length; i++)
    {
        var shape = walls[i];
        shape.setElasticity(1);     //设置弹性系数
        shape.setFriction(1);       //设置摩擦力
        this.space.addStaticShape(shape);
    }
},

update计时器 :

update: function (dt) {
    var timeStep = 0.03;
    this.space.step(timeStep);    //timeStep 控制物理世界的时间流速
}

显示物理框体 :

 showDebug: function () {
        this._debugNode = new cc.PhysicsDebugNode(this.space);
        this._debugNode.visible = true;     // 为true 时, 显示物理框体
        this.addChild(this._debugNode);
    },

第三步 :

onEnter中添加点击事件 , onExit中移除 :

onEnter: function () {
    this._super();
    cc.eventManager.addListener({event: cc.EventListener.TOUCH_ONE_BY_ONE,
        onTouchBegan: this.TouchBegan.bind(this)
    }, this);
},

onExit: function () {
    this._super();
    cc.eventManager.removeListener(cc.EventListener.TOUCH_ONE_BY_ONE);
},

点击生成物理精灵 :

    TouchBegan: function (touch, event) {
        cc.log("TouchBegan");
        var p = touch.getLocation();

        var body = new cp.Body(1, cp.momentForBox(1, 50, 50));    //其中参数 1 是质量(mass) |  50是框体的 宽和高
        body.setPos(p);
        this.space.addBody(body);

        var shape = new cp.BoxShape(body, 50, 50);
        shape.setElasticity(0.5);             //设置弹性系数
        shape.setFriction(0.5);               //设置摩擦力
        this.space.addShape(shape);

        //创建物理精灵
        var sprite = new cc.PhysicsSprite("res/box.png");
        sprite.setBody(body);
        sprite.setPosition(cc.p(p.x, p.y));
        this.addChild(sprite);

        return true;
    },

这样就可以生成一个简单的物理空间了.
这里写图片描述


物理引擎常用API :

设置冲量 :

  • 只能对 Body 设置, 提供一个向上为1000的冲量 , 冲量相当于瞬间的力 , 通常做跳跃时使用.
body.applyImpulse(cp.v(0,1000),cp.v(0,0))

设置力 :

  • 只能对 Body 设置, 提供一个向上为1000的力 , 和冲量不同 , 力会一直存在.
body.applyForce(cp.v(0,1000),cp.v(0,0))

设置碰撞类型 :

  • 只能对 Shape 设置 , 设置了类型才可以做碰撞检测
shape.setCollisionType(1001);   

设置分组、层 :

  • 只能对 Shape 设置 , 设置了分组 , 同组之间相互没有碰撞 .
    注意 : 同层之间才会发生碰撞 , 不同组之间会发生碰撞 .
shape.group = 5;
shape.layers= 5;

获取碰撞类型 :

  • 没有get函数 直接获取属性
var type = shape.collision_type;

给两个特定碰撞类型添加碰撞事件 :

  • 第1 、第2 参数是需要检测碰撞的2个碰撞类型
  • 后4个参数 是回调函数 , 分别是 :
    刚接触时(Begin) | 接触的每次step(Pre) | 接触并碰撞相应已经处理(Post) | 分离(Separate)
this.space.addCollisionHandler(1001, 1002, Begin, Pre, Post, Separate);

Begin: function(araiber, space)
{
    cc.log("CollisionBegin")
}

//...

特别注意 :

1. 碰撞检测的回调函数参数 araiber , 它可以获取碰撞的两个 shape 和 body, 但是无法确定A 和 B 分别是哪个对象 , 需要自己判断 .

2. 在碰撞移除处理时 , 需要调用指定函数addPostStepCallback 在下一帧进行处理 , 处理方式是 移除body , shape , 物理精灵自身.

space.removeBody(body);
space.removeShape(shape);
sp.removeFromParent();

3. 移除处理的时候 容易出现A物体 碰撞 两个B物体 , A物体调用两次移除 , 第二次移除的时候会报错 , 所以我的处理是用try - catch方法 .

4. 碰撞组 和 层的关系 , 同层之间才会发生碰撞 , 不同层没有碰撞 , 优先级高于组 , 不同组之间会发生碰撞 .

5. walls数组成员的最后一个参数是墙的厚度 , 很重要 , 没有厚度的墙体容易被穿透.(强够厚,就不怕穿透)

这里写图片描述

完整碰撞处理代码 :

Begin: function(araiber, space)
{
    var shapeA = araiber.getA();
    var shapeB = araiber.getB();

    var bodyA = araiber.body_a;
    var bodyB = araiber.body_b;

    var bullet_shape;
    var enemy_shape;

    // 假设1001是子弹 1002是敌人
    // 判断shapeA的碰撞类型如果是1001 shapeA就是子弹 shapeB就是敌人

    if(shapeA.collision_type == 1001)
    {
        bullet_shape = shapeA;
        enemy_shape = shapeB;
    }
    else
    {
        bullet_shape = shapeB;
        enemy_shape = shapeA;
    }

    var bullet_body;
    var enemy_body;

    //body的_type属性不是自带的, 在创建body的时候添加上去的.
    if(bodyA._type == 1001)
    {
        bullet_body = bodyA
        enemy_body = bodyB
    }
    else
    {
        bullet_body = bodyB
        enemy_body = bodyA
    }


    // 移除处理需要调用特定函数 addPostStepCallback 意为在下一帧处理 .

    space.addPostStepCallback(
        function(){
            try
            {
                space.removeBody(bullet_body);
                space.removeShape(bullet_shape);
            }
            catch (error)
            {
                cc.log("已经被移除了")
            }

            for(var i = 0; i < gameLayer.bullet.length; i++)
            {
                if(gameLayer.bullet[i].getBody() == bullet_body)
                {
                    cc.log("找到子弹 消除")
                    gameLayer.bullet[i].removeFromParent();
                    gameLayer.bullet.splice(i,1);
                }
            }


            for(var i = 0; i < gameLayer.enemy.length; i++)
            {
                if(gameLayer.enemy[i].getBody() == enemy_body)
                {
                    cc.log("找到敌人 - 掉血")
                    gameLayer.enemy[i].hp--
                    cc.log(gameLayer.enemy[i].hp)
                    if(gameLayer.enemy[i].hp <= 0)
                    {
                        space.removeBody(enemy_body);
                        space.removeShape(enemy_shape);
                        gameLayer.enemy[i].removeFromParent();
                        gameLayer.enemy.splice(i,1);
                    }

                }
            }

        }.bind(this));

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值