基于JBox2d物理引擎和canvas的游戏开发实例

 本文基于JBox2d+canvas,后续提供NDK+openglEs版本;本文的主要目的是给大家介绍如何使用创建一个物理世界。

一、主函数:

  • 主函数包括了Box2D的基本流程
  • 简单来说,一个Box2D程序的基本流程是由以下三个基本步骤构成的:

基于JBox2d物理引擎和canvas的游戏开发实例_第1张图片

代码如下:
  1. function box2dMain() {
  2. setupWorld();               //1. 创建一个世界
  3. addBodys();                 //2. 为世界创建物体
  4. setInterval(step, 1000/60); //3. 让世界动起来,反复计算和绘制世界
  5. }
二、创建世界:
  • 设定世界有效区域的大小:超过有效区域的物体将不参与计算。
  • 定义重力:重力是一个二维矢量,矢量在Box2D中用b2Vec2来定义。
  • 设定是否允许物体休眠:当物体静止下来,它就会被判定为休眠,如果打开这个开关,对于休眠的物体将停止模拟。直到它被其它物体解除,它才会醒来。
代码:
  1. function setupWorld(){
  2. //1. 设置有效区域大小 - b2AABB 类 (左上角向量,右下角向量)
  3. worldAABB = new b2AABB();
  4. worldAABB.minVertex.Set(-1000, -1000);  //左上角
  5. worldAABB.maxVertex.Set(1000, 1000);    //右下角
  6. //2. 定义重力 - 2D向量 - b2Vec2 类 (x,y)
  7. gravity = new b2Vec2(0, 300);
  8. //3. 忽略休眠的物体
  9. var doSleep = true;
  10. //4. 创建世界 - b2World
  11. var world = new b2World(worldAABB, gravity, doSleep);
  12. }
三、创建物体:
  • 形状定义:Box2D中有三种基本形状,圆形(Circle)、矩形(Box)、多边形(Poly)。每个形状可以单独定义摩擦力、弹性、密度、相对位置等参数。形状是组成物体的基本材料。(当物体的密度设定为0时,物体变为墙类物体,不可移动)
  • 物体定义:物体可由多个形状组成。形状由其定义相对位置(localPosition)决定其在物体中的位置,形状添加到物体后,其相对位置始终保持不变。
  • 物体:物体只有使用世界的CreateBody()来生成,物体是物体定义的实例。只有使用这个函数生成的物体,才会在世界中被模拟。

 基于JBox2d物理引擎和canvas的游戏开发实例_第2张图片


代码:
  1. function addBodys(){

  2. //1. 定义形状   b2CircleDef,b2BoxDef,b2PolyDef 类
  3. var Shape1 = new b2CircleDef(); //Shape1:圆形
  4. Shape1.radius = 20;                 //半径
  5. Shape1.localPosition.Set(0, 0);     //偏移量
  6. Shape1.density = 1.0;               //密度
  7. Shape1.restitution = .3;            //弹性
  8. Shape1.friction = 1;                //摩擦力

  9. var Shape2 = new b2PolyDef();   //Shape2:多边形
  10. Shape2.vertexCount = 3;                     //顶点数为5
  11. Shape2.vertices[0] = new b2Vec2(0,-20);     //顶点1
  12. Shape2.vertices[1] = new b2Vec2(23.10,20);  //顶点2
  13. Shape2.vertices[2] = new b2Vec2(-23.10,20); //顶点3
  14. Shape2.localPosition.Set(0, 30);    //偏移量
  15. Shape2.density = 1.0;               //密度
  16. Shape2.restitution = .3;            //弹性
  17. Shape2.friction = 1;                //摩擦力

  18. //2. 定义物体   b2BodyDef 类
  19. var BodyDef1 = new b2BodyDef();
  20. BodyDef1.position.Set(100, 100);    //设置物体的初始位置
  21. BodyDef1.AddShape(Shape1);          //物体中加入Shape1
  22. BodyDef1.AddShape(Shape2);          //物体中加入Shape2

  23. //3. 将物体添加至world
  24. Body = World.CreateBody(BodyDef1);  //在世界中创建物体

  25. //...可用同样流程继续添加物体,再定义一块地板
  26. var Shape3 = new b2BoxDef();    //Shape3:矩形

  27. Shape3.extents.Set(200, 5);         //定义矩形高、宽
  28. Shape2.density = 0;                 //墙体密度为0
  29. Shape2.restitution = .3;            //弹性
  30. Shape2.friction = 1;                //摩擦力
  31. var BodyDef2 = new b2BodyDef();
  32. BodyDef2.position.Set(220, 500);    //设置物体的初始位置
  33. BodyDef2.AddShape(Shape3);          //物体中加入Shape3
  34. Body2 = World.CreateBody(BodyDef2); //在世界中创建物体
  35. }
