初识chipmunk物理引擎
chipmunk本是一个独立的开源项目,用纯c编写.cocos2d同时整合了chipmunk和box2d两个物理引擎.
相比之下,chipmunk更轻量易用,但是相关的文档很少.
- space: 发生物理模拟的空间,可容纳body, shape,joint
- body:刚体,可被赋予shape。刚体具有质量,转动惯量,位置,线性速度,加速度,角度,角速度,角加速度等属性。刚体之间可通过joint连接
- shape:决定刚体的碰撞外形。一个刚体上可覆盖上多个shape,同属于一个刚体的shape不会互相发生碰撞。shape同样需要加到space中。有圆,线段,凸多边形这三种shape类型。
- joint: 用于连接刚体。有4种类型:
- pin joint: 相当于一根棍子(质量忽略)加两个大头针(锚点),两个刚体如果用pin joint连接,他们之间的距离不会改变,他们各自可绕锚点转动(如果有力矩的话)
- slide joint: 相当于把pin joint的棍子换成了滑槽。这个滑槽有最大和最小长度。
- pivot joint: 即一个旋转轴。两个刚体都绕这个轴旋转
- groove joint:相当于可滑动的pivot joint。将刚体2的旋转轴挂到处于刚体1的一段滑槽上。
chipmunk小demo
以下demo实例用的是cocos2d-js
-
初始化物理世界
initPhysics:function(){
var winSize = cc.director.getWinSize();
// 创建物理空间
this.space = new cp.Space();
// 设置重力
this.space.gravity = cp.v(0, -100);
this.space.sleepTimeThreshold = 0.5; // 静止睡眠时间阀值var staticBody = this.space.staticBody; // 设置空间边界 var walls = [ new cp.SegmentShape(staticBody, cp.v(0, 0), cp.v(winSize.width, 0), 0), // 下 new cp.SegmentShape(staticBody, cp.v(0, winSize.height), cp.v(winSize.width, winSize.height), 0), // 上 new cp.SegmentShape(staticBody, cp.v(0, 0), cp.v(0, winSize.height), 0), // 左 new cp.SegmentShape(staticBody, cp.v(winSize.width, 0), cp.v(winSize.width, winSize.height), 0) // 右 ]; for (var i = 0; i < walls.length; i++) { var shape = walls[i]; shape.setElasticity(1); shape.setFriction(1); this.space.addStaticShape(shape); } },
-
打开调试模式
setupDebugNode: function () { this._debugNode = new cc.PhysicsDebugNode(this.space); this._debugNode.visible = true; this.addChild(this._debugNode); },
刚体创建
-
动态刚体:
cp.Body(质量,转动惯量)
cp.CircleShape(刚体, 半径, 重心与圆心的偏移量)loadDynamicBody: function (p) { // 刚体创建 var body = new cp.Body(1, cp.momentForCircle(1, 0, 55, cp.vzero)); body.setPos(p); this.space.addBody(body); // 形状创建 var shape = new cp.CircleShape(body, 55, cp.vzero); shape.setElasticity(0.5); shape.setFriction(0.5); this.space.addShape(shape); //body.setAngVel(10); // 旋转速度 //body.applyForce(cp.v(300,300),cp.v(0,0)); // 持续力 //body.applyImpulse(cp.v(300,300),cp.v(0,0)); // 瞬时冲量 // // 精灵绑定刚体 // var sprite = new cc.PhysicsSprite("res/btn_refresh.png"); // 无法通过文件路径创建 // sprite.setBody(body); // this.addChild(sprite); return body },
-
静态刚体:
静态刚体创建与动态刚体基本一样,唯一的区别是静态刚体不将刚体添加到space空间,要不然会报错,具体为什么,不明。 由于静态刚体的不可移动特性,space空间内只一个静态刚体就足够,其他只要创建shape,并添加到这个静态刚体this.space.staticBody上即可。 如果你需要移动静态刚体最好new cp.StaticBody()创建。 loadStaticBody:function(position){ // 刚体创建 //var body = this.space.staticBody; var body = new cp.StaticBody(); body.setPos(position); // 形状创建 var shape = new cp.BoxShape(body, 100, 100); shape.setElasticity(0.5); shape.setFriction(0.5); this.space.addShape(shape); // // 精灵 // var sprite = new cc.PhysicsSprite("res/btn_refresh.png"); // 无法通过文件路径创建 // sprite.setBody(body); // this.addChild(sprite); return body },
-
让物理世界动起来
前面的创建还缺最关键的一步,就是激活整个物理世界
this.scheduleUpdate() 开启调度
并在更新函数内添加物理世界更新
update:function(dt){ var timeStep = 0.03; this.space.step(timeStep); // // 静态刚体位置更新(否则静态刚体创建后位置无法改变) // this.space.reindexStatic(); }
完整的代码
ChipmunkLayer.js
var DEBUG_NODE_SHOW = true;
var ChipmunkLayer = cc.Layer.extend({
ctor: function () {
this._super();
// 初始化物理世界
this.initPhysics();
// 开启调试模式
this.setupDebugNode();
// 加载动态刚体
this.loadDynamicBody(cp.v(480,300));
// 加载静态刚体
this.loadStaticBody(cp.v(480,100));
// 更新世界
this.scheduleUpdate();
},
initPhysics:function(){
var winSize = cc.director.getWinSize();
this.space = new cp.Space();
// 设置重力
this.space.gravity = cp.v(0, -100);
this.space.sleepTimeThreshold = 0.5; // 静止睡眠时间阀值
var staticBody = this.space.staticBody;
// 设置空间边界
var walls = [ new cp.SegmentShape(staticBody, cp.v(0, 0),
cp.v(winSize.width, 0), 0),
new cp.SegmentShape(staticBody, cp.v(0, winSize.height),
cp.v(winSize.width, winSize.height), 0),
new cp.SegmentShape(staticBody, cp.v(0, 0),
cp.v(0, winSize.height), 0),
new cp.SegmentShape(staticBody, cp.v(winSize.width, 0),
cp.v(winSize.width, winSize.height), 0)
];
for (var i = 0; i < walls.length; i++) {
var shape = walls[i];
shape.setElasticity(1);
shape.setFriction(1);
this.space.addStaticShape(shape);
}
},
setupDebugNode: function () {
this._debugNode = new cc.PhysicsDebugNode(this.space);
this._debugNode.visible = DEBUG_NODE_SHOW;
this.addChild(this._debugNode);
},
loadStaticBody:function(position){
// 刚体创建
//var body = this.space.staticBody;
var body = new cp.StaticBody();
body.setPos(position);
// 形状创建
var shape = new cp.BoxShape(body, 100, 100);
shape.setElasticity(0.5);
shape.setFriction(0.5);
this.space.addShape(shape);
// // 精灵
// var sprite = new cc.PhysicsSprite("res/btn_refresh.png"); // 无法通过文件路径创建
// sprite.setBody(body);
// this.addChild(sprite);
return body
},
loadDynamicBody: function (position) {
// 刚体创建
var body = new cp.Body(1, cp.momentForCircle(1, 0, 55, cp.vzero));
body.setPos(position);
this.space.addBody(body);
// 形状创建
var shape = new cp.CircleShape(body, 55, cp.vzero);
shape.setElasticity(0.5);
shape.setFriction(0.5);
this.space.addShape(shape);
//body.setAngVel(10); // 旋转速度
//body.applyForce(cp.v(300,300),cp.v(0,0)); // 持续力
//body.applyImpulse(cp.v(300,300),cp.v(0,0)); // 瞬时冲量
// // 精灵绑定刚体
// var sprite = new cc.PhysicsSprite("res/btn_refresh.png"); // 无法通过文件路径创建
// sprite.setBody(body);
// this.addChild(sprite);
return body
},
update:function(dt){
var timeStep = 0.03;
this.space.step(timeStep);
// // 静态刚体位置更新(否则静态刚体创建后位置无法改变)
// this.space.reindexStatic();
}
});