2025年Chipmunk-js物理引擎学习笔记

Chipmunk-js物理引擎学习笔记一 基本概念 空间 在 Chipmunk 中 空间是所有对象容器 因此 刚体 形状 链接节点等对象都需要添加到空间中 空间控制这些对象的相互作用 刚体 物理上的刚体指的是在运动和受力作用后 形状和大小不改变的物体 Chipmunk 中的刚体拥有质量 位置 速度 角速度等物理性质 须注意的是

大家好,我是讯享网,很高兴认识大家。

一、基本概念

  • 空间:在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>
讯享网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(); 

使用浏览器打开后的:
1477392-20190616163948957-1622893498.gif

四、 添加阻挡方块

//添加阻挡方块 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);

最终效果:
1477392-20190616164310151-422877261.gif
引擎的具体实现细节可参考Chipmunk的文档,虽然函数名等有出入,但大致实现思路是一样的哈~

小讯
上一篇 2025-04-08 20:56
下一篇 2025-01-08 13:50

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/18155.html