http://blog.sina.com.cn/s/blog_441c62380101i1wz.html
2,在世界里添加刚体(B)
还剩下添加地板,把砖块改成动态刚体的,先来考虑一下玩偶,如果玩偶的形状非圆非方怎么办。玩偶是 Totem Destroyer 游戏的主角,我们不能只用一个盒子草草了事,这样会对不起游戏里的角色的。
我想玩偶的形状应该如下
这就是我想到的玩偶,我们要用 Box2D创建它。左手边是玩偶轮廓,右手边是填充好的玩偶。
你首先注意到的是,这个玩偶是由许多个刚体一起组成了一个复合刚体,记住Box2D只对凸多边形产生作用,跟那些单一盒子状的木条是不一样的。我们需要把所有的玩偶对象用同样的方法混合。
我们先从竖直的盒子开始, 在最后一个brick 方法后调用它。
public function Main() {
world=new b2World(new b2Vec2(0,5),true);
debugDraw();
brick(275,435,30,30);
brick(365,435,30,30);
brick(320,405,120,30);
brick(320,375,60,30);
brick(305,345,90,30);
brick(320,300,120,60);
idol(320,242);
addEventListener(Event.ENTER_FRAME,updateWorld);
}
我们在 idol 方法里创建玩偶:
private function idol(pX:Number,pY:Number):void {
var bodyDef:b2BodyDef=new b2BodyDef();
bodyDef.position.Set(pX/worldScale,pY/worldScale);
var polygonShape:b2PolygonShape=new b2PolygonShape();
polygonShape.SetAsBox(5/worldScale,20/worldScale);
var fixtureDef:b2FixtureDef=new b2FixtureDef();
fixtureDef.shape=polygonShape;
fixtureDef.density=1;
fixtureDef.restitution=0.4;
fixtureDef.friction=0.5;
var theIdol:b2Body=world.CreateBody(bodyDef);
theIdol.CreateFixture(fixtureDef);
}
现在已经创建了一个新的盒子状图形,和之前建立的木条是一样的。
测试影片将会看到玩偶的身子:
玩偶的第二部分是在身子底部叠上一个十字交叉,相交叉的部分是由两个盒子状组成的,只不过他们都逆时针的旋转45度。
Creating an oriented box shape
想要创建一个定向的盒子形状,我们使用一个跟SetAsBox 类似的方法b2PolygonShape,你也可以使用更高级的 SetAsOrientedBox 方法。
参数是盒子的全长和全宽,盒子的中心点,还要定义一个b2Vec2对象和旋转弧度。
1,根据上面所说的, idol 方法这样接着写下去:
var bW:Number=5/worldScale;
var bH:Number=20/worldScale;
var boxPos:b2Vec2=new b2Vec2(0,10/worldScale);
var boxAngle:Number=- Math.PI/4;
前两行定义了盒子的大小,第三行定义了位置,你或许有些疑问,玩偶的第一个盒子刚体的位置是(320,242),为什么玩偶的第二个盒子刚体在(0,10)位置,他不应该离第一个盒子更近一点吗?
这就是你要学习的神奇的复合对象,这里的位置不是绝对位置,而是相对于第一个盒子的相对位置。
所以这一行的意思是:第二个盒子会被放置在第一个盒子中心点下方一点点的地方。
最后一行指明弧度为逆时针45度。
2,根据这四个变量,你可以如下所示调用 SetAsOrientedBox 方法。
polygonShape.SetAsOrientedBox(bW,bH,boxPos,boxAngle);
3,然后更新 fixture shape
fixtureDef.shape=polygonShape;
4,哈,好神奇,我们把 fixture 连接到现有的 theIdol 刚体上了。
theIdol.CreateFixture(fixtureDef);
5,把同样的部分应用到另外一个盒子上去,只需要改变 boxAngle变量:
boxAngle=Math.PI/4;
6,创建定向盒子,更新 fixture shape,把它添加到theIdol 刚体。
polygonShape.SetAsOrientedBox(bW.bH,boxPos,boxAngle);
fixtureDef.shape=polygonShape;
theIdol.CreateFixture(fixtureDef);
7,最后,完整的idol 方法如下所示:
private function idol(pX:Number,pY:Number):void{
var bodyDef:b2BodyDef=new b2BodyDef();
bodyDef.position.Set(pX/worldScale,pY/worldScale);
var polygonShape:b2PolygonShape=new b2PolygonShape();
polygonShape.SetAsBox(5/worldScale,20/worldScale);
var fixtureDef:b2FixtureDef=new b2FixtureDef();
fixtureDef.shape=polygonShape;
fixtureDef.density=1;
fixtureDef.restitution=0.4;
fixtureDef.friction=0.5;
var theIdol:b2Body=world.CreateBody(bodyDef);
theIdol.CreateFixture(fixtureDef);
var bW:Number=5/worldScale;
var bH:Number=20/worldScale;
var boxPos:b2Vec2=new b2Vec2(0,10/worldScale);
var boxAngle:Number=-Math.PI/4;
polygonShape.SetAsOrientedBox(bW,bH,boxPos,boxAngle);
fixtureDef.shape=polygonShape;
theIdol.CreateFixture(fixtureDef);
boxAngle=Math.PI/4;
polygonShape.SetAsOrientedBox(bW,bH,boxPos,boxAngle);
fixtureDef.shape=polygonShape;
theIdol.CreateFixture(fixtureDef);
}
8,测试影片:
现在开始创建它的头部
这次,你自己独立完成吧,说到底他只是另一个定向盒子,这个玩偶对象的一部分,我会教你另外一种方法去解决这个问题,用一种特别厉害的方法去键多边形。
创建任意多边形
Box2D允许你创建任意多边形,只要这个多边形是凸多边形,也就是说所有的内角都小于180度,所以
所有的顶点都远离中心点,还有你提供的点要是顺时针方向。
1,首先新建一个 vector 来存储所有的向量:
var vertices:Vector.=new Vector.();
2,然后把所有的顶点以 b2Vec2 对象顺时针顺序放入数组,他们的位置是相对于人偶中心点的相对位置,
vertices.push(new b2Vec2(-15/worldScale,-25/worldScale));
vertices.push(new b2Vec2(0,-40/worldScale));
vertices.push(new b2Vec2(15/worldScale,-25/worldScale));
vertices.push(new b2Vec2(0,-10/worldScale));
3,上面的几行代码写的是玩偶头的部分的四个向量,现在把这些向量转化成多边形。
polygonShape.SetAsVector(vertices,4)
SetAsVector 方法把vector中的向量顺时针排成一个多变形,第二个参数是需要使用的顶点个数。
4,最后了,通常你需要更新 fixture shape 并把它添加到theIdol刚体上:
fixtureDef.shape=polygonShape;
theIdol.CreateFixture(fixtureDef);
5,idol方法如下所示:
private function idol(pX:Number,pY:Number):void{
var bodyDef:b2BodyDef=new b2BodyDef();
bodyDef.position.Set(pX/worldScale,pY/worldScale);
var polygonShape:b2PolygonShape=new b2PolygonShape();
polygonShape.SetAsBox(5/worldScale,20/worldScale);
var fixtureDef:b2FixtureDef=new b2FixtureDef();
fixtureDef.shape=polygonShape;
fixtureDef.density=1;
fixtureDef.restitution=0.4;
fixtureDef.friction=0.5;
var theIdol:b2Body=world.CreateBody(bodyDef);
theIdol.CreateFixture(fixtureDef);
var bW:Number=5/worldScale;
var bH:Number=20/worldScale;
var boxPos:b2Vec2=new b2Vec2(0,10/worldScale);
var boxAngle:Number=-Math.PI/4;
polygonShape.SetAsOrientedBox(bW,bH,boxPos,boxAngle);
fixtureDef.shape=polygonShape;
theIdol.CreateFixture(fixtureDef);
boxAngle=Math.PI/4;
polygonShape.SetAsOrientedBox(bW,bH,boxPos,boxAngle);
fixtureDef.shape=polygonShape;
theIdol.CreateFixture(fixtureDef);
var vertices:Vector.=new Vector.();
vertices.push(new b2Vec2(-15/worldScale,
-25/worldScale));
vertices.push(new b2Vec2(0,-40/worldScale));
vertices.push(new b2Vec2(15/worldScale,
-25/worldScale));
vertices.push(new b2Vec2(0,-10/worldScale));
polygonShape.SetAsVector(vertices,4);
fixtureDef.shape=polygonShape;
theIdol.CreateFixture(fixtureDef);
}
6,测试影片,玩偶站在最上面的木条上:
7,现在你需要创建一个地板,一个静态的盒子(用 floor 方法表示):
public function Main() {
world=new b2World(new b2Vec2(0,5),true);
debugDraw();
brick(275,435,30,30);
brick(365,435,30,30);
brick(320,405,120,30);
brick(320,375,60,30);
brick(305,345,90,30);
brick(320,300,120,60);
idol(320,242);
floor();
addEventListener(Event.ENTER_FRAME,updateWorld);
}
8,floor 方法如下所示:
private function floor():void {
var bodyDef:b2BodyDef=new b2BodyDef();
bodyDef.position.Set(320/worldScale,465/worldScale);
var polygonShape:b2PolygonShape=new b2PolygonShape();
polygonShape.SetAsBox(320/worldScale,15/worldScale);
var fixtureDef:b2FixtureDef=new b2FixtureDef();
fixtureDef.shape=polygonShape;
fixtureDef.restitution=0.4;
fixtureDef.friction=0.5;
var theFloor:b2Body=world.CreateBody(bodyDef);
theFloor.CreateFixture(fixtureDef);
}
9,把木条转化成动态刚体,注释去掉:
private function
brick(pX:int,pY:int,w:Number,h:Number):void {
var bodyDef:b2BodyDef=new b2BodyDef();
bodyDef.position.Set(pX/worldScale,pY/worldScale);
bodyDef.type=b2Body.b2_dynamicBody;
var polygonShape:b2PolygonShape=new b2PolygonShape();
polygonShape.SetAsBox(w/2/worldScale,h/2/worldScale);
var fixtureDef:b2FixtureDef=new b2FixtureDef();
fixtureDef.shape=polygonShape;
fixtureDef.density=2;
fixtureDef.restitution=0.4;
fixtureDef.friction=0.5;
var theBrick:b2Body=world.CreateBody(bodyDef);
theBrick.CreateFixture(fixtureDef);
}
10,最后,把idol 也改成动态刚体:
private function idol(pX:Number,pY:Number):void {
var bodyDef:b2BodyDef=new b2BodyDef();
bodyDef.position.Set(pX/worldScale,pY/worldScale);
bodyDef.type=b2Body.b2_dynamicBody;
var polygonShape:b2PolygonShape=new b2PolygonShape();
polygonShape.SetAsBox(5/worldScale,20/worldScale);
var fixtureDef:b2FixtureDef=new b2FixtureDef();
fixtureDef.shape=polygonShape;
fixtureDef.density=1;
fixtureDef.restitution=0.4;
fixtureDef.friction=0.5;
var theIdol:b2Body=world.CreateBody(bodyDef);
theIdol.CreateFixture(fixtureDef);
var bW:Number=5/worldScale;
var bH:Number=20/worldScale;
var boxPos:b2Vec2=new b2Vec2(0,10/worldScale);
var boxAngle:Number=- Math.PI/4;
polygonShape.SetAsOrientedBox(bW,bH,boxPos,boxAngle);
fixtureDef.shape=polygonShape;
theIdol.CreateFixture(fixtureDef);
boxAngle=Math.PI/4;
polygonShape.SetAsOrientedBox(bW,bH,boxPos,boxAngle);
fixtureDef.shape=polygonShape;
theIdol.CreateFixture(fixtureDef);
var vertices:Vector.=new Vector.();
vertices.push(new b2Vec2(-15/worldScale,
-25/worldScale));
vertices.push(new b2Vec2(0,-40/worldScale));
vertices.push(new b2Vec2(15/worldScale,
-25/worldScale));
vertices.push(new b2Vec2(0,-10/worldScale));
polygonShape.SetAsVector(vertices,4);
fixtureDef.shape=polygonShape;
theIdol.CreateFixture(fixtureDef);
}
正如本章开始所说,你将会使用Box2d写一个真正的游戏,这才刚开始。
本章结束啦,下章再见。
总结
本章是这本书里重要的章节之一,如何创建刚体,怎样使用它们来设计游戏关卡,想要使用更多的Box2D刚体,我建议你创建更多关的 Totem Destroye游戏或者像 Red Removeer ,Angry Bird游戏,言而总之,总而言之,就是处理各种形状啦。