当前位置:   article > 正文

Chipmunk-js物理引擎学习笔记

chipmunk.js

一、基本概念

  • 空间:在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基本遵循以上步骤,首先创建页面结构:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>hello Chipmunk</title>
  5. </head>
  6. <body>
  7. <canvas></canvas>
  8. </body>
  9. <style type="text/css">
  10. html {background-color: grey;}
  11. canvas {background-color: black;}
  12. </style>
  13. <!-- 注意必须先引入cp.js -->
  14. <script type="text/javascript" src="./cp.js"></script>
  15. <script type="text/javascript" src="./hellochipmunk.js"></script>
  16. </html>

下载cp.js存放至根目录下;
在根目录创建hellochipmunk.js文件,首先创建物理空间:

  1. var height = 480; //界面的高度
  2. var width = 640;//界面的宽度
  3. /*** 物理空间 ***/
  4. function World() {
  5. //初始化空间和重力
  6. this.space = new cp.Space();//创建空间
  7. var v = cp.v;//cp.v是chipmunk中定义的二维空间矢量
  8. this.space.gravity = v(0, 100);//设置重力矢量,重力数值越大,下落加速度越大
  9. //添加空间的边界条件。需要设置边界的形状、弹性系数、摩擦系数。
  10. this.addBoundary = function() {
  11. //设置左边界。
  12. var left = this.space.addShape(new cp.SegmentShape(this.space.staticBody, v(0, 0), v(0, height), 2));
  13. //设置边界的弹性系数。0.0表示完全非弹性碰撞,1.0表示弹性碰撞。
  14. left.setElasticity(0.5);
  15. //设置摩擦系数。0.0表示无摩擦。
  16. left.setFriction(1);
  17. //设置右边界。
  18. var right = this.space.addShape(new cp.SegmentShape(this.space.staticBody, v(width, 0), v(width, height), 2));
  19. right.setElasticity(0.5);
  20. right.setFriction(1);
  21. //设置上边界。
  22. var top = this.space.addShape(new cp.SegmentShape(this.space.staticBody, v(0, 0), v(width, 0), 2));
  23. top.setElasticity(0.5);
  24. top.setFriction(1);
  25. //设置底边界。
  26. var bottom = this.space.addShape(new cp.SegmentShape(this.space.staticBody, v(0, height), v(width, height), 2));
  27. bottom.setElasticity(0.5);
  28. bottom.setFriction(1);
  29. }
  30. //添加球体。首先需要在空间中创建一个刚体,为其赋予质量、转动惯量;
  31. //然后需要指名刚体的形状,这里我们创建的是球体,所以为物体添加一个圆形的形状
  32. this.addBody = function() {
  33. var radius = 25;
  34. var mass = 1;
  35. //设置球体的转动惯量,这里使用库中的一个函数计算其惯量
  36. var moment = cp.momentForCircle(mass, 0, radius, cp.vzero);
  37. //在空间中创建球体
  38. var ballBody = new cp.Body(mass, moment);
  39. this.space.addBody(ballBody);
  40. ballBody.setPos(v(width/2, height/3));
  41. //为球体添加形状
  42. var ballShape = new cp.CircleShape(ballBody, radius, cp.vzero);
  43. this.space.addShape(ballShape);
  44. ballShape.setFriction(1);
  45. ballShape.setElasticity(0.7);
  46. }
  47. }

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

  1. /*** 在画布中实现可视化 ***/
  2. function Canvas() {
  3. var _this = this;
  4. this.cns = document.getElementsByTagName('canvas')[0];//设置画布大小
  5. this.cns.height = height;
  6. this.cns.width = width;
  7. this.ctx = this.cns.getContext('2d');
  8. this.drawLine = function(ctx, a, b) {
  9. this.ctx.beginPath();
  10. this.ctx.moveTo(a.x, a.y);
  11. this.ctx.lineTo(b.x, b.y);
  12. this.ctx.stroke();
  13. };
  14. this.drawCircle = function(ctx, c, radius) {
  15. this.ctx.lineWidth = 3;
  16. this.ctx.beginPath();
  17. this.ctx.arc(c.x, c.y, radius, 0, 2*Math.PI, false);
  18. this.ctx.fill();
  19. this.ctx.stroke();
  20. };
  21. this.draw = function(world) {
  22. _this.ctx.strokeStyle = 'white';
  23. _this.ctx.lineCap = 'round';
  24. _this.ctx.clearRect(0, 0, _this.cns.width, _this.cns.height);
  25. _this.ctx.font = "16px sans-serif";
  26. _this.ctx.lineCap = 'round';
  27. world.space.eachShape(function(shape) {
  28. _this.ctx.fillStyle = 'red'
  29. shape.draw(_this.ctx);
  30. })
  31. }
  32. cp.PolyShape.prototype.draw = function(ctx) {
  33. ctx.lineWidth = 2;
  34. ctx.beginPath();
  35. ctx.fillStyle = 'blue';
  36. var verts = this.tVerts;
  37. var len = verts.length;
  38. var lastPoint = new cp.Vect(verts[len - 2], verts[len - 1]);
  39. ctx.moveTo(lastPoint.x, lastPoint.y);
  40. for(var i = 0; i < len; i+=2){
  41. var p = new cp.Vect(verts[i], verts[i+1]);
  42. ctx.lineTo(p.x, p.y);
  43. }
  44. ctx.fill();
  45. ctx.stroke();
  46. };
  47. cp.SegmentShape.prototype.draw = function(ctx) {
  48. ctx.lineWidth = Math.max(1, this.r * 2);
  49. _this.drawLine(ctx, this.ta, this.tb);
  50. };
  51. cp.CircleShape.prototype.draw = function(ctx) {
  52. _this.drawCircle(ctx, this.tc, this.r);
  53. // 显示球体中的一条半径,从而可以清楚观察到球体的转动
  54. _this.drawLine(ctx,this.tc, cp.v.mult(this.body.rot, this.r).add(this.tc));
  55. };
  56. }

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

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

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

四、 添加阻挡方块

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

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

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

转载于:https://www.cnblogs.com/Gavin257/p/11029176.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/105214
推荐阅读
相关标签
  

闽ICP备14008679号