Chipmunk是一个开源的物理引擎,最近想做一个动作Html5游戏,需要用到物理引擎,所以找来学了下。
Chipmunk的核心概念:
- 空间(space)
- 物体(body)
- 形状(shape)
- 关节(joint)
一般来说,使用该引擎的流程如下:
接下来介绍Chipmunk在Cocos2d-js中的使用。
Cocos2d-js中自带了Chipmunk,但是如果要使用还得在project.json中的"modules"配置中添加模块声明:
"modules" : ["cocos2d", "external"]
"external"
模块包含了chipmunk等子模块
首先,在Layer对象的构造函数ctor中新建space对象,并且为之添加边界:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
var winSize = cc.director.getWinSize();
this .space = new cp.Space(); //以cp开头的对象表明其是chipmunk的类
this ._debugNode = new cc.PhysicsDebugNode( this .space);
this ._debugNode.visible = true ; //是否开启debug模式,开启后会显示遮罩和关节等
this .addChild( this ._debugNode);
this .space.gravity = cp.v(0, -100);
//设置space这个空间的重力,cp.v用来表示一个二维矢量,这里表示x轴重力为0,y为-100
var staticBody = this .space.staticBody;
// 设置边界
//cp.SegmentShape()用来为space设置边界,后三个参数分别为边界起点、终点以及边界宽度
var walls = [ new cp.SegmentShape(staticBody, cp.v(0, 0), cp.v(winSize.width, 0), 0), // bottom
new cp.SegmentShape(staticBody, cp.v(0, winSize.height), cp.v(winSize.width, winSize.height), 0), // top
new cp.SegmentShape(staticBody, cp.v(0, 0), cp.v(0, winSize.height), 0), // left
new cp.SegmentShape(staticBody, cp.v(winSize.width, 0), cp.v(winSize.width, winSize.height), 0) // right
];
for ( var i = 0; i < walls.length; i++) {
var shape = walls[i];
shape.setElasticity(1); //设置弹性为1
shape.setFriction(1); //设置摩擦力为1
this .space.addStaticShape(shape);
}
|
space对象的边界也是shape+body对象,只不过是静态的,不可动。
然后在space中添加body:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
var body = new cp.Body(1, cp.momentForBox(1, SPRITE_WIDTH, SPRITE_HEIGHT));
//cp.Body()有两个参数,第一个为质量,第二个为惯性值,通过cp.momentForBox()得到
//cp.momentForBox()得到一个长方形的惯性值,第一个参数为“惯性力矩”一般设为1,后面两个参数为长方形body的宽和高
body.setPos(p);
//设置body的重心,p为cc.p对象
this .space.addBody(body);
//新建一个shape对象需要传入一个body对象作为参数,该body对象就是shape要与之绑定的对象
var shape = new cp.BoxShape(body, SPRITE_WIDTH, SPRITE_HEIGHT);
shape.setElasticity(0.5);
shape.setFriction(0.5);
this .space.addShape(shape);
//创建物理引擎精灵对象
var sprite = new cc.PhysicsSprite( "res/BoxA2.png" );
sprite.setBody(body); //sprite与body绑定
sprite.setPosition(cc.p(p.x, p.y));
this .addChild(sprite);
body.data = sprite;
//这样设置之后可以通过body.data来得到绑定的sprite
|
我将body、
shape、
sprite三者的关系理解为 :body是一个物体的内在属性,比如质量多大,运动起来的惯性是怎样的,shape则是一个物体的外在属性,比如是圆的还是方的,表面是光滑还是粗糙(摩擦力),物体与之相撞后的弹力等。像边界这样
不动
的staticBody,不用设置其质量、惯性,直接由this.space.staticBody得到就可以。sprite就是一个物体看起来的样子,哪怕sprite的图片是个方的,只要与之绑定的shape是圆的,它还是可以滚起来。
为物体添加关节:
关节(joint)是一条线段,将两个物体连在一起,物体围绕两个端点可以转动。
this
.space.addConstraint(
new
cp.PinJoint(body1, body2, cp.v(0,0), cp.v(0, SPRITE_WIDTH / 2)));
该方法可以为两个物体(body1,body2)添加关节。
cp.PinJoint()方法的后两个参数为关节在body1和body2里面连接点的坐标,它是模型坐标
在上述步骤之后,便完成了对物体和空间的初始化。接下来需要调用this.scheduleUpdate()来开启动画。并且在其回调函数update()中设置绘制间隔:
1
2
3
4
|
update: function () {
var period = 0.05;
this .space.step(period);
}
|
到此为止,space中的物体后便会发生相撞后反弹、下落等动作,但如果需要两个物体相撞后执行一些方法,则需设置碰撞检测。
设置碰撞检测:
1
2
3
4
5
6
|
this .space.addCollisionHandler(COLLISION_TYPE, COLLISION_TYPE,
this .collisionBegin.bind( this ),
this .collisionPre.bind( this ),
this .collisionPost.bind( this ),
this .collisionSeparate.bind( this )
);
|
.addCollisionHandler()方法有6个参数。前两个为两个碰撞物体碰撞类型,碰撞类型是一个整数,只有物体的碰撞类型与碰撞检测中设置的碰撞类型相等时碰撞才能发生。后面四个参数为四个回调方法,它们执行的时机分别是:
物体第一次相撞时触发,只能触发一次,该方法返回一个布尔值,若为true,则可触发后面的方法
- 持续碰撞时触发,可反复触发,
该方法返回一个布尔值,若为true,则可触发方法第三个方法
- 也是持续碰撞时触发,但仅当第二个方法返回true时才执行
- 物体分开时触发,只能触发一次
此外 还需要为物体的shape设置碰撞检测类型:
shape.setCollisionType(COLLISION_TYPE);