使用Box2dWeb模拟飞行箭矢

来源:互联网 发布:欢乐麻将淘宝怎么回事 编辑:程序博客网 时间:2024/04/28 15:25
 

[HTML5]使用Box2dWeb模拟飞行箭矢

标签: HTML5Box2d游戏
 3287人阅读 评论(0) 收藏 举报
 分类:
 

Box2d是一个2D游戏物理引擎,由Erin Catto开发,于2007年发布。很多2D游戏都用过Box2d,其中最有名的自然是愤怒的小鸟。Box2d本身是C++编写,但在不同平台都有它的衍生版本,像Flash版的Box2dFlash,JS版的Box2dJS和Box2dWeb。最近偶然看到一篇使用Box2dFlash模拟箭矢飞行效果的文章:

http://www.emanueleferonato.com/2012/12/10/flying-arrows-simulation-with-box2d/

很有意思,想尝试使用下Box2d。

之前从没接触过Flash,选择JS版的Box2d,而Box2dJS已经很久没更新,所以使用Box2dWeb重写箭矢飞行效果。

网上有不少Box2d教程,不过介绍其应用的多些。对于Box2d基本概念和原理,推荐阿蕉的博客,他将Box2d C++的系列教程译成中文。虽然C++和JS不同,但是Box2d原理是相通的,可以参考。

http://blog.csdn.net/wen294299195/article/category/1227604

首先下载Box2dWeb

https://code.google.com/p/box2dweb/downloads/list

压缩包里只有四个文件,这里只需要Box2dWeb-2.1.a.3.min.js(也可以用Box2dWeb-2.1.a.3.js,方便了解Box2DWeb的各个函数)。

按照下面的目录结构创建各个文件即可:

|-js/

| |-Box2dWeb-2.1.a.3.min.js

| |-game.js

|-arrow.html

编辑arrow.html,引用javascript文件并创建一个canvas标签,代码如下:

[html] view plain copy
 print?
  1. <!DOCTYPE HTML>  
  2. <html>  
  3.     <head>  
  4.        <title>Box2DWeb Test</title>  
  5.         <scripttypescripttype="text/javascript"src="js/Box2dWeb-2.1.a.3.min.js"></script>  
  6.         <scripttypescripttype="text/javascript" src="js/game.js"></script>  
  7.     </head>  
  8.    
  9.     <bodyonloadbodyonload="init();">  
  10.         <canvasidcanvasid="canvas" width="640" height="480"style="background-color:#333333;"></canvas>  
  11.     </body>  
  12. </html>  

接下来编辑game.js。从arrow.html中可以看到,页面载入后调用init方法模拟整个过程,添加下面的代码:

[javascript] view plain copy
 print?
  1. function init() {  
  2. // Commen code for usingBox2D object.  
  3.     var b2Vec2 =Box2D.Common.Math.b2Vec2;  
  4.     var b2AABB =Box2D.Collision.b2AABB;  
  5.     var b2BodyDef =Box2D.Dynamics.b2BodyDef;  
  6.     var b2Body =Box2D.Dynamics.b2Body;  
  7.     varb2FixtureDef = Box2D.Dynamics.b2FixtureDef;  
  8.     var b2Fixture =Box2D.Dynamics.b2Fixture;  
  9.     var b2World =Box2D.Dynamics.b2World;  
  10.     varb2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape;  
  11. var b2DebugDraw =Box2D.Dynamics.b2DebugDraw;  
  12. /* 下文添加 */  
  13. };  

以上代码是为了方便使用Box2d中的对象。接着就是设置全局属性,像canvas的大小、Box2d的世界参数、鼠标消息响应方法等。

