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标签,代码如下:

<!DOCTYPE HTML>
<html><head><title>Box2DWeb Test</title><scripttype="text/javascript"src="js/Box2dWeb-2.1.a.3.min.js"></script><scripttype="text/javascript" src="js/game.js"></script></head><bodyοnlοad="init();"><canvasid="canvas" width="640" height="480"style="background-color:#333333;"></canvas></body>
</html>

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

function init() {
// Commen code for usingBox2D object.var b2Vec2 =Box2D.Common.Math.b2Vec2;var b2AABB =Box2D.Collision.b2AABB;var b2BodyDef =Box2D.Dynamics.b2BodyDef;var b2Body =Box2D.Dynamics.b2Body;varb2FixtureDef = Box2D.Dynamics.b2FixtureDef;var b2Fixture =Box2D.Dynamics.b2Fixture;var b2World =Box2D.Dynamics.b2World;varb2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape;
var b2DebugDraw =Box2D.Dynamics.b2DebugDraw;
/* 下文添加 */
};

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

// Get canvas fordrawing.
var canvas =document.getElementById("canvas");
var canvasPosition =getElementPosition(canvas);
var context =canvas.getContext("2d");// World constants.
var worldScale = 30;
var dragConstant=0.05;
var dampingConstant = 2;
var world = newb2World(new b2Vec2(0, 10),true);document.addEventListener("mousedown",onMouseDown);
debugDraw();
window.setInterval(update,1000/60);

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

// Create bottom wall
createBox(640,30,320,480,b2Body.b2_staticBody,null);
// Create top wall
createBox(640,30,320,0,b2Body.b2_staticBody,null);
// Create left wall
createBox(30,480,0,240,b2Body.b2_staticBody,null);
// Create right wall
createBox(30,480,640,240,b2Body.b2_staticBody,null);functioncreateBox(width,height,pX,pY,type,data){var bodyDef = new b2BodyDef;bodyDef.type = type;bodyDef.position.Set(pX/worldScale,pY/worldScale);bodyDef.userData=data;var polygonShape = new b2PolygonShape;polygonShape.SetAsBox(width/2/worldScale,height/2/worldScale);var fixtureDef = new b2FixtureDef;fixtureDef.density = 1.0;fixtureDef.friction = 0.5;fixtureDef.restitution = 0.5;fixtureDef.shape = polygonShape;var body=world.CreateBody(bodyDef);body.CreateFixture(fixtureDef);
}

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

function onMouseDown(e) {var evt = e||window.event;createArrow(e.clientX-canvasPosition.x,e.clientY-canvasPosition.y);
}function createArrow(pX,pY) {// Set the left corner as the originalpoint.var angle = Math.atan2(pY-450, pX);// Define the shape of arrow.var vertices = [];vertices.push(new b2Vec2(-1.4,0));vertices.push(new b2Vec2(0,-0.1));vertices.push(new b2Vec2(0.6,0));vertices.push(newb2Vec2(0,0.1));var bodyDef = new b2BodyDef;bodyDef.type = b2Body.b2_dynamicBody;bodyDef.position.Set(40/worldScale,400/worldScale);bodyDef.userData = "Arrow";var polygonShape = new b2PolygonShape;polygonShape.SetAsVector(vertices,4);var fixtureDef = new b2FixtureDef;fixtureDef.density = 1.0;fixtureDef.friction = 0.5;fixtureDef.restitution = 0.5;fixtureDef.shape = polygonShape;var body = world.CreateBody(bodyDef);body.CreateFixture(fixtureDef);// Set original state of arrow.body.SetLinearVelocity(newb2Vec2(20*Math.cos(angle), 20*Math.sin(angle)));body.SetAngle(angle);body.SetAngularDamping(dampingConstant);}

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

function debugDraw() {var debugDraw = new b2DebugDraw();debugDraw.SetSprite(document.getElementById("canvas").getContext("2d"));debugDraw.SetDrawScale(worldScale);debugDraw.SetFillAlpha(0.5);debugDraw.SetLineThickness(1.0);debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);world.SetDebugDraw(debugDraw);
}function update() { world.Step(1/60,10,10);world.ClearForces();for(var b = world.m_bodyList; b != null; b = b.m_next){if(b.GetUserData() === "Arrow") {updateArrow(b);}}world.DrawDebugData();
}

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

functionupdateArrow(arrowBody) {// Calculate arrow's fligth speed.var flightSpeed =Normalize2(arrowBody.GetLinearVelocity());// Calculate arrow's pointingdirection.var bodyAngle = arrowBody.GetAngle();var pointingDirection = new b2Vec2(Math.cos(bodyAngle),-Math.sin(bodyAngle));// Calculate arrow's flightingdirection and normalize it.var flightAngle =Math.atan2(arrowBody.GetLinearVelocity().y,arrowBody.GetLinearVelocity().x);var flightDirection = newb2Vec2(Math.cos(flightAngle), Math.sin(flightAngle));// Calculate dot production.var dot = b2Dot( flightDirection,pointingDirection );var dragForceMagnitude = (1 -Math.abs(dot)) * flightSpeed * flightSpeed * dragConstant *arrowBody.GetMass();var arrowTailPosition =arrowBody.GetWorldPoint(new b2Vec2( -1.4, 0 ) );arrowBody.ApplyForce( newb2Vec2(dragForceMagnitude*-flightDirection.x,dragForceMagnitude*-flightDirection.y),arrowTailPosition );
}function b2Dot(a, b) {return a.x * b.x + a.y * b.y;
}function Normalize2(b) {return Math.sqrt(b.x * b.x + b.y *b.y);
}

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

