zoukankan      html  css  js  c++  java
  • box2dweb 学习笔记--sample讲解

    前言:
      之前博文"台球游戏的核心算法和AI(1)" 中, 提到过想用HTML5+Box2d来编写实现一个台球游戏. 以此来对比感慨一下游戏物理引擎的巨大威力.
      做为H5+box2d的初学者, 将简单讲讲box2d的一些基础概念, 并对一个sample样例做下讲解. 权作学习笔记.

    资料:
      box2d源自flash版, 后迁移到各个语言版本, box2dweb是与最新flash版本同步的js 2D物理引擎库.
      box2dweb版网址: http://code.google.com/p/box2dweb/.
      box2d官网: http://box2d.org/.

    基本概念:
      世界: b2world
      box2d物体依托的世界存在, 其需指定重力向量, 以及静止物体的休眠开关.

    var world = new b2World(gravity, doSleep);

      刚体: b2body
      物理世界中的具体物体, 有动态/静态物体之分.
      夹具: b2fixture
      定义物体的形状,材质属性(密度, 摩擦系数,弹性系数)等等.

    代码样例:
      box2dweb库采用当前最新的Box2dWeb-2.1a.3. 该库只包含一个js文件, 并附带了样例.
      文件组织结构如下所示:
      
      我们以sample.html为例, 对box2dweb库做下简单的讲解.
      展示的效果如下:
      

      具体代码如下:

    <html>
       <head>
          <title>Box2dWeb example</title>
       </head>
       <body onload="init();">
          <canvas id="canvas" width="600" height="400"></canvas>
       </body>
       <script type="text/javascript" src="Box2dWeb-2.1.a.3.min.js"></script>
       <script type="text/javascript">
          var world;
          
          function init() {
             var   b2Vec2 = Box2D.Common.Math.b2Vec2
             	,	b2BodyDef = Box2D.Dynamics.b2BodyDef
             	,	b2Body = Box2D.Dynamics.b2Body
             	,	b2FixtureDef = Box2D.Dynamics.b2FixtureDef
             	,	b2Fixture = Box2D.Dynamics.b2Fixture
             	,	b2World = Box2D.Dynamics.b2World
             	,	b2MassData = Box2D.Collision.Shapes.b2MassData
             	,	b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape
             	,	b2CircleShape = Box2D.Collision.Shapes.b2CircleShape
             	,	b2DebugDraw = Box2D.Dynamics.b2DebugDraw
                ;
             
             world = new b2World(
                   new b2Vec2(0, 10)    //gravity
                ,  true                 //allow sleep
             );
             
             var fixDef = new b2FixtureDef;
             fixDef.density = 1.0;
             fixDef.friction = 0.5;
             fixDef.restitution = 0.2;
             
             var bodyDef = new b2BodyDef;
             
             //create ground
             bodyDef.type = b2Body.b2_staticBody;
             bodyDef.position.x = 9;
             bodyDef.position.y = 13;
             fixDef.shape = new b2PolygonShape;
             fixDef.shape.SetAsBox(10, 0.5);
             world.CreateBody(bodyDef).CreateFixture(fixDef);
             
             //create some objects
             bodyDef.type = b2Body.b2_dynamicBody;
             for(var i = 0; i < 10; ++i) {
                if(Math.random() > 0.5) {
                   fixDef.shape = new b2PolygonShape;
                   fixDef.shape.SetAsBox(
                         Math.random() + 0.1 //half width
                      ,  Math.random() + 0.1 //half height
                   );
                } else {
                   fixDef.shape = new b2CircleShape(
                      Math.random() + 0.1 //radius
                   );
                }
                bodyDef.position.x = Math.random() * 10;
                bodyDef.position.y = Math.random() * 10;
                world.CreateBody(bodyDef).CreateFixture(fixDef);
             }
             
             //setup debug draw
             var debugDraw = new b2DebugDraw();
    			debugDraw.SetSprite(document.getElementById("canvas").getContext("2d"));
    			debugDraw.SetDrawScale(30.0);
    			debugDraw.SetFillAlpha(0.3);
    			debugDraw.SetLineThickness(1.0);
    			debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
    			world.SetDebugDraw(debugDraw);
             
             window.setInterval(update, 1000 / 60);
          };
          
          function update() {
             world.Step(
                   1 / 60   //frame-rate
                ,  10       //velocity iterations
                ,  10       //position iterations
             );
             world.DrawDebugData();
             world.ClearForces();
          };
       
       </script>
       
       
    </html>

      js应该没有类似java和c#的命令空间的概念, 为避免冲突, 往往通过添加前缀名来解决, 比如box2dweb的采用b2前缀. 另一方面, 其通过简写的技巧来缩短类和函数的引用.

    var b2Vec2 = Box2D.Common.Math.b2Vec2
      , b2BodyDef = Box2D.Dynamics.b2BodyDef
      , b2Body = Box2D.Dynamics.b2Body
      , b2FixtureDef = Box2D.Dynamics.b2FixtureDef
      , b2Fixture = Box2D.Dynamics.b2Fixture
      , b2World = Box2D.Dynamics.b2World
      , b2MassData = Box2D.Collision.Shapes.b2MassData
      , b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape
      , b2CircleShape = Box2D.Collision.Shapes.b2CircleShape
      , b2DebugDraw = Box2D.Dynamics.b2DebugDraw
    ;

      注: 通过简写来缩短类名和函数对象的引用.
      • 创建世界

    world = new b2World(
      new b2Vec2(0, 10) //gravity
      , true //allow sleep
    );

      • 创建地面

    var bodyDef = new b2BodyDef;
    //create ground
    bodyDef.type = b2Body.b2_staticBody;
    bodyDef.position.x = 9;
    bodyDef.position.y = 13;
    fixDef.shape = new b2PolygonShape;
    fixDef.shape.SetAsBox(10, 0.5);
    world.CreateBody(bodyDef).CreateFixture(fixDef);

      注: b2Body.b2_staticBody标示该物体为静态物体(固定物), 一个物体由b2BodyDef和b2FixtureDef来确定.
      • 创建刚体

    //create some objects
    bodyDef.type = b2Body.b2_dynamicBody;
    for(var i = 0; i < 10; ++i) {
      if(Math.random() > 0.5) {
        fixDef.shape = new b2PolygonShape;
        fixDef.shape.SetAsBox(
          Math.random() + 0.1 //half width
          , Math.random() + 0.1 //half height
        );
      } else {
        fixDef.shape = new b2CircleShape(
          Math.random() + 0.1 //radius
        );
      }
      bodyDef.position.x = Math.random() * 10;
      bodyDef.position.y = Math.random() * 10;
      world.CreateBody(bodyDef).CreateFixture(fixDef);
    }

      注: 这边随机创建了10个圆形/矩形的物体
      • box2dweb的调试器(可视化)

    //setup debug draw
    var debugDraw = new b2DebugDraw();
    debugDraw.SetSprite(document.getElementById("canvas").getContext("2d"));
    debugDraw.SetDrawScale(30.0);
    debugDraw.SetFillAlpha(0.3);
    debugDraw.SetLineThickness(1.0);
    debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
    world.SetDebugDraw(debugDraw);

      注: DrawScale为物理世界和像素的比例值, 以及Sprite的canvas的2d上下文.
      • 事件驱动
      注册定时器, 定时更新. 而物理引擎的world.step函数是整个box2d的核心, 其模拟/驱动了物理世界的运行.

    window.setInterval(update, 1000 / 60);
    
    function update() {
      world.Step(
        1 / 60 //frame-rate
        , 10 //velocity iterations
        , 10 //position iterations
      );
      world.DrawDebugData();
      world.ClearForces();
    };

    总结:
      从这个sample代码中, 学习到了很多. 实践出真知, 希望自己作为一个html5er的初学者能快速成长.

    写在最后:
      
    如果你觉得这篇文章对你有帮助, 请小小打赏下. 其实我想试试, 看看写博客能否给自己带来一点小小的收益. 无论多少, 都是对楼主一种由衷的肯定.

       

  • 相关阅读:
    【Luogu】P1402 酒店之王 题解
    CSP/S 2019 游记
    【Luogu】P1306 斐波那契公约数 题解
    【Luogu】P1072 Hankson 的趣味题 题解
    字符串函数
    对数换底公式
    round(x,y)和format(x,y)
    约束和索引
    复合主键对外键的影响
    外键
  • 原文地址:https://www.cnblogs.com/mumuxinfei/p/4535664.html
Copyright © 2011-2022 走看看