Egret-Box2d (一)
按照官方文档学习的记录,由于文档是英文的,所以本文中的截图都是经过百度翻译过的,box2d github地址:https://github.com/flyover/box2d.ts

首先要创建一个放置物体的地方,也就是box2dWorld,简称为b2World,其中x和y就是重力的大小和方向了,y:10也就是重力加速度。
this.world = new b2World({ x: 0, y: 10 });
有了世界还需要有地面,这里就涉及到单位转换了,box2d使用的是MKS单位,也就是米、千克、秒,并不是我们常用的px(像素),由百度可知,1 米=30 像素。
let groundBodyDef = new b2BodyDef();
groundBodyDef.position.Set(0, 300 / 30);//此处就是把300像素转换成10米
groundBodyDef.type = b2BodyType.b2_staticBody;//地面是不会动的,所以设置为静态的
上面的只是对物体进行定义,然后开始创建一个物体
let groundBody = this.world.CreateBody(groundBodyDef);
接下来是对物体的形状进行设置
let groundBox = new b2PolygonShape();//这是个矩形
groundBox.SetAsBox(500 / 2 / 30, 30 / 2 / 30);
//这里有个500 / 2 / 30,是不是感觉很诡异?
根据官方文档解释,SetAsBox的参数是半宽半高,所以要除以2,后面的除以30是单位转换

然后给物体添加上这个形状,后面的1是这个物体的密度,因为物体都是有密度的,所以不写的话可能会出现奇怪的bug,这个方法还有其他的重载,所以密度写在其他地方也可以
groundBody.CreateFixture(groundBox, 1);
然后地面就创建好了,不过运行起来还是什么都看不到的,因为box2d不自带渲染,然后我也找不到合适的b2debugdraw,我也不想自己写,就先用egret做个矩形吧
let rect = new egret.Sprite();
rect.graphics.beginFill(Math.random() * 0xffffff);
rect.graphics.drawRect(0, 0, 500, 30);
rect.graphics.endFill();
rect.anchorOffsetX = 500 / 2;
rect.anchorOffsetY = 30 / 2;
rect.x=0;
rect.y=300;
groundBodyDef.userData = rect;//这里的userData用于存一些东西
this.addChild(rect);
然后运行起来就能发现创建的地面了

然后我们来创建一个牛顿的苹果,还是上面的操作,只是把静态改成动态了。
let appleDef = new b2BodyDef();
appleDef.type = b2BodyType.b2_dynamicBody;//动态的
appleDef.position.Set(30 / 30, 30 / 30);
因为苹果可以受到力的影响,所以要给他添加一下材质(也叫夹具),就是密度、摩擦、形状等。
let fixDef = new b2FixtureDef();//这个就是材质
let appleShape = new b2PolygonShape();
appleShape.SetAsBox(50 / 2 / 30, 50 / 2 / 30);
fixDef.shape = appleShape;
fixDef.density = 1.0;//这个就是之前提到过的密度
fixDef.friction = 0.3;//这个是摩擦
fixDef.restitution = 0.2;//掉在地上弹起来的效果
this.world.CreateBody(appleDef).CreateFixture(fixDef);//添加到世界中
然后为了方便实用,把之前那个创建矩形(egret的那个)封装一下
createRect(x, y, width, height) {
let rect = new egret.Sprite();
rect.graphics.beginFill(Math.random() * 0xffffff);
rect.graphics.drawRect(0, 0, width, height);
rect.graphics.endFill();
rect.anchorOffsetX = width / 2;
rect.anchorOffsetY = height / 2;
rect.x = x;
rect.y = y;
return rect;
}
然后让苹果显示出来
appleDef.userData = this.createRect(30, 30, 50, 50);
this.addChild(appleDef.userData);
这是我们运行一下,会发现苹果是掉不下来的,因为我们还没有把box2d启动起来
//在合适的地方添加监听
this.addEventListener(egret.Event.ENTER_FRAME, this.loop, this);
//每帧调用这个方法
loop() {
this.world.Step(1 / 60, 6, 2);
for (var bodyIndex: b2Body = this.world.GetBodyList(); bodyIndex; bodyIndex = bodyIndex.GetNext()) {
if (bodyIndex.m_userData != null) {
bodyIndex.m_userData.x = bodyIndex.GetPosition().x * 30
bodyIndex.m_userData.y = bodyIndex.GetPosition().y * 30
bodyIndex.m_userData.rotation = bodyIndex.GetAngle() * 180 / Math.PI;
}
}
}
上面的Step中的第一个参数是时间步长,1 / 60相当于六十分之一秒执行一次,也就是60hz,后边那两个参数为什么写6和2,就看官网的解释吧。

后面的for循环就是遍历每一个物体,并改变他的位置和角度,注意box2d用的是弧度制,不是角度值,而且还要进行单位的转换。
效果图

还可以添加多个


box2d 文档地址:https://box2d.org/documentation/md__d_1__git_hub_box2d_docs_hello.html