//http://js-tut.aardon.de/js-tut/tutorial/position.html
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};
}

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

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

[HTML5]使用Box2dWeb模拟飞行箭矢相关推荐

  1. [HTML5]使用Box2dWeb模拟射箭效果并添加能量槽

    上次已实现箭矢的飞行效果,但是箭在碰到墙壁时直接反弹回来,像钢棍而不是箭.在Box2d中,可以利用关节(Joint)将箭和靶子连接起来,组成一个整体,实现射击效果.使用关节要在文件开头添加新的变量,方 ...

  2. android 模拟飞行,安卓版模拟飞行 X Plane 9试玩

    2004年的圣诞节那天,我垂头丧气地坐在我家的廉价电脑前,盯着那老式的CRT显示器屏幕.我都不知道电脑里的模拟飞行游戏是正在安装,还是已经卡死了.电脑主机在桌子下面嗡嗡嗡地响,都快带不动这个庞然大物般 ...

  3. matlab如何模拟竹蜻蜓飞行,JSBSim_Matlab 将 与 进行联合仿真 模拟飞行计算 247万源代码下载- www.pudn.com...

    文件名称: JSBSim_Matlab下载  收藏√  [ 5  4  3  2  1 ] 开发工具: Visual C++ 文件大小: 7092 KB 上传时间: 2015-07-26 下载次数: ...

  4. 微软模拟飞行2020服务器多少内存,《微软模拟飞行2020》配置公开,想玩爽还需玩家加大投入...

    作为众多硬核玩家在2020年最为期待的游戏之一,<微软模拟飞行2020>的所有细节公开都广受关注.要知道,这款游戏除了具有顶级的画面外,其对全球航线.机场和即使天气的模拟演算都堪称专业级. ...

  5. visual studio 代码提示_《微软模拟飞行2020》代码暗示下一代Xbox或支持VR

    (映维网 2020年10月24日)<微软模拟飞行2020>已经开始内测VR功能,并且将头显支持范围扩大到支持3Glasses S2等.但更令社区感到兴奋的是,PC游戏的代码变化引起了人们对 ...

  6. 模拟飞行 android,RFS模拟飞行pro安卓版

    RFS模拟飞行pro安卓版是一款十分真实的飞行与驾驶体验,在这里更多的危险也即将要发生了,充满了危机的时刻.更加真实的冒险也在等待你的完成哦,属于你的热血游戏与体验模式,全新的与充满了危险的时刻也在等 ...

  7. 盲僧一键r闪用什么设置_美加狮R.A.T. PRO X3至尊版带你畅玩模拟飞行

    很多模拟飞行或者皇牌空战的玩家们都追求在游戏过程中的真实驾驶体验,渴望通过游戏来实现自己的飞行梦.但普通鼠标的左右键及滚轮并不能带给玩家逼真的体验,美加狮全新发布的鼠标R.A.T. PRO X3至尊版 ...

  8. 运用卫星数据及AI技术 微软推出新一代模拟飞行游戏

    在E3 2019游戏展上,微软展示了将于2020年推出的新一代<Microsoft Flight Simulator>游戏.借助卫星数据和最新的AI技术,图片看起来非常令人印象深刻. 自2 ...

  9. 8in1模拟器v2模拟飞行_重新想象飞行模拟器:过去和现在

    8in1模拟器v2模拟飞行 本文是Microsoft的Web开发系列的一部分. 感谢您支持使SitePoint成为可能的合作伙伴. Apple于1980年推出了Flight Simulator的第一个 ...

最新文章

  1. 第一个python程序:定义,列表,元组,集合,求并集交集,键和值,运算符,缩进
  2. telegram 内联模式 介绍
  3. boost::geometry::model::segment用法的测试程序
  4. 匿名函数的简单理解和应用
  5. go generate 生成代码
  6. 【Qt开发】关于QWSServer
  7. Chrome无法使用Unity Web Player的解决方案
  8. 软件测试简历中的项目应该如何准备?
  9. 法语语法学习笔记——代词(1)
  10. 做人最大的无知,是错把平台当本事(深度好文)
  11. 欢迎来怼--第三十六次Scrum会议
  12. AUTOCAD绘制3D家具有感
  13. Java中类对象为空是什么意思?
  14. Webstorm2018激活和汉化详细步骤
  15. Google Earth Engine (GEE) ——Earth Engine Explorer (EE Explorer)使用最全解析(8000字长文)
  16. 《墨水心》(Inkheart)
  17. 服务器系统进不了路由器,Win7输入192.168.0.1打不开路由器管理界面的解决方法
  18. 学习,使用主成分分析 (Principal components analysis,PCA)处理数据必看文章
  19. 2.Echarts柱状图最详解析及示例
  20. 大数据时代的伦理道德

热门文章

  1. OpenCV-通道分离cv::split
  2. linux 输入法错误,Ubuntu 16.04安装搜狗拼音输入法错误问题的解决方法
  3. ecshop 支持 php,ecshop支持PHP7的修改方法
  4. 单元测试框架-Junit
  5. angular 解决闪烁问题_AngularJS页面访问时出现页面闪烁问题的解决
  6. java反射最佳实践_Java 反射最佳实践 – 码农网
  7. java对mysql进行查找替换_java对mysql的增删改查
  8. win10添加环境变量后没用_python 学习之在 win10 下安装 Anaconda
  9. Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks
  10. python中局部变量使用