一、基本概念##

  • 空间:在Chipmunk中,空间是所有对象容器。因此,刚体、形状、链接节点等对象都需要添加到空间中。空间控制这些对象的相互作用。
  • 刚体:物理上的刚体指的是在运动和受力作用后,形状和大小不改变的物体。Chipmunk中的刚体拥有质量、位置、速度、角速度等物理性质。须注意的是,添加到空间中的刚体只是一个质点,需要为其赋予形状后,它才有面积或体积的性质。
  • 形状:形状定义了物体碰撞的外形,同时包括物体如弹性系数、摩擦系数等表面的性质;你可以对一个刚体赋予多个形状,同一物体的形状不会碰撞。
  • 连接节点:连接节点定义刚体之间的连接方式。

二、Chipmunk-js与Chipmunk的区别##

  • 运行速度下降了,Chipmunk-js大概比Chipmunk慢了3倍的样子,Chipmunk的作者说用纯C写的部分原因就是它运行速度很快哈哈
  • Chipmunk-js用面向对象的形式来写,所以函数名些许不同,比如cpvadd(a, b)变成了cp.vadd(a, b)
  • 去除了函数中描述数组长度的参数,比如:
    cpMomentForPoly(mass, numVerts, *verts, offset);

变成了:

    cp.momentForPoly(mass, verts, offset);
  • 去除了大部分getter和setter函数。

三、 HelloChipmunk案例##

使用Chipmunk物理引擎进行开发的一般步骤为:

(1)创建物理空间;

(2)指定空间边界;

(3)创建空间中的物体;

(4)创建空间中的形状;

(5)连接精灵与物体(实现物体可视化);

(6)检测碰撞。

使用Chipmunk-js基本遵循以上步骤,首先创建页面结构:

<!DOCTYPE html>
<html>
<head>
<title>hello Chipmunk</title>
</head>
<body>
<canvas></canvas>
</body>
<style type="text/css">
html {background-color: grey;}
canvas {background-color: black;}
</style>
<!-- 注意必须先引入cp.js -->
<script type="text/javascript" src="./cp.js"></script>
<script type="text/javascript" src="./hellochipmunk.js"></script>
</html>

下载cp.js存放至根目录下;

在根目录创建hellochipmunk.js文件,首先创建物理空间:

var height = 480; //界面的高度
var width = 640;//界面的宽度 /*** 物理空间 ***/
function World() {
//初始化空间和重力
this.space = new cp.Space();//创建空间
var v = cp.v;//cp.v是chipmunk中定义的二维空间矢量
this.space.gravity = v(0, 100);//设置重力矢量,重力数值越大,下落加速度越大 //添加空间的边界条件。需要设置边界的形状、弹性系数、摩擦系数。
this.addBoundary = function() {
//设置左边界。
var left = this.space.addShape(new cp.SegmentShape(this.space.staticBody, v(0, 0), v(0, height), 2));
//设置边界的弹性系数。0.0表示完全非弹性碰撞,1.0表示弹性碰撞。
left.setElasticity(0.5);
//设置摩擦系数。0.0表示无摩擦。
left.setFriction(1); //设置右边界。
var right = this.space.addShape(new cp.SegmentShape(this.space.staticBody, v(width, 0), v(width, height), 2));
right.setElasticity(0.5);
right.setFriction(1); //设置上边界。
var top = this.space.addShape(new cp.SegmentShape(this.space.staticBody, v(0, 0), v(width, 0), 2));
top.setElasticity(0.5);
top.setFriction(1); //设置底边界。
var bottom = this.space.addShape(new cp.SegmentShape(this.space.staticBody, v(0, height), v(width, height), 2));
bottom.setElasticity(0.5);
bottom.setFriction(1);
} //添加球体。首先需要在空间中创建一个刚体,为其赋予质量、转动惯量;
//然后需要指名刚体的形状,这里我们创建的是球体,所以为物体添加一个圆形的形状
this.addBody = function() {
var radius = 25;
var mass = 1;
//设置球体的转动惯量,这里使用库中的一个函数计算其惯量
var moment = cp.momentForCircle(mass, 0, radius, cp.vzero);
//在空间中创建球体
var ballBody = new cp.Body(mass, moment);
this.space.addBody(ballBody);
ballBody.setPos(v(width/2, height/3));
//为球体添加形状
var ballShape = new cp.CircleShape(ballBody, radius, cp.vzero);
this.space.addShape(ballShape);
ballShape.setFriction(1);
ballShape.setElasticity(0.7);
}
}

然后在画布上将物理空间绘画出来:

