一、基本概念##

  • 空间:在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的文档,虽然函数名等有出入,但大致实现思路是一样的哈~

Chipmunk-js物理引擎学习笔记的更多相关文章

  1. p2.js物理引擎学习

    P2简介 P2是一款基于Javascript编写的HTML5 2D物理引擎,和Box2D.Nape等2D物理引擎一样,P2集成了各种复杂的物理公式和算法,可以帮助我们轻松的实现碰撞.反弹等物理现象的模 ...

  2. 浏览器中js执行机制学习笔记

    浏览器中js执行机制学习笔记 RiverSouthMan关注 0.0772019.05.15 20:56:37字数 872阅读 291 同步任务 当一个脚本第一次执行的时候,js引擎会解析这段代码,并 ...

  3. three.js 之cannon.js物理引擎

    今天郭先生说的是一个物理引擎,它十分小巧并且操作简单,没错他就是cannon.js.这些优点都源自于他是基于js编写的,对于js使用者来说cannon.js拥有其他物理引擎没有的纯粹性.从学习成本来看 ...

  4. three.js cannon.js物理引擎之Heightfield

    今天郭先生说一说cannon.js物理引擎之Heightfield高度场,学过场论的朋友都知道物理学中把某个物理量在空间的一个区域内的分布称为场,高度场就是与高度相关的场,而cannon.js物理引擎 ...

  5. three.js cannon.js物理引擎制作一个保龄球游戏

    关于cannon.js我们已经学习了一些知识,今天郭先生就使用已学的cannon.js物理引擎的知识配合three基础知识来做一个保龄球小游戏,效果如下图,在线案例请点击博客原文. 我们需要掌握的技能 ...

  6. three.js cannon.js物理引擎之齿轮动画

    郭先生今天继续说一说cannon.js物理引擎,并用之前已经学习过的知识实现一个小动画,知识点包括ConvexPolyhedron多边形.Shape几何体.Body刚体.HingeConstraint ...

  7. 【09-23】js原型继承学习笔记

    js原型继承学习笔记 function funcA(){ this.a="prototype a"; } var b=new funcA(); b.a="object a ...

  8. NVelocity模板引擎学习笔记

    NVelocity模板引擎学习笔记 学习模板引擎有一段时间现在做一些总结

  9. Underscore.js 源码学习笔记(下)

    上接 Underscore.js 源码学习笔记(上) === 756 行开始 函数部分. var executeBound = function(sourceFunc, boundFunc, cont ...

随机推荐

  1. cocos2dx新建项目

    首先你得下载好cococs2dx,还有python2.x版本,还有vs2017 然后cmd在你Cocos2dx的路径下输入 python setup.py 然后你就回车回车回车 然后重新打开cmd 这 ...

  2. Python爬虫之记录一次下载验证码的尝试

      好久没有写过爬虫的文章了,今天在尝试着做验证码相关的研究时,遇到了验证码的收集问题.   一般,验证码的加载都有着比较复杂的算法和加密在里边,但是笔者今天碰到的验证码却比较幸运,有迹可循.在此,给 ...

  3. JavaScript Array every()&some()&reduce()方法

    every()方法测试数组的所有元素是否都通过了指定函数的测试. // 每一项都要满足条件才会返回true,只要有一项不满足返回false var arr = [1, 2, 3, 4]; let bl ...

  4. spark系列-4、spark序列化方案、GC对spark性能的影响

    一.spark的序列化 1.1.官网解释 http://spark.apache.org/docs/2.1.1/tuning.html#data-serialization 序列化在任何分布式应用程序 ...

  5. 图论--2-SAT--暴力染色法模板(字典序最小解) RQ的板子

    //暴力DFS,求字典序最小的解,也是求字典序唯一的方法 #include<cstdio> #include<cstring> #include<vector> u ...

  6. Automatic Reference Counting

    NSObject简化版alloc: struct obj_layout { NSUInteger retained; }; + (id)alloc { int size = sizeof(struct ...

  7. R - Weak Pair HDU - 5877 离散化+权值线段树+dfs序 区间种类数

    R - Weak Pair HDU - 5877 离散化+权值线段树 这个题目的初步想法,首先用dfs序建一颗树,然后判断对于每一个节点进行遍历,判断他的子节点和他相乘是不是小于等于k, 这么暴力的算 ...

  8. 剑指offer--(根据前序遍历和中序遍历)重建二叉树

    题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7, ...

  9. LRU 的C# 实现

    首先 先写点儿感悟吧: 本来计划是 晚上回家写的  后来发现还是没坚持的了  上午花了一个多小时  做了一下这个题目  应该还有提高的空间 的,这个题目是在力扣里面看到的  为什么看到这个题目 是因为 ...

  10. [hdu3507 Print Article]斜率优化dp入门

    题意:需要打印n个正整数,1个数要么单独打印要么和前面一个数一起打印,1次打印1组数的代价为这组数的和的平方加上常数M.求最小代价. 思路:如果令dp[i]为打印前i个数的最小代价,那么有 dp[i] ...