[javascript] view plain copy
 print?
  1. // Get canvas fordrawing.  
  2. var canvas =document.getElementById("canvas");  
  3. var canvasPosition =getElementPosition(canvas);  
  4. var context =canvas.getContext("2d");  
  5.      
  6. // World constants.  
  7. var worldScale = 30;  
  8. var dragConstant=0.05;  
  9. var dampingConstant = 2;  
  10. var world = newb2World(new b2Vec2(0, 10),true);  
  11.      
  12. document.addEventListener("mousedown",onMouseDown);  
  13. debugDraw();              
  14. window.setInterval(update,1000/60);  

设置好Box2d的世界之后就可以放置各种模型。接下来的代码创建四面墙壁来封闭区域:

[javascript] view plain copy
 print?
  1. // Create bottom wall  
  2. createBox(640,30,320,480,b2Body.b2_staticBody,null);  
  3. // Create top wall  
  4. createBox(640,30,320,0,b2Body.b2_staticBody,null);  
  5. // Create left wall  
  6. createBox(30,480,0,240,b2Body.b2_staticBody,null);  
  7. // Create right wall  
  8. createBox(30,480,640,240,b2Body.b2_staticBody,null);  
  9.    
  10. functioncreateBox(width,height,pX,pY,type,data){  
  11.     var bodyDef = new b2BodyDef;  
  12.     bodyDef.type = type;  
  13.     bodyDef.position.Set(pX/worldScale,pY/worldScale);  
  14.     bodyDef.userData=data;  
  15.    
  16.     var polygonShape = new b2PolygonShape;  
  17.     polygonShape.SetAsBox(width/2/worldScale,height/2/worldScale);  
  18.    
  19.     var fixtureDef = new b2FixtureDef;  
  20.     fixtureDef.density = 1.0;  
  21.     fixtureDef.friction = 0.5;  
  22.     fixtureDef.restitution = 0.5;  
  23.     fixtureDef.shape = polygonShape;  
  24.          
  25.     var body=world.CreateBody(bodyDef);  
  26.     body.CreateFixture(fixtureDef);  
  27. }  

希望点击鼠标时,从左下角向鼠标点击的位置发射一支箭。所以在鼠标点击消息的响应方法中调用createArrow方法,根据传入的坐标生成一支箭,并赋给它初速度,代码如下:

[javascript] view plain copy
 print?
  1. function onMouseDown(e) {  
  2.     var evt = e||window.event;  
  3.     createArrow(e.clientX-canvasPosition.x,e.clientY-canvasPosition.y);  
  4. }  
  5.    
  6. function createArrow(pX,pY) {  
  7.     // Set the left corner as the originalpoint.  
  8.     var angle = Math.atan2(pY-450, pX);  
  9.    
  10.     // Define the shape of arrow.  
  11.     var vertices = [];  
  12.     vertices.push(new b2Vec2(-1.4,0));  
  13.     vertices.push(new b2Vec2(0,-0.1));  
  14.     vertices.push(new b2Vec2(0.6,0));  
  15.     vertices.push(newb2Vec2(0,0.1));  
  16.    
  17.     var bodyDef = new b2BodyDef;  
  18.     bodyDef.type = b2Body.b2_dynamicBody;  
  19.     bodyDef.position.Set(40/worldScale,400/worldScale);  
  20.     bodyDef.userData = "Arrow";  
  21.    
  22.     var polygonShape = new b2PolygonShape;  
  23.     polygonShape.SetAsVector(vertices,4);  
  24.    
  25.     var fixtureDef = new b2FixtureDef;  
  26.     fixtureDef.density = 1.0;  
  27.     fixtureDef.friction = 0.5;  
  28.     fixtureDef.restitution = 0.5;  
  29.     fixtureDef.shape = polygonShape;  
  30.          
  31.     var body = world.CreateBody(bodyDef);  
  32.     body.CreateFixture(fixtureDef);  
  33.    
  34.     // Set original state of arrow.  
  35.     body.SetLinearVelocity(newb2Vec2(20*Math.cos(angle), 20*Math.sin(angle)));  
  36.     body.SetAngle(angle);  
  37.     body.SetAngularDamping(dampingConstant);  
  38.  }  

