天天看點

[javascript] Box2D JS初探(一個控制小球的遊戲例子)。學習用!

 Box2D 開源實體引擎,第一次接觸,主要用途應該是做遊戲,不過也可以作些簡單的頁面特性,比如切割粉碎。拖動帶彈性系數。

從寫了個控制小球運動,可以方向鍵控制左右和彈跳,碰到障礙物就死掉的DEMO來試試。

示範位址: null

[javascript] Box2D JS初探(一個控制小球的遊戲例子)。學習用!

這裡注意的是,市面上有box2d JS 和 box2d Web2種js版本,有些小夥伴用老的box2d JS,那就不是這麼寫的了非常麻煩,而且box2d js不更新了,不建議學習使用。

<html>
   <head>
      <title>Box2dWeb example</title>
   </head>
   <body οnlοad="init();">
      <img id="tulip" style="display: none" src="33.jpg" alt="The Tulip" />
      <canvas id="canvas" width="900" height="600"></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
		,	b2MouseJointDef = Box2D.Dynamics.Joints.b2MouseJointDef
		,	b2WeldJointDef = Box2D.Dynamics.Joints.b2WeldJointDef
            ;
         
         world = new b2World(
               new b2Vec2(0,10)    //gravity  重力的方向,力度 機關牛,10就是重力加速度G
            ,  true                //allow sleep
         );
         
         var fixDef = new b2FixtureDef; //剛體建立
         fixDef.density = 1.0;    //密度
         fixDef.friction = 0.5;   //摩擦力 加大了之後正方形被推動就比較不容易動
         fixDef.restitution = 0.8;  //彈性系數,1應該就是不衰減,大于1反而越來越快
         
         var bodyDef = new b2BodyDef;
         
         //create ground
         bodyDef.type = b2Body.b2_staticBody;
         bodyDef.position.x = 1;  //機關是米,一米是30像素。
         bodyDef.position.y = 19.8;
	 //以下試圖建立四邊框(用剛體來做,遊戲四邊的場景邊框,不然會掉出去)
         fixDef.shape = new b2PolygonShape;
         fixDef.shape.SetAsBox(30, 0.1);   //長寬應該(寬長,xy對應)
         world.CreateBody(bodyDef).CreateFixture(fixDef);
         fixDef.shape.SetAsBox(0.1, 20);
         bodyDef.position.Set(0.1, 0.1);
         world.CreateBody(bodyDef).CreateFixture(fixDef);
	 fixDef.shape.SetAsBox(30, 0.1);
         bodyDef.position.Set(0.1, 0.1);
         world.CreateBody(bodyDef).CreateFixture(fixDef);
	 fixDef.shape.SetAsBox(0.1, 20);
         bodyDef.position.Set(29.8, 0.1);
         world.CreateBody(bodyDef).CreateFixture(fixDef);
	 //在場景中制作台階
	 fixDef.shape.SetAsBox(3, 0.1);
	 bodyDef.position.Set(10, 18.5);
         world.CreateBody(bodyDef).CreateFixture(fixDef);
	 
	 var mouseX, mouseY,selectBody, keyBoll,vX, vY,keyVelocity,Death = false,barrier;
         var canvasPosition = getElementPosition(document.getElementById("canvas"));
	 var context = document.getElementById("canvas").getContext("2d");
	 var img=document.getElementById("tulip");
	 //在場景中的空中放置一個正方形
	 bodyDef.type = b2Body.b2_dynamicBody;
	 fixDef.shape = new b2PolygonShape();
         fixDef.shape.SetAsBox(1,1); //30px * 30px 的矩形
	 fixDef.restitution = 2;  //改變彈性系數,如果撞到他會更快的反彈
	 bodyDef.position.Set(10,13); //矩形陷阱的放置位置
	 console.log(fixDef.shape.GetVertices() );
	 console.log(typeof fixDef.shape.GetVertices()[0] );
         selectBody = world.CreateBody(bodyDef).CreateFixture(fixDef).GetBody();
	 //建個連結器。把矩形固定在場景中
	 var jointDef = new b2MouseJointDef();
	 jointDef.bodyA = world.GetGroundBody(); 
         jointDef.bodyB = selectBody;
	 //矩形和場景本體相連
         jointDef.target.Set(10, 13);
	 //連接配接位置
         jointDef.collideConnected = true;
	 //是否碰撞。要碰。不然就是根線,不能固定用
         jointDef.maxForce = 3000.0;
	 //最大力,如果設定過小,會被從固定位置撞開
	 world.CreateJoint(jointDef);
	 //連接配接器加入世界
	 // 建立釘子
	 fixDef.restitution = 0;
	 fixDef.friction = 5000
	 fixDef.shape = new b2PolygonShape;
	 var vArray = [new b2Vec2(0,-0.5),new b2Vec2(0.25,0.5),new b2Vec2(-0.25,0.5)]
	 fixDef.shape.SetAsVector(vArray, 3);
	 //建立一個三角形這裡要注意了,Vector字面是向量,其實穿進去的是三角形頂點坐标List,3是頂點個數。而且要順時針方向,不然無法實體判定。
	 bodyDef.position.Set(15,19.5);
	 barrier = world.CreateBody(bodyDef).CreateFixture(fixDef).GetBody();
	 //建立連接配接,這個WeldJoint看字面就知道,是剛體連接配接,上面那個連接配接會被力改變,會旋轉。這個就是焊死了。相當于固定
	 jointDef = new b2WeldJointDef();
	 jointDef.bodyA = world.GetGroundBody();
	 jointDef.bodyB = barrier;
	 jointDef.localAnchorA = new b2Vec2(15, 19.3)
	 jointDef.localAnchorB = barrier.GetLocalCenter();
         jointDef.collideConnected = true;
         
	 world.CreateJoint(jointDef);
	 //建立主角--一個球 
	 fixDef.restitution = 0.8;
	 fixDef.shape = new b2CircleShape(1);
	 bodyDef.position.Set(1,19.5);
	 bodyDef.userData=img;
	 //給球上圖檔
         keyBoll = world.CreateBody(bodyDef).CreateFixture(fixDef).GetBody();
	 //把這個球的body記錄下來。
	 /**
	 這裡是點選小球在滑鼠位置降落下來的 監聽。
	 document.addEventListener("mousedown", function(e) {
	    mouseX = (e.layerX - canvasPosition.x) / 30;
            mouseY = (e.layerY - canvasPosition.y) / 30; 
         }, true);
	 
	 
	 document.addEventListener("mouseup", function(e) {
	    fixDef.shape = new b2CircleShape(0.5);
	    bodyDef.position.Set(mouseX,mouseY);
            selectBody = world.CreateBody(bodyDef).CreateFixture(fixDef).GetBody();
	    vX = (e.layerX - canvasPosition.x) / 30 - mouseX;
	    vY = (e.layerY - canvasPosition.y) / 30 - mouseY;
	    selectBody.ApplyImpulse( new b2Vec2(vX*5,vY*5), selectBody.GetLocalCenter());
         }, true);
	 **/
	 
	 //監控鍵盤事件
	 document.addEventListener("keydown", function(e) {
	    var theEvent = window.event || e;
	    var code = theEvent.keyCode || theEvent.which;
	    console.log(code);
	    var keyVelocity = keyBoll.GetLinearVelocity();
	    //按上方向鍵:
	    if(code==38){
	       //判定是不是y方向速度為0 ,我要球落地挺穩才讓他繼續下一次起跳,不然會越來越高。
	      if (keyVelocity.y == 0) {
	       //給一個y方向20的向上加速度。算下10的重力。應該也就2秒就下落了。
	       keyBoll.ApplyImpulse(new b2Vec2(0,-20), keyBoll.GetWorldCenter());
	      }
	    }
	    //左按鍵
	    if(code==37){
	      keyBoll.SetAwake(true);
	      //喚醒目标,并直接給向左10的速度,這裡和上不一樣,是直接替換速度,并不是加速度,是以Y方向的速度還需要加入。
	      keyBoll.SetLinearVelocity(new b2Vec2(-10,keyVelocity.y), keyBoll.GetWorldCenter());
	    }
	    //右按鍵
	    if(code==39){
	      keyBoll.SetAwake(true);
	      //同理
	      keyBoll.SetLinearVelocity(new b2Vec2(10,keyVelocity.y), keyBoll.GetWorldCenter());
	    }
 
         }, false);
	 //監聽按鍵彈起,并給個減速(也可以直接熟讀至0)看個人喜好。
	 document.addEventListener("keyup", function(e) {
	    var theEvent = window.event || e;
	    var code = theEvent.keyCode || theEvent.which;
	    console.log(code);
	    if(code==37){
	      keyBoll.ApplyImpulse(new b2Vec2(10,0), keyBoll.GetWorldCenter());
	    }
	    if(code==39){
	      keyBoll.ApplyImpulse(new b2Vec2(-10,0), keyBoll.GetWorldCenter());
	    }
	   
         }, false);
	 
         //setup debug draw
         var debugDraw = new b2DebugDraw();
			debugDraw.SetSprite(document.getElementById("canvas").getContext("2d"));
			debugDraw.SetDrawScale(30.0);
			debugDraw.SetFillAlpha(0.3);
			debugDraw.SetLineThickness(2.0);
			debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
			world.SetDebugDraw(debugDraw);
         
         window.setInterval(update, 1000 / 60); //配置偵數
	 
	 
	 
	 //官網的例子裡的一個canvans定位函數
         function getElementPosition(element) {
            var elem=element, tagname="", x=0, y=0;
           
            while((typeof(elem) == "object") && (typeof(elem.tagName) != "undefined")) {
               y += elem.offsetTop;
               x += elem.offsetLeft;
               tagname = elem.tagName.toUpperCase();

               if(tagname == "BODY")
                  elem=0;

               if(typeof(elem) == "object") {
                  if(typeof(elem.offsetParent) == "object")
                     elem = elem.offsetParent;
               }
            }

            return {x: x, y: y};
         }
	 
	 function update() {
	   
	 var a = 1 / 60;
	 //如果2個球被被喚醒了,并且球和釘子在一定範圍内,則說明撞到釘子了。GameOver 并且把重新整理率置99999,表示不動了。
	 if (barrier.IsAwake() && keyBoll.IsAwake()) {
	    if (barrier.GetPosition().x + 2 > keyBoll.GetPosition().x && barrier.GetPosition().x - 2 < keyBoll.GetPosition().x ) {
	       alert("Game Over");
	       a = 999999;
	    }
	    console.log(barrier.GetPosition());
	    console.log(keyBoll.GetPosition()); 
	 }
         world.Step(
               a   //frame-rate
            ,  10      //velocity iterations 
            ,  10      //position iterations
         );
         world.DrawDebugData();
	 //貼圖
	 context.save();
	 context.translate(keyBoll.GetPosition().x*30,keyBoll.GetPosition().y*30);
	 context.rotate(keyBoll.GetAngle());
	 context.drawImage(keyBoll.GetUserData(),-keyBoll.GetUserData().width/2,-keyBoll.GetUserData().height/2);
	 context.restore(); 
         world.ClearForces();
      };
      };
      
      
   
   </script>
   
   
</html>
           

繼續閱讀