/*** 在画布中实现可视化 ***/
function Canvas() {
var _this = this;
this.cns = document.getElementsByTagName('canvas')[0];//设置画布大小
this.cns.height = height;
this.cns.width = width;
this.ctx = this.cns.getContext('2d');
this.drawLine = function(ctx, a, b) {
this.ctx.beginPath();
this.ctx.moveTo(a.x, a.y);
this.ctx.lineTo(b.x, b.y);
this.ctx.stroke();
};
this.drawCircle = function(ctx, c, radius) {
this.ctx.lineWidth = 3;
this.ctx.beginPath();
this.ctx.arc(c.x, c.y, radius, 0, 2*Math.PI, false);
this.ctx.fill();
this.ctx.stroke();
};
this.draw = function(world) {
_this.ctx.strokeStyle = 'white';
_this.ctx.lineCap = 'round'; _this.ctx.clearRect(0, 0, _this.cns.width, _this.cns.height);
_this.ctx.font = "16px sans-serif";
_this.ctx.lineCap = 'round';
world.space.eachShape(function(shape) {
_this.ctx.fillStyle = 'red'
shape.draw(_this.ctx);
})
}
cp.PolyShape.prototype.draw = function(ctx) {
ctx.lineWidth = 2;
ctx.beginPath();
ctx.fillStyle = 'blue'; var verts = this.tVerts;
var len = verts.length;
var lastPoint = new cp.Vect(verts[len - 2], verts[len - 1]);
ctx.moveTo(lastPoint.x, lastPoint.y);
for(var i = 0; i < len; i+=2){
var p = new cp.Vect(verts[i], verts[i+1]);
ctx.lineTo(p.x, p.y);
}
ctx.fill();
ctx.stroke();
};
cp.SegmentShape.prototype.draw = function(ctx) {
ctx.lineWidth = Math.max(1, this.r * 2);
_this.drawLine(ctx, this.ta, this.tb);
};
cp.CircleShape.prototype.draw = function(ctx) {
_this.drawCircle(ctx, this.tc, this.r);
// 显示球体中的一条半径,从而可以清楚观察到球体的转动
_this.drawLine(ctx,this.tc, cp.v.mult(this.body.rot, this.r).add(this.tc));
};
}

最后运行空间,通过更新画布来显示动画:

var raf = window.requestAnimationFrame
|| window.webkitRequestAnimationFrame
|| window.mozRequestAnimationFrame
|| window.oRequestAnimationFrame
|| window.msRequestAnimationFrame
|| function(callback) {
return window.setTimeout(callback, 1000 / 60);
};
var drawFrame = function() {
var dt = 1/60;
//每dt个时间步内更新空间。
world.space.step(dt);
//刷新画布图像
canvas.draw.call(this, world);
raf(drawFrame);
}; var world = new World();//(1)创建物理空间;
world.addBoundary();//(2)指定空间边界;
world.addBody();//(3)创建空间中的物体;(4)创建空间中的形状;
var canvas = new Canvas();//(5)连接精灵与物体(实现物体可视化);
drawFrame();

使用浏览器打开后的:

四、 添加阻挡方块##

我们可以在球体下落的路径上添加一个方块,模拟球体与方块的碰撞现象。在如弹一弹的小游戏中,实现原理与此类似,它们是在球体与方块碰撞后加入了回调函数,以实现加分或方块消失等事件

可以将阻挡方块看作是一种边界条件,我们在World里的addBoundary函数添加:

//添加阻挡方块
var blockBody = new cp.Body(Infinity, Infinity);//由于方块是静止的,我们设它的质量和转动惯量为无穷大
blockBody.setPos(cp.v(width/2, height*2/3));
blockBody.setAngle(0.1);//设置方块偏转角度
var block = this.space.addShape(new cp.BoxShape(blockBody, 50, 50),);
block.setElasticity(1);
block.setFriction(1);

最终效果:



引擎的具体实现细节可参考Chipmunk的文档,虽然函数名等有出入,但大致实现思路是一样的哈~

最新文章

  1. iOS开发之多种Cell高度自适应实现方案的UI流畅度分析
  2. AngularJS Directive 隔离 Scope 数据交互
  3. php session的存放目录,再次回顾
  4. Oracle Fusion Applications (11.1.8) Media Pack and Oracle Application Development Framework 11g (11.1.1.7.2) for Microsoft Windows x64 (64-bit)
  5. bzoj 1854: [Scoi2010]游戏
  6. 通过jQuery或ScriptManager以Ajax方式访问服务
  7. Linux ulimit 系统资源控制
  8. 未能加载文件或程序集 Newtonsoft.Json, Version=4.5.0.0 的报错,解决方法
  9. bouncycastle 国密SM2 API的使用
  10. SQLServer中SQL语句与可执行二进制语句
  11. 对于spring中事务@Transactional注解的理解
  12. CSS white-space属性详解
  13. 小白的CTF学习之路3——二进制数据基础与运算(下)
  14. loki grafana 团队开源的,类似Prometheus 的log 系统
  15. python 之 基础
  16. 原生js(二)
  17. SendTo MD5 - imsoft.cnblogs
  18. 【CodeForces】713 C. Sonya and Problem Wihtout a Legend
  19. TestDirector自定义管理:工程配置
  20. 图形管线之旅 Part5

热门文章

  1. optparse--强大的命令行参数处理包
  2. MyBatis学习总结(9)——使用MyBatis Generator自动创建代码
  3. 集合框架-day10
  4. Ubuntu 14.04 配置samba
  5. U-Mail邮件系统详解邮件收发延迟原因及解决方案
  6. 数学--数论--HDU 1098 Ignatius's puzzle (费马小定理+打表)
  7. RabbitMQ的使用(一)- RabbitMQ服务安装
  8. windows脱密码总结
  9. jQuery中的查找节点、创建节点、插入节点、删除节点、替换节点、复制节点操作方法
  10. LTE基站开局流程脚本的具体含义