接下来就是系统方法,绘制物体并定时更新:

[javascript] view plain copy
 print?
  1. function debugDraw() {  
  2.     var debugDraw = new b2DebugDraw();  
  3.     debugDraw.SetSprite(document.getElementById("canvas").getContext("2d"));  
  4.     debugDraw.SetDrawScale(worldScale);  
  5.     debugDraw.SetFillAlpha(0.5);  
  6.     debugDraw.SetLineThickness(1.0);  
  7.     debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);  
  8.     world.SetDebugDraw(debugDraw);  
  9. }  
  10.       
  11. function update() {   
  12.     world.Step(1/60,10,10);  
  13.     world.ClearForces();  
  14.   
  15.     for(var b = world.m_bodyList; b != null; b = b.m_next){  
  16.        if(b.GetUserData() === "Arrow") {  
  17.                 updateArrow(b);  
  18.             }  
  19.     }  
  20.           
  21.     world.DrawDebugData();  
  22. }  

注意上面update方法中调用的updateArrow方法,它负责模拟箭矢在空中运动形态,让整个过程更加真实。

[javascript] view plain copy
 print?
  1. functionupdateArrow(arrowBody) {  
  2.     // Calculate arrow's fligth speed.  
  3.     var flightSpeed =Normalize2(arrowBody.GetLinearVelocity());  
  4.    
  5.     // Calculate arrow's pointingdirection.  
  6.     var bodyAngle = arrowBody.GetAngle();  
  7.     var pointingDirection = new b2Vec2(Math.cos(bodyAngle),-Math.sin(bodyAngle));  
  8.    
  9.     // Calculate arrow's flightingdirection and normalize it.  
  10.     var flightAngle =Math.atan2(arrowBody.GetLinearVelocity().y,arrowBody.GetLinearVelocity().x);  
  11.     var flightDirection = newb2Vec2(Math.cos(flightAngle), Math.sin(flightAngle));  
  12.    
  13.     // Calculate dot production.  
  14.     var dot = b2Dot( flightDirection,pointingDirection );  
  15.     var dragForceMagnitude = (1 -Math.abs(dot)) * flightSpeed * flightSpeed * dragConstant *arrowBody.GetMass();  
  16.     var arrowTailPosition =arrowBody.GetWorldPoint(new b2Vec2( -1.4, 0 ) );  
  17.     arrowBody.ApplyForce( newb2Vec2(dragForceMagnitude*-flightDirection.x,dragForceMagnitude*-flightDirection.y),arrowTailPosition );  
  18. }  
  19.    
  20. function b2Dot(a, b) {  
  21.     return a.x * b.x + a.y * b.y;  
  22. }  
  23.    
  24. function Normalize2(b) {  
  25.     return Math.sqrt(b.x * b.x + b.y *b.y);  
  26. }  

最后是getElementPosition方法,用于获得canvas的偏移坐标:

[javascript] view plain copy
 print?
  1. //http://js-tut.aardon.de/js-tut/tutorial/position.html  
  2. function getElementPosition(element) {  
  3.     var elem=element, tagname="",x=0, y=0;  
  4.     while((typeof(elem) =="object") && (typeof(elem.tagName) != "undefined")){  
  5.         y += elem.offsetTop;  
  6.         x += elem.offsetLeft;  
  7.         tagname = elem.tagName.toUpperCase();  
  8.         if(tagname == "BODY"){  
  9.             elem=0;  
  10.         }  
  11.         if(typeof(elem) =="object"){  
  12.             if(typeof(elem.offsetParent) =="object"){  
  13.                 elem = elem.offsetParent;  
  14.             }  
  15.         }  
  16.     }  
  17.     return {x: x, y: y};  
  18. }  

程序的运行结果(Chrome 25.0.1323.1下测试)如下图所示:


源代码下载地址:http://download.csdn.net/detail/raymondcode/5151381

0 0