在Egret中使用Box2D
昨天我们一起认识了Egret白鹭引擎,一个源自于ActionScript的HTML5游戏引擎,可以让有ActionScript经验的开发者轻松制作出HTML5游戏。作为Box2D的忠实粉丝,拉登大叔想到的第一件事,就是将Egret和Box 2D结合起来,开发物理游戏,好啦,闲话少说我们马上开始。
Typescript版的Box2D
因为Egret是基于Typescript语言的,所以为了实现与Egret的完美结合,我们需要使用Typescript版本的Box2D,这一点并不难,在github上搜索Box2D可以很轻松的找到TS版的Box2Dweb,地址如下:
https://github.com/borisyankov/DefinitelyTyped/tree/master/box2d
它是由ActionScript版Box2D 2.1转译过来的,因此在使用起来可以完全参考本站中的Box2D教程。接下来是将TS版本的Box2D导入到你的Egret项目中啦。(先不要下载,后面我会进行说明)
导入Box2D
我们知道,在ActionScript中通过设置项目属性中,可以添加外部类库的引用。在Egret中也是类似的,但是因为Egret项目目前没有自己的IDE,无法通过可视化窗口设置对类库的引用,只能通过项目文件夹下的egretProperties.json文件来设置。具体可以参考官方文档:Egret 与第三方 TypeScript / JavaScript 库集成
http://docs.egret-labs.org/post/manual/threelibs/uselibs.html
不过说实话,官方的文档有不少坑的,还是看我的图文教程吧。
大体过程是这样的:
- 将类库文件粘贴到项目中,Egret官方文档中推荐放置在src文件夹下,但我个人总不习惯将类库放在src源代码目录下,所有自己进件了一个myLibs的文件夹(不要放在libs文件夹下,有可能会导致编译错误)。这里的类库文件包括两个,一个是原生的js文件,另一个是以d.ts结尾的,对原生js文件API进行声明的.ts文件。另外还有一个.json的类库配置文件。如下图所示:
- 为了Egret项目可以正确的引用第3放类库,项目配置文件B和类库配置文件A中的内容,需要遵循一定的规则,具体如下图所示:
- 类库配置文件A.json文件中,各个属性说明如下:
- name:编译后类库文件将保存到libs文件夹的以该属性值命名的Box2dFolder子文件夹下。
- dependence:需要引用的类库。这里保持不变。
- source:源文件存放的目录,“.”表示当前目录。
- file_list:此模块包括的所有代码,需要包括全部 js 文件、ts 文件以及js文件所对应的.d.ts文件
- 按照上图编辑好项目配置文件egretProperties.json文件和类库配置文件A.json,在命令提示符中输入 egret build -e,编译项目类库引用。
编译完成后,我们就可以基于Egret编写Box2D物理应用啦。
需要特别说明的是,JS版Box2DWeb中的SetSprite调试试图是一个CanvasRenderingContext2D对象,这是canvas对象的一个属性,如以下代码所示:
debugDraw.SetSprite(document.GetElementsByTagName("canvas")[0].getContext("2d"));
而Egret本身也是基于canvas进行渲染的,这样会导致Box2D调试试图会覆盖Egret的渲染内容。拉登大叔基于Egret的Sprite对象,修改了JS版Box2DWeb中的调试试图的渲染方法,我们可以像ActionScript版本Box2Dweb一样,直接用Sprite对象来渲染调试试图,修改后代码如下:
var s:egret.Sprite = new egret.Sprite(); this.addChild(s); this.debug.SetSprite(s);
修改后的Box2D对应的js和ts文件,请点击下面的链接进行下载。
示例说明
好了,闲话少说,我们来看一看示例。下面的示例中,舞台上会随机创建20个尺寸不一的矩形,自由下落,当他们落到地面时,会很自然的进行反弹和碰撞。点击图片查看动态效果:
对应的源代码如下,点击下载源文件
class Main extends egret.DisplayObjectContainer { public constructor() { super(); this.addEventListener(egret.Event.ADDED_TO_STAGE, this.onAddToStage, this); } private world:Box2D.Dynamics.b2World; private debug:Box2D.Dynamics.b2DebugDraw; private p2m:number = 30; private onAddToStage(event:egret.Event) { var sWidth:number = this.stage.stageWidth; var sHeight:number = this.stage.stageHeight; this.createWorld(); this.createDebug(); for(var i:number = 0;i<20;i++){ this.createBox(Math.random()*300+50,Math.random()*200+50,Math.random()*30+10,Math.random()*30+10); } this.createBox(sWidth/2,sHeight,sWidth,10,true); this.createBox(sWidth/2,0,sWidth,10,true); this.createBox(0,sHeight/2,10,sHeight,true); this.createBox(sWidth,sHeight/2,10,sHeight,true); this.addEventListener(egret.Event.ENTER_FRAME,this.loop,this); } private createBox(posX:number,posY:number,w:number,h:number,isStatic:boolean=false){ var bodyDef:Box2D.Dynamics.b2BodyDef = new Box2D.Dynamics.b2BodyDef(); bodyDef.position = new Box2D.Common.Math.b2Vec2(posX/this.p2m,posY/this.p2m); bodyDef.type = Box2D.Dynamics.b2Body.b2_dynamicBody; if(isStatic) { bodyDef.type = Box2D.Dynamics.b2Body.b2_staticBody; } var body:Box2D.Dynamics.b2Body = this.world.CreateBody(bodyDef); var poly:Box2D.Collision.Shapes.b2PolygonShape; poly = Box2D.Collision.Shapes.b2PolygonShape.AsBox(w/this.p2m,h/this.p2m); var fixtureDef:Box2D.Dynamics.b2FixtureDef = new Box2D.Dynamics.b2FixtureDef(); fixtureDef.density = 3; fixtureDef.restitution = 0.2; fixtureDef.shape = poly; body.CreateFixture(fixtureDef); } private createWorld(){ var gravity:Box2D.Common.Math.b2Vec2 = new Box2D.Common.Math.b2Vec2(0,10); this.world = new Box2D.Dynamics.b2World(gravity,true); } private createDebug(){ var s:egret.Sprite = new egret.Sprite(); this.addChild(s); this.debug = new Box2D.Dynamics.b2DebugDraw(); this.debug.SetSprite(s); this.debug.SetDrawScale(30); this.debug.SetLineThickness(1); this.debug.SetAlpha(0.8); this.debug.SetFillAlpha(0.5); this.debug.SetFlags(Box2D.Dynamics.b2DebugDraw.e_shapeBit); this.world.SetDebugDraw(this.debug); } private loop(e:egret.Event){ this.world.Step(1/60,10,10); this.world.DrawDebugData(); } }
代码与ActionScript中类似,我就不进行过多的讲解了,如果你对Box2D还不太熟悉,请参考我们之前的教程。
http://www.ladeng6666.com/blog/category/box2d/page/5/
只是需要注意的是,在声明变量指定变量类型时,必须使用完整的包名称,如:
private world:Box2D.Dynamics.b2World;
我至今还是很不习惯。
不过,我试过在微信和手机浏览器中打开上面的示例,二维码如下:
运行效果不是很流畅,所以本文也只是抛砖引玉,向大家介绍Egret与Box2D的搭配使用。同时也期待Egret官方团队能够找到更高效的物理引擎解决方案。
联系作者
用Egret当然卡,有没有试过box2djs,这个好很多,https://code.google.com/p/box2dweb/
第三方的 类库 d.ts去哪弄 ,难道要自己写?
在Github上搜索,应有尽有!
拉登大神,有没有box2dweb的教程,你的书籍如果再有一本box2dweb的就好了,因为我想用H5开发游戏!
H5我现在用Egret + p2,预计年底出版的Egret书中,会有详细的教程,谢谢支持!
我用demo 在egret 时
var gravity:Box2D.Common.Math.b2Vec2 = new Box2D.Common.Math.b2Vec2(0,10);
报 Box2DBox2D is not defined 是什么原因拉登大叔
类库引用错误,我这个教程里,egret的版本比较老了,具体参考一下egret官方类库导入的文档
egret里面创建不了圆形刚体啊,大佬