之前我们知道了如何创建标准几何体刚体及其外观,此教程主要解决如何创建复杂刚体的问题。Box2D使用多边形拼接形成复杂的外观。通过前面的教程我们知道使用下面两句来创建一个刚体。
b2Body = b2World.createBody(b2BodyDef)
b2Body.createFixture(b2FixtureDef)
对于复杂刚体,b2Body和b2BodyDef还是一个,即始终是一个刚体,我们通过FixtureDef来实现多个多边形拼接,即创建多个b2FixtureDef,并多次执行
b2Body.createFixture(b2FixtureDef)
如果,鱼缸通过若干个四边形拼接而成
而b2FixtureDef的shape属性需要提供一个多边形b2PolygonShape,此多边形可使用下面方法来创建。
b2PolygonShape.setAsArray(veticesArray)
此方法需要一个b2Vec2对象的数组,此数组每一个元素决定了一个顶点,数组元素的顺序按照顺时针排序(必须)。
具体实现代码
1 private var _container:b2Body;
2 [Embed(source="./assets/container.png")]
3 public var ContainerImg:Class;
4
5 //添加容器的外观,并对齐好
6 private function addContainerTexture():void
7 {
8 var img:Bitmap = new ContainerImg();
9 this.addChild(img);
10
11 //调整图片的位置
12 img.x = 43;
13 img.y = 3;
14 }
15 private function createContainer():void
16 {
17 //容器的所有顶点组成的三维数组
18 //第一维度是一个多边形
19 //第二维度是多边形中的四个顶点
20 //第三维度是每个顶点的x,y坐标
21 var shapeCoords:Array = [
22 [[61,55],[77,67],[39,135],[23,124]],
23 [[23,124],[39,135],[25,220],[6,218]],
24 [[6,218],[25,220],[44,305],[28,312]],
25 [[28,312],[44,305],[94,372],[82,384]],
26 [[82,384],[94,372],[167,413],[161,425]],
27 [[161,425],[167,413],[250,424],[250,437]],
28 [[250,438],[250,424],[339,416],[341,429]],
29
30 [[341,430],[339,416],[411,383],[418,393]],
31 [[418,393],[411,383],[464,327],[478,334]],
32 [[478,334],[464,327],[489,254],[504,252]],
33 [[504,252],[489,254],[488,183],[504,177]],
34 [[504,177],[488,183],[470,112],[488,103]],
35 [[488,103],[470,112],[443,66],[465,63]],
36 [[77,67],[72,46],[436,43],[443,66]]
37 ];
38 //创建一个刚体定义
39 var bodyDef:b2BodyDef = new b2BodyDef();
40 bodyDef.type = b2Body.b2_staticBody;
41 bodyDef.position.Set(20 / PIXEL_TO_METER, -10/PIXEL_TO_METER);
42 //创建刚体
43 _container = world.CreateBody(bodyDef);
44 //为刚体创建修饰物
45 //传递顶点数组作为参数
46 createFixtrues(shapeCoords);
47 }
48 //创建Fixtures
49 //根据顶点数组的第一维度,创建多个Fixture
50 private function createFixtrues(coords:Array):void
51 {
52 for(var i:int = 0; i<coords.length; i++)
53 {
54 var shape:b2PolygonShape = new b2PolygonShape();
55 //调用创建顶点方法,将数组的第二维度作为参数
56 //返回一个顶点数组,用于创建shape
57 var shapeVertices:Array = createVerticesArray(coords[i]);
58 shape.SetAsArray(shapeVertices);
59 var shapeFixtureDef:b2FixtureDef = new b2FixtureDef();
60 shapeFixtureDef.shape = shape;
61 shapeFixtureDef.density = 1;
62 shapeFixtureDef.restitution = 1.0;
63 _container.CreateFixture(shapeFixtureDef);
64 }
65 }
66
67 //创建顶点数组
68 private function createVerticesArray(coords:Array):Array
69 {
70 //不能少于三个顶点
71 if(coords.length < 3)
72 {
73 throw new Error("Shape create wrong");
74 }
75 var vertices:Array = new Array();
76 //遍历顶点数组的第二维度,生成b2Vec2数组
77 for (var i:int = 0; i<coords.length ; i++)
78 {
79 var vertice:b2Vec2 = new b2Vec2(coords[i][0]/PIXEL_TO_METER, coords[i][1]/PIXEL_TO_METER);
80 vertices.push(vertice);
81 }
82
83 return vertices;
84
85 }
那么,为什么我们不一下子创建所有的顶点,然后按顺时针顺序连接起来,形成一个整体的多边形?
因为Box2D边框不允许凹进去,而鱼缸内边框是弯曲的向内凹,所有无法进行正确的碰撞检测。
那么多顶点,我们要怎么获取那么精确呢?
我是这么做的,不确定是否最简,我用的还算方便。借助Photoshop,首先把鱼缸边缘没有用的像素全部裁切掉,然后打开信息面板,将鼠标指到相应的位置,便显示该位置的坐标,将坐标记下就可以。最后把裁切后鱼缸保存作为外观图片,这样正好能够对上。