四、让世界运动起来:

  • step()函数的作用是计算某段时间后,世界中物体的位置和角度,并将其绘制到浏览器中。
  • 计算机中的动画,是一帧一帧构成的,每一帧表现了动画中某一时刻的一个场景。所以我们使用定时器函数setInterval(step, 1000/60),来每1/60秒执行一次计算和重绘工作,也就是上述的step()函数。
  • step()中的dt参数,告诉了计算机要计算当前时间多少秒以后的世界,Box2D官方推荐为1/60秒,当然,如果你的计算机足够快,缩小这个时间间隔。另外dt应该与setInterval()函数中的第二个参数对应起来,这样才不会导致物体看起来运动的比你想像的要快或者慢。还有一点,dt不宜过大,否则模拟会不太精确,可能出现物体穿过另一个物体之类的bug。
  • step()中的iterations参数,是多个物体同时发生碰撞时的模拟精度,越高的值会使模拟越精确,但同时也会让运算速度大幅下降,推荐值为10。
  • step()中的World.step()函数是用来计算世界中物体的位置,执行后,物体的位置、角度、速度等信息更新。;
  • step()中的drawWorld()函数会将物体绘制在浏览器中。

基于JBox2d物理引擎和canvas的游戏开发实例_第3张图片 


代码:

  1. function step(){
  2. //计算多少秒之后的世界
  3. var dt = 1/60;
  4. //迭代次数,影响物体碰撞的计算精度,太高会导致速度过慢
  5. var iterations = 10;
  6. //计算dt秒之后世界中物体的位置
  7. World.step(dt,iterations);
  8. //绘制世界
  9. drawWorld();
  10. }
五、绘制世界:

一般情况下我们只利用box2d提供物理模拟,具体世界的绘制工作自己实现。具体绘制方式opengl,canvas,etc。
代码:
  1. /绘制世界
  2. function drawWorld(){

  3. //绘制之前将上一帧的内容清除
  4. context.clearRect(0, 0, canvasWidth, canvasHeight);
  5. //遍历世界中的物体
  6. for (var b = World.m_bodyList; b; b = b.m_next) {
  7. //遍历物体中的形状
  8. for (var s = b.GetShapeList(); s != null; s = s.GetNext())
  9. {
  10. this.drawShape(s);  //绘制一个形状
  11. }
  12. }

  13. }

  14. //绘制一个形状
  15. function drawShape(shape){

  16. context.strokeStyle = '#000';       //线形
  17. context.beginPath();
  18. switch (shape.m_type) {
  19. case b2Shape.e_circleShape:{    //如果是圆形,画圆
  20. var circle = shape;
  21. var r = circle.m_radius;
  22. var pos = circle.m_position;
  23. var pos2 = circle.m_R.col1.clone().scale(r).add(pos);
  24. context.arc(pos.x, pos.y, r, 0, Math.PI * 2, false);
  25. context.moveTo(pos.x, pos.y);
  26. context.lineTo(pos2.x, pos2.y);
  27. break;
  28. }
  29. case b2Shape.e_polyShape:{      //如果是多边形,画多边形
  30. var poly = shape;
  31. var tV = b2Math.AddVV(poly.m_position,
  32. b2Math.b2MulMV(poly.m_R, poly.m_vertices[0]));
  33. context.moveTo(tV.x, tV.y);
  34. for (var i = 0; i < poly.m_vertexCount; i++) {
  35. var v = b2Math.AddVV(poly.m_position,
  36. b2Math.b2MulMV(poly.m_R, poly.m_vertices[i]));
  37. context.lineTo(v.x, v.y);
  38. }
  39. context.lineTo(tV.x, tV.y);
  40. break;
  41. }
  42. }
  43. context.stroke();   //绘制

  44. }

你可能感兴趣的:(基于JBox2d物理引擎和canvas的游戏开发实例)