Box2dの学习超级积木小游戏制作

挺早之前看到过的小游戏,超级积木2,在开心网、QQ校友、空间传得挺多的,闲来没事就试着把它做出来,感觉还挺简单的,就仅仅使用了Box2D引擎中的创建刚体而已

 

点击这里下载源码


游戏规则就是把所有的积木摆放在舞台上并保持10S不倒下就算过关了

 

要制作一个Box2D游戏,最重要的还是了解它的运作机制

 

代码
 
   
1 package
2 {
3 import Box2D.Collision.b2AABB;
4 import Box2D.Collision.Shapes.b2PolygonDef;
5 import Box2D.Common.Math.b2Vec2;
6 import Box2D.Dynamics.b2Body;
7 import Box2D.Dynamics.b2BodyDef;
8 import Box2D.Dynamics.b2DebugDraw;
9 import Box2D.Dynamics.b2World;
10 import flash.display.Sprite;
11 import flash.events.Event;
12 import flash.events.KeyboardEvent;
13 import flash.events.MouseEvent;
14 /* *
15 * ...
16 * @description HelloWorld
17 * @author ispooky
18 * @date 2010.11.15
19 *
20 * @see http://ispooky.cnblogs.com
21 */
22
23 public class HelloWorldApp extends Sprite
24 {
25 // 缩放比例
26 public static const RATIO : int = 30 ;
27 // 时间步
28 public static const ITERATIONS : int = 30 ;
29 // 迭代次数
30 public static const TIME_STEP :Number = 1 / 30 ;
31
32 // 物理空间
33 private static var world :b2World;
34 // Debug绘制容器
35 private static var spriteToDrawOn :Sprite;
36
37 public function HelloWorldApp()
38 {
39 if (stage) init();
40 else addEventListener(Event.ADDED_TO_STAGE, init);
41 }
42
43 private function init(e:Event = null ): void
44 {
45 removeEventListener(Event.ADDED_TO_STAGE, init);
46
47 initB2D();
48 stage.addEventListener(MouseEvent.CLICK, onClickHandler);
49 stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDownHandler);
50 }
51
52 private function onKeyDownHandler(e:KeyboardEvent): void
53 {
54 if (e.keyCode == 82 /* R */ )
55 {
56 /// //
57 // 销毁Body
58 /// //
59 for (var bb:b2Body = world.m_bodyList; bb; bb = bb.m_next)
60 {
61 if ( ! bb.IsStatic()) { world.DestroyBody(bb) };
62 }
63 }
64 }
65
66 private function onClickHandler(e:MouseEvent): void
67 {
68 if (world.GetBodyCount() > 30 ) return ;
69 createBoxs();
70 }
71
72 private function initB2D(): void
73 {
74 addEventListener(Event.ENTER_FRAME, onLoopHandler, false , 0 , true );
75 createWorld();
76 showDebug();
77 createGrounds();
78 createBoxs();
79 }
80
81 private function createBoxs(): void
82 {
83 var bodyDef:b2BodyDef;
84 var boxDef:b2PolygonDef;
85 var body:b2Body;
86
87 bodyDef = new b2BodyDef();
88 bodyDef.position.Set((( int (Math.random() * 200 ) - 100 ) + 275.0 ) / RATIO, - 100.0 / RATIO);
89 boxDef = new b2PolygonDef();
90 boxDef.SetAsBox( int ((Math.random() * 20 ) + 20 ) / RATIO / 2 , ( int (Math.random() * 20 ) + 20 ) / RATIO / 2 );
91 boxDef.density = 1 ;
92 boxDef.friction = 0.4 ;
93 boxDef.restitution = 0.1 ;
94
95 body = world.CreateBody(bodyDef);
96 body.CreateShape(boxDef);
97 body.SetMassFromShapes();
98 }
99
100 private function createGrounds(): void
101 {
102 var bodyDef:b2BodyDef;
103 var boxDef:b2PolygonDef;
104 var body:b2Body;
105
106 // 刚体定义
107 bodyDef = new b2BodyDef();
108 // 设置位置
109 bodyDef.position.Set( 275.0 / RATIO, 390.0 / RATIO);
110 // 形状定义
111 boxDef = new b2PolygonDef();
112 // 设置高宽
113 boxDef.SetAsBox( 550.0 / RATIO / 2 , 20.0 / RATIO / 2 );
114 // 密度,0为静态物
115 boxDef.density = 0 ;
116 // 摩擦力
117 boxDef.friction = 0.3 ;
118 // 弹力
119 boxDef.restitution = 0.2 ;
120
121 body = world.CreateBody(bodyDef);
122 body.CreateShape(boxDef);
123 // 计算质量,因此处为静态物,所以不需计算
124 // body.SetMassFromShapes();
125 }
126
127 private function showDebug(): void
128 {
129 spriteToDrawOn = new Sprite();
130 addChild(spriteToDrawOn);
131 var dbgDraw:b2DebugDraw = new b2DebugDraw();
132 // 绘制图形
133 dbgDraw.m_sprite = spriteToDrawOn;
134 // 缩放比例
135 dbgDraw.m_drawScale = RATIO;
136 // 填充线的颜色透明度
137 dbgDraw.m_alpha = 1.0 ;
138 // 填充区域的颜色透明度
139 dbgDraw.m_fillAlpha = 0.5 ;
140 // 线型粗细
141 dbgDraw.m_lineThickness = 1.0 ;
142 // 绘制图形位
143 dbgDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit;
144
145 world.SetDebugDraw(dbgDraw);
146 }
147
148 private function createWorld(): void
149 {
150 // 边界
151 var worldAABB:b2AABB = new b2AABB();
152 worldAABB.lowerBound.Set( - 3000 / RATIO, - 3000 / RATIO);
153 worldAABB.upperBound.Set( 3000 / RATIO, 3000 / RATIO);
154 // 重力
155 var gravity:b2Vec2 = new b2Vec2( 0 , 10 );
156 // 允许休眠
157 var doSleep:Boolean = true ;
158
159 world = new b2World(worldAABB, gravity, doSleep);
160 }
161
162 private function onLoopHandler(e:Event): void
163 {
164 if (world == null ) return ;
165 // 刷新物理空间
166 world.Step(TIME_STEP, ITERATIONS);
167 }
168
169 }
170
171 }

代码运行结果截图

代码运行结果

一般来讲,Box2D 的运作机制就是创建一个物理空间,然后往里边加刚体等东西,最后就是刷新模拟物理空间了。

具体为:

 

创建一个物理空间,区域b2AABB框,重力g值,是否允许休眠的布尔值

创建静态地面刚体:

刚体定义,设置位置,角度,阻尼,贴图等属性

形状定义,高宽,密度,摩擦力,弹力等属性

创建刚体

创建形状

计算质量

……

创建其它刚体,关节

……

刷新模拟物理空间

 

注:

Box2D的单位是米、千克和秒(MKS)。而Flash使用的是像素单位,缩放比例一般设置为1米=30像素,虽然是可以自己任意定义的。

刚体默认原点是在中心,贴图则在左上角

SetAsBox函数接收的是半个宽度和半个高度

静态物体的密度为0

贴图是添加到舞台上的,而不是物理空间

Box2D的角度使用的是弧度制

 

 

接下来所要实现的就是在特定位置生成特定的刚体

 

代码
 
   
1 package
2 {
3 import Box2D.Collision.b2AABB;
4 import Box2D.Collision.Shapes.b2CircleDef;
5 import Box2D.Collision.Shapes.b2PolygonDef;
6 import Box2D.Common.Math.b2Vec2;
7 import Box2D.Dynamics.b2Body;
8 import Box2D.Dynamics.b2BodyDef;
9 import Box2D.Dynamics.b2DebugDraw;
10 import Box2D.Dynamics.b2World;
11 import flash.display.Sprite;
12 import flash.events.Event;
13 import flash.events.KeyboardEvent;
14 import flash.events.MouseEvent;
15 import flash.system.IME;
16 /* *
17 * ...
18 * @description superStacker1
19 * @author ispooky
20 * @date 2010.11.15
21 *
22 * @see http://ispooky.cnblogs.com
23 */
24 public class superStacker1 extends Sprite
25 {
26 // 缩放比例
27   public static const RATIO : int = 30 ;
28 // 时间步
29   public static const ITERATIONS : int = 30 ;
30 // 迭代次数
31   public static const TIME_STEP :Number = 1 / 30 ;
32
33 // 物理空间
34   private static var world :b2World;
35 // Debug绘制容器
36   private static var spriteToDrawOn :Sprite;
37
38 // 提示MC
39   private var tip_mc:Sprite;
40 // 刚体类型 1 : 圆形,2 : 三角形, 3 : 矩形
41   private var now_type: int = 1 ;
42 private var now_width:Number = 40 ;
43 private var now_height:Number = 40 ;
44
45 public function superStacker1()
46 {
47 if (stage) init();
48 else addEventListener(Event.ADDED_TO_STAGE, init);
49 }
50
51 private function init(e:Event = null ): void
52 {
53 removeEventListener(Event.ADDED_TO_STAGE, init);
54 IME.enabled = false ;
55
56 initB2D();
57
58 tip_mc = new Sprite();
59 addChild(tip_mc);
60 stage.addEventListener(MouseEvent.MOUSE_DOWN, onDownHandler);
61 stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDownHandler);
62 }
63
64 private function onKeyDownHandler(e:KeyboardEvent): void
65 {
66 if (e.keyCode == 82 /* R */ )
67 {
68 for (var bb:b2Body = world.m_bodyList; bb; bb = bb.m_next)
69 {
70 if ( ! bb.IsStatic()) { world.DestroyBody(bb) };
71 }
72 }
73 }
74
75 private function onDownHandler(e:MouseEvent): void
76 {
77 now_type = int (Math.random() * 3 ) + 1 ;
78 tip_mc.graphics.clear();
79 tip_mc.graphics.beginFill( 0x900000 , 0.6 );
80 switch (now_type)
81 {
82 // 圆形
83   case 1 :
84 tip_mc.graphics.drawCircle( 0 , 0 , now_width * 0.5 );
85 break ;
86 // 三角形
87 case 2 :
88 tip_mc.graphics.moveTo( 0 , now_height * 0.5 );
89 tip_mc.graphics.lineTo(now_width * 0.5 , - now_height * 0.5 );
90 tip_mc.graphics.lineTo( - now_width * 0.5 , - now_height * 0.5 );
91 tip_mc.rotation = 180 ;
92 break ;
93 // 矩形
94 case 3 :
95 tip_mc.graphics.drawRect( - now_width * 0.5 , - now_height * 0.5 , now_width, now_height);
96 break ;
97 }
98 tip_mc.graphics.endFill();
99 tip_mc.x = mouseX;
100 tip_mc.y = mouseY;
101 stage.addEventListener(MouseEvent.MOUSE_MOVE, onMoveHandler);
102 stage.addEventListener(MouseEvent.MOUSE_UP, onUpHandler);
103 }
104
105 private function onUpHandler(e:MouseEvent): void
106 {
107 stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMoveHandler);
108 stage.removeEventListener(MouseEvent.MOUSE_UP, onUpHandler);
109 tip_mc.graphics.clear();
110 createBox(now_type);
111 }
112
113 private function onMoveHandler(e:MouseEvent): void
114 {
115 tip_mc.x = mouseX;
116 tip_mc.y = mouseY;
117 e.updateAfterEvent();
118 }
119
120 private function initB2D(): void
121 {
122 addEventListener(Event.ENTER_FRAME, onLoopHandler, false , 0 , true );
123 createWorld();
124 showDebug();
125 createGrounds();
126 }
127
128 private function createBox(value: int ): void
129 {
130 var bodyDef:b2BodyDef;
131 var boxDef:b2PolygonDef;
132 var circleDef:b2CircleDef;
133 var body:b2Body;
134
135 bodyDef = new b2BodyDef();
136 bodyDef.position.Set(mouseX / RATIO, mouseY / RATIO);
137 switch (value)
138 {
139 case 1 :
140 circleDef = new b2CircleDef();
141 circleDef.radius = now_width * 0.5 / RATIO;
142 circleDef.density = 1 ;
143 circleDef.friction = 0.1 ;
144 circleDef.restitution = 0.3 ;
145 body = world.CreateBody(bodyDef);
146 body.CreateShape(circleDef);
147 break ;
148 case 2 :
149 bodyDef.angle = 180 * (Math.PI / 180 );
150 boxDef = new b2PolygonDef();
151 boxDef.vertexCount = 3 ;
152 boxDef.vertices[ 0 ].Set(now_width * 0.5 / RATIO, - now_height * 0.5 / RATIO);
153 boxDef.vertices[ 1 ].Set( 0 , now_height * 0.5 / RATIO);
154 boxDef.vertices[ 2 ].Set( - now_width * 0.5 / RATIO, - now_height * 0.5 / RATIO);
155 boxDef.density = 1 ;
156 boxDef.friction = 0.3 ;
157 boxDef.restitution = 0.2 ;
158 body = world.CreateBody(bodyDef);
159 body.CreateShape(boxDef);
160 break ;
161 case 3 :
162 boxDef = new b2PolygonDef();
163 boxDef.SetAsBox(now_width / RATIO / 2 , now_height / RATIO / 2 );
164 boxDef.density = 1 ;
165 boxDef.friction = 0.4 ;
166 boxDef.restitution = 0.1 ;
167 body = world.CreateBody(bodyDef);
168 body.CreateShape(boxDef);
169 break ;
170 }
171 body.SetMassFromShapes();
172 }
173
174 private function createGrounds(): void
175 {
176 var bodyDef:b2BodyDef;
177 var boxDef:b2PolygonDef;
178 var body:b2Body;
179
180 // 刚体定义
181 bodyDef = new b2BodyDef();
182 // 设置位置
183 bodyDef.position.Set( 275.0 / RATIO, 250.0 / RATIO);
184 // 形状定义
185 boxDef = new b2PolygonDef();
186 // 设置高宽
187 boxDef.SetAsBox( 250.0 / RATIO / 2 , 20.0 / RATIO / 2 );
188 // 密度,0为静态物
189 boxDef.density = 0 ;
190 // 摩擦力
191 boxDef.friction = 0.3 ;
192 // 弹力
193 boxDef.restitution = 0.2 ;
194
195 body = world.CreateBody(bodyDef);
196 body.CreateShape(boxDef);
197 // 计算质量,因此处为静态物,所以不需计算
198 // body.SetMassFromShapes();
199 }
200
201 private function showDebug(): void
202 {
203 spriteToDrawOn = new Sprite();
204 addChild(spriteToDrawOn);
205 var dbgDraw:b2DebugDraw = new b2DebugDraw();
206 // 绘制图形
207 dbgDraw.m_sprite = spriteToDrawOn;
208 // 缩放比例
209 dbgDraw.m_drawScale = RATIO;
210 // 填充线的颜色透明度
211 dbgDraw.m_alpha = 1.0 ;
212 // 填充区域的颜色透明度
213 dbgDraw.m_fillAlpha = 0.5 ;
214 // 线型粗细
215 dbgDraw.m_lineThickness = 1.0 ;
216 // 绘制图形位
217 dbgDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit;
218
219 world.SetDebugDraw(dbgDraw);
220 }
221
222 private function createWorld(): void
223 {
224 // 边界
225 var worldAABB:b2AABB = new b2AABB();
226 worldAABB.lowerBound.Set( - 3000 / RATIO, - 3000 / RATIO);
227 worldAABB.upperBound.Set( 3000 / RATIO, 3000 / RATIO);
228 // 重力
229 var gravity:b2Vec2 = new b2Vec2( 0 , 10 );
230 // 允许休眠
231 var doSleep:Boolean = true ;
232
233 world = new b2World(worldAABB, gravity, doSleep);
234 }
235
236 private function onLoopHandler(e:Event): void
237 {
238 if (world == null ) return ;
239 // 刷新物理空间
240 world.Step(TIME_STEP, ITERATIONS);
241 }
242
243 }
244
245 }

代码运行结果

相比较HelloWorld而言,就是在生成刚体的时候设置了刚体定义的位置由鼠标位置确定,放在鼠标弹起事件时操作,同时刚体有了圆形、矩形、三角形三种,还有一个提示图形,没了

 

判断物体是否出界是该游戏是否结束的依据,在Event.Enter_Frame事件中添加以下代码就可以实现了,坐标判断

 

代码
 
   
1 for (var bb:b2Body = world.m_bodyList; bb; bb = bb.m_next)
2 {
3 if (bb.GetPosition().y * RATIO > stage.stageHeight)
4 {
5 tip_txt.text = ' 提示框:有物体离开舞台 ' + int (Math.random() * 100000 );
6 world.DestroyBody(bb);
7 }
8 }

任何时候都应该把没用的Body销毁掉

 

代码运行结果

 

 

再接着,添加滚动提示框跟游戏判断

 

代码
 
   
1 package
2 {
3 import Box2D.Collision.b2AABB;
4 import Box2D.Collision.Shapes.b2CircleDef;
5 import Box2D.Collision.Shapes.b2PolygonDef;
6 import Box2D.Common.Math.b2Vec2;
7 import Box2D.Dynamics.b2Body;
8 import Box2D.Dynamics.b2BodyDef;
9 import Box2D.Dynamics.b2DebugDraw;
10 import Box2D.Dynamics.b2World;
11 import flash.display.Shape;
12 import flash.display.Sprite;
13 import flash.events.Event;
14 import flash.events.KeyboardEvent;
15 import flash.events.MouseEvent;
16 import flash.system.IME;
17 import flash.text.TextField;
18 /* *
19 * ...
20 * @description superStacker3
21 * @author ispooky
22 * @date 2010.11.15
23 *
24 * @see http://ispooky.cnblogs.com
25 */
26 public class superStacker3 extends Sprite
27 {
28 // 缩放比例
29   public static const RATIO : int = 30 ;
30 // 时间步
31   public static const ITERATIONS : int = 30 ;
32 // 迭代次数
33   public static const TIME_STEP :Number = 1 / 30 ;
34
35 // 物理空间
36   private static var world :b2World;
37 // Debug绘制容器
38   private static var spriteToDrawOn :Sprite;
39
40 // 提示MC
41   private var tip_mc:Sprite;
42 // 刚体类型 1 : 圆形,2 : 三角形, 3 : 矩形
43   private var now_type: int = 1 ;
44 private var now_width:Number = 40 ;
45 private var now_height:Number = 40 ;
46
47 // 剩余物
48   private var remainder_arr:Array;
49 private var remainder_mc:Sprite;
50
51 public var tip_txt:TextField;
52 public function superStacker3()
53 {
54 if (stage) init();
55 else addEventListener(Event.ADDED_TO_STAGE, init);
56 }
57
58 private function init(e:Event = null ): void
59 {
60 removeEventListener(Event.ADDED_TO_STAGE, init);
61 IME.enabled = false ;
62
63 initB2D();
64 getRemainder();
65 tip_mc = new Sprite();
66 addChild(tip_mc);
67 stage.addEventListener(MouseEvent.MOUSE_DOWN, onDownHandler);
68 stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDownHandler);
69 }
70
71 private function getRemainder(): void
72 {
73 remainder_arr = getData();
74 if (remainder_mc != null ) { removeChild(remainder_mc) };
75 remainder_mc = getScrollTip(remainder_arr);
76 remainder_mc.x = 30 ;
77 remainder_mc.y = 30 ;
78 addChild(remainder_mc);
79 }
80
81 private function onKeyDownHandler(e:KeyboardEvent): void
82 {
83 if (e.keyCode == 82 /* R */ )
84 {
85 for (var bb:b2Body = world.m_bodyList; bb; bb = bb.m_next)
86 {
87 if ( ! bb.IsStatic()) { world.DestroyBody(bb) };
88 }
89 getRemainder();
90 tip_txt.text = ' 提示框: ' ;
91 }
92 }
93
94 private function onDownHandler(e:MouseEvent): void
95 {
96 if (remainder_arr.length <= 0 )
97 {
98 tip_txt.text = ' 所有物体都摆放了,成功过关 ' ;
99 return ;
100 }
101 now_type = remainder_arr[ 0 ].type;
102 tip_mc.graphics.clear();
103 tip_mc.graphics.beginFill( 0x900000 , 0.6 );
104 switch (now_type)
105 {
106 // 圆形
107   case 1 :
108 tip_mc.graphics.drawCircle( 0 , 0 , remainder_arr[ 0 ].width * 0.5 );
109 break ;
110 // 三角形
111   case 2 :
112 tip_mc.graphics.moveTo( 0 , remainder_arr[ 0 ].height * 0.5 );
113 tip_mc.graphics.lineTo(remainder_arr[ 0 ].width * 0.5 , - remainder_arr[ 0 ].height * 0.5 );
114 tip_mc.graphics.lineTo( - remainder_arr[ 0 ].width * 0.5 , - remainder_arr[ 0 ].height * 0.5 );
115 tip_mc.rotation = 180 ;
116 break ;
117 // 矩形
118   case 3 :
119 tip_mc.graphics.drawRect( - now_width * 0.5 , - now_height * 0.5 , now_width, now_height);
120 break ;
121 }
122 tip_mc.graphics.endFill();
123 tip_mc.x = mouseX;
124 tip_mc.y = mouseY;
125 stage.addEventListener(MouseEvent.MOUSE_MOVE, onMoveHandler);
126 stage.addEventListener(MouseEvent.MOUSE_UP, onUpHandler);
127 }
128
129 private function onUpHandler(e:MouseEvent): void
130 {
131 stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMoveHandler);
132 stage.removeEventListener(MouseEvent.MOUSE_UP, onUpHandler);
133 tip_mc.graphics.clear();
134 createBox(now_type);
135
136 remainder_arr.shift();
137 removeChild(remainder_mc);
138 remainder_mc = getScrollTip(remainder_arr);
139 remainder_mc.x = 30 ;
140 remainder_mc.y = 30 ;
141 addChild(remainder_mc);
142 }
143
144 private function onMoveHandler(e:MouseEvent): void
145 {
146 tip_mc.x = mouseX;
147 tip_mc.y = mouseY;
148 e.updateAfterEvent();
149 }
150
151 private function initB2D(): void
152 {
153 addEventListener(Event.ENTER_FRAME, onLoopHandler, false , 0 , true );
154 createWorld();
155 showDebug();
156 createGrounds();
157 }
158
159 private function createBox(value: int ): void
160 {
161 var bodyDef:b2BodyDef;
162 var boxDef:b2PolygonDef;
163 var circleDef:b2CircleDef;
164 var body:b2Body;
165
166 bodyDef = new b2BodyDef();
167 bodyDef.position.Set(mouseX / RATIO, mouseY / RATIO);
168 switch (value)
169 {
170 case 1 :
171 circleDef = new b2CircleDef();
172 circleDef.radius = now_width * 0.5 / RATIO;
173 circleDef.density = 1 ;
174 circleDef.friction = 0.1 ;
175 circleDef.restitution = 0.3 ;
176 body = world.CreateBody(bodyDef);
177 body.CreateShape(circleDef);
178 break ;
179 case 2 :
180 bodyDef.angle = 180 * (Math.PI / 180 );
181 boxDef = new b2PolygonDef();
182 boxDef.vertexCount = 3 ;
183 boxDef.vertices[ 0 ].Set(now_width * 0.5 / RATIO, - now_height * 0.5 / RATIO);
184 boxDef.vertices[ 1 ].Set( 0 , now_height * 0.5 / RATIO);
185 boxDef.vertices[ 2 ].Set( - now_width * 0.5 / RATIO, - now_height * 0.5 / RATIO);
186 boxDef.density = 1 ;
187 boxDef.friction = 0.3 ;
188 boxDef.restitution = 0.2 ;
189 body = world.CreateBody(bodyDef);
190 body.CreateShape(boxDef);
191 break ;
192 case 3 :
193 boxDef = new b2PolygonDef();
194 boxDef.SetAsBox(now_width / RATIO / 2 , now_height / RATIO / 2 );
195 boxDef.density = 1 ;
196 boxDef.friction = 0.4 ;
197 boxDef.restitution = 0.1 ;
198 body = world.CreateBody(bodyDef);
199 body.CreateShape(boxDef);
200 break ;
201 }
202 body.SetMassFromShapes();
203 }
204
205 private function createGrounds(): void
206 {
207 var bodyDef:b2BodyDef;
208 var boxDef:b2PolygonDef;
209 var body:b2Body;
210
211 // 刚体定义
212   bodyDef = new b2BodyDef();
213 // 设置位置
214   bodyDef.position.Set( 275.0 / RATIO, 250.0 / RATIO);
215 // 形状定义
216   boxDef = new b2PolygonDef();
217 // 设置高宽
218   boxDef.SetAsBox( 250.0 / RATIO / 2 , 20.0 / RATIO / 2 );
219 // 密度,0为静态物
220   boxDef.density = 0 ;
221 // 摩擦力
222 boxDef.friction = 0.3 ;
223 // 弹力
224 boxDef.restitution = 0.2 ;
225
226 body = world.CreateBody(bodyDef);
227 body.CreateShape(boxDef);
228 // 计算质量,因此处为静态物,所以不需计算
229 // body.SetMassFromShapes();
230 }
231
232 private function showDebug(): void
233 {
234 spriteToDrawOn = new Sprite();
235 addChild(spriteToDrawOn);
236 var dbgDraw:b2DebugDraw = new b2DebugDraw();
237 // 绘制图形
238 dbgDraw.m_sprite = spriteToDrawOn;
239 // 缩放比例
240 dbgDraw.m_drawScale = RATIO;
241 // 填充线的颜色透明度
242 dbgDraw.m_alpha = 1.0 ;
243 // 填充区域的颜色透明度
244 dbgDraw.m_fillAlpha = 0.5 ;
245 // 线型粗细
246 dbgDraw.m_lineThickness = 1.0 ;
247 // 绘制图形位
248 dbgDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit;
249
250 world.SetDebugDraw(dbgDraw);
251 }
252
253 private function createWorld(): void
254 {
255 // 边界
256 var worldAABB:b2AABB = new b2AABB();
257 worldAABB.lowerBound.Set( - 3000 / RATIO, - 3000 / RATIO);
258 worldAABB.upperBound.Set( 3000 / RATIO, 3000 / RATIO);
259 // 重力
260 var gravity:b2Vec2 = new b2Vec2( 0 , 10 );
261 // 允许休眠
262 var doSleep:Boolean = true ;
263
264 world = new b2World(worldAABB, gravity, doSleep);
265 }
266
267 private function onLoopHandler(e:Event): void
268 {
269 if (world == null ) return ;
270 // 刷新物理空间
271 world.Step(TIME_STEP, ITERATIONS);
272
273 for (var bb:b2Body = world.m_bodyList; bb; bb = bb.m_next)
274 {
275 if (bb.GetPosition().y * RATIO > stage.stageHeight)
276 {
277 tip_txt.text = ' 有物体掉落,游戏失败,请按R键重置游戏 ' ;
278 world.DestroyBody(bb);
279 }
280 }
281 }
282
283 // 获取剩余刚体的滚动提示框
284 public function getScrollTip(arr:Array):Sprite
285 {
286 var sp:Sprite = new Sprite();
287 for (var i: int = 0 ; i < arr.length; i ++ )
288 {
289 var isp:Shape = new Shape();
290 isp.graphics.beginFill( 0x3399CC , 0.4 );
291 switch (arr[i].type)
292 {
293 case 1 :
294 isp.graphics.drawCircle( 0 , 0 , arr[i].width * 0.5 );
295 break ;
296 case 2 :
297 isp.graphics.moveTo( 0 , arr[i].height * 0.5 );
298 isp.graphics.lineTo(arr[i].width * 0.5 , - arr[i].height * 0.5 );
299 isp.graphics.lineTo( - arr[i].width * 0.5 , - arr[i].height * 0.5 );
300 isp.rotation = 180 ;
301 break ;
302 case 3 :
303 isp.graphics.drawRect( - arr[i].width * 0.5 , - arr[i].height * 0.5 , arr[i].width, arr[i].height);
304 break ;
305 }
306 isp.graphics.endFill();
307 isp.x = i * 50 ;
308 sp.addChild(isp);
309 }
310
311 return sp;
312 }
313
314 // 获取剩余刚体的数据
315 public function getData():Array
316 {
317 var arr:Array = [];
318 for (var i: int = 0 ; i < 10 ; i ++ )
319 {
320 var obj:Object = new Object();
321 if (i < 4 )
322 {
323 obj.type = 3 ;
324 } else if (i > 6 )
325 {
326 obj.type = 2 ;
327 } else
328 {
329 obj.type = 1 ;
330 }
331
332 obj.width = 40 ;
333 obj.height = 40 ;
334 arr.push(obj);
335 }
336 return arr;
337 }
338 }
339
340 }

 

 

这部分跟Box2D基本没关系,就此省了

 

代码运行结果

 

游戏大概就这样子了,接下来要处理的就是给刚体贴图,注意因为有贴图,所以在销毁刚体时记得removeChild并设置其为null

 

 

代码
 
   
1 package
2 {
3 import Box2D.Collision.b2AABB;
4 import Box2D.Collision.Shapes.b2CircleDef;
5 import Box2D.Collision.Shapes.b2PolygonDef;
6 import Box2D.Common.Math.b2Vec2;
7 import Box2D.Dynamics.b2Body;
8 import Box2D.Dynamics.b2BodyDef;
9 import Box2D.Dynamics.b2DebugDraw;
10 import Box2D.Dynamics.b2World;
11 import flash.display.MovieClip;
12 import flash.display.Shape;
13 import flash.display.Sprite;
14 import flash.events.Event;
15 import flash.events.KeyboardEvent;
16 import flash.events.MouseEvent;
17 import flash.system.IME;
18 import flash.text.TextField;
19 /* *
20 * ...
21 * @description superStacker4
22 * @author ispooky
23 * @date 2010.11.15
24 *
25 * @see http://ispooky.cnblogs.com
26 */
27 public class superStacker4 extends Sprite
28 {
29 // 缩放比例
30 public static const RATIO : int = 30 ;
31 // 时间步
32 public static const ITERATIONS : int = 30 ;
33 // 迭代次数
34 public static const TIME_STEP :Number = 1 / 30 ;
35
36 // 物理空间
37 private static var world :b2World;
38 // Debug绘制容器
39 private static var spriteToDrawOn :Sprite;
40
41 // 提示MC
42 private var tip_mc:Sprite;
43 // 刚体类型 1 : 圆形,2 : 三角形, 3 : 矩形
44 private var now_type: int = 1 ;
45 private var now_width:Number = 40 ;
46 private var now_height:Number = 40 ;
47
48 // 剩余物
49 private var remainder_arr:Array;
50 private var remainder_mc:Sprite;
51
52 public var tip_txt:TextField;
53 public function superStacker4()
54 {
55 if (stage) init();
56 else addEventListener(Event.ADDED_TO_STAGE, init);
57 }
58
59 private function init(e:Event = null ): void
60 {
61 removeEventListener(Event.ADDED_TO_STAGE, init);
62 IME.enabled = false ;
63
64 initB2D();
65 getRemainder();
66 tip_mc = new Sprite();
67 addChild(tip_mc);
68 stage.addEventListener(MouseEvent.MOUSE_DOWN, onDownHandler);
69 stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDownHandler);
70 }
71
72 private function getRemainder(): void
73 {
74 remainder_arr = getData();
75 if (remainder_mc != null ) { removeChild(remainder_mc) };
76 remainder_mc = getScrollTip(remainder_arr);
77 remainder_mc.x = 30 ;
78 remainder_mc.y = 30 ;
79 addChild(remainder_mc);
80 }
81
82 private function onKeyDownHandler(e:KeyboardEvent): void
83 {
84 if (e.keyCode == 82 /* R */ )
85 {
86 for (var bb:b2Body = world.m_bodyList; bb; bb = bb.m_next)
87 {
88 if (bb.m_userData is MovieClip)
89 {
90 removeChild(bb.m_userData);
91 bb.m_userData = null ;
92 }
93 if ( ! bb.IsStatic()) { world.DestroyBody(bb) };
94 }
95 getRemainder();
96 tip_txt.text = ' 提示框: ' ;
97 }
98 }
99
100 private function onDownHandler(e:MouseEvent): void
101 {
102 if (remainder_arr.length <= 0 )
103 {
104 tip_txt.text = ' 所有物体都摆放了,成功过关 ' ;
105 return ;
106 }
107 now_type = remainder_arr[ 0 ].type;
108 tip_mc.graphics.clear();
109 tip_mc.graphics.beginFill( 0x900000 , 0.6 );
110 switch (now_type)
111 {
112 // 圆形
113 case 1 :
114 tip_mc.graphics.drawCircle( 0 , 0 , remainder_arr[ 0 ].width * 0.5 );
115 break ;
116 // 三角形
117 case 2 :
118 tip_mc.graphics.moveTo( 0 , remainder_arr[ 0 ].height * 0.5 );
119 tip_mc.graphics.lineTo(remainder_arr[ 0 ].width * 0.5 , - remainder_arr[ 0 ].height * 0.5 );
120 tip_mc.graphics.lineTo( - remainder_arr[ 0 ].width * 0.5 , - remainder_arr[ 0 ].height * 0.5 );
121 tip_mc.rotation = 180 ;
122 break ;
123 // 矩形
124 case 3 :
125 tip_mc.graphics.drawRect( - now_width * 0.5 , - now_height * 0.5 , now_width, now_height);
126 break ;
127 }
128 tip_mc.graphics.endFill();
129 tip_mc.x = mouseX;
130 tip_mc.y = mouseY;
131 stage.addEventListener(MouseEvent.MOUSE_MOVE, onMoveHandler);
132 stage.addEventListener(MouseEvent.MOUSE_UP, onUpHandler);
133 }
134
135 private function onUpHandler(e:MouseEvent): void
136 {
137 stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMoveHandler);
138 stage.removeEventListener(MouseEvent.MOUSE_UP, onUpHandler);
139 tip_mc.graphics.clear();
140 createBox(now_type);
141
142 remainder_arr.shift();
143 removeChild(remainder_mc);
144 remainder_mc = getScrollTip(remainder_arr);
145 remainder_mc.x = 30 ;
146 remainder_mc.y = 30 ;
147 addChild(remainder_mc);
148 }
149
150 private function onMoveHandler(e:MouseEvent): void
151 {
152 tip_mc.x = mouseX;
153 tip_mc.y = mouseY;
154 e.updateAfterEvent();
155 }
156
157 private function initB2D(): void
158 {
159 addEventListener(Event.ENTER_FRAME, onLoopHandler, false , 0 , true );
160 createWorld();
161 showDebug();
162 createGrounds();
163 }
164
165 private function createBox(value: int ): void
166 {
167 var bodyDef:b2BodyDef;
168 var boxDef:b2PolygonDef;
169 var circleDef:b2CircleDef;
170 var body:b2Body;
171
172 bodyDef = new b2BodyDef();
173 bodyDef.position.Set(mouseX / RATIO, mouseY / RATIO);
174 switch (value)
175 {
176 case 1 :
177 circleDef = new b2CircleDef();
178 circleDef.radius = now_width * 0.5 / RATIO;
179 circleDef.density = 1 ;
180 circleDef.friction = 0.1 ;
181 circleDef.restitution = 0.3 ;
182 bodyDef.userData = new CircleSkin();
183 bodyDef.userData.width = now_width;
184 bodyDef.userData.height = now_width;
185 addChild(bodyDef.userData);
186 body = world.CreateBody(bodyDef);
187 body.CreateShape(circleDef);
188 break ;
189 case 2 :
190 bodyDef.angle = 180 * (Math.PI / 180 );
191 boxDef = new b2PolygonDef();
192 boxDef.vertexCount = 3 ;
193 boxDef.vertices[ 0 ].Set(now_width * 0.5 / RATIO, - now_height * 0.5 / RATIO);
194 boxDef.vertices[ 1 ].Set( 0 , now_height * 0.5 / RATIO);
195 boxDef.vertices[ 2 ].Set( - now_width * 0.5 / RATIO, - now_height * 0.5 / RATIO);
196 boxDef.density = 1 ;
197 boxDef.friction = 0.3 ;
198 boxDef.restitution = 0.2 ;
199 bodyDef.userData = new TriSkin();
200 bodyDef.userData.width = now_width;
201 bodyDef.userData.height = now_height;
202 addChild(bodyDef.userData);
203 body = world.CreateBody(bodyDef);
204 body.CreateShape(boxDef);
205 break ;
206 case 3 :
207 boxDef = new b2PolygonDef();
208 boxDef.SetAsBox(now_width / RATIO / 2 , now_height / RATIO / 2 );
209 boxDef.density = 1 ;
210 boxDef.friction = 0.4 ;
211 boxDef.restitution = 0.1 ;
212 bodyDef.userData = new RectSkin();
213 bodyDef.userData.width = now_width;
214 bodyDef.userData.height = now_height;
215 addChild(bodyDef.userData);
216 body = world.CreateBody(bodyDef);
217 body.CreateShape(boxDef);
218 break ;
219 }
220 body.SetMassFromShapes();
221 }
222
223 private function createGrounds(): void
224 {
225 var bodyDef:b2BodyDef;
226 var boxDef:b2PolygonDef;
227 var body:b2Body;
228
229 // 刚体定义
230 bodyDef = new b2BodyDef();
231 // 设置位置
232 bodyDef.position.Set( 275.0 / RATIO, 250.0 / RATIO);
233 // 形状定义
234 boxDef = new b2PolygonDef();
235 // 设置高宽
236 boxDef.SetAsBox( 250.0 / RATIO / 2 , 20.0 / RATIO / 2 );
237 // 密度,0为静态物
238 boxDef.density = 0 ;
239 // 摩擦力
240 boxDef.friction = 0.3 ;
241 // 弹力
242 boxDef.restitution = 0.2 ;
243
244 body = world.CreateBody(bodyDef);
245 body.CreateShape(boxDef);
246 // 计算质量,因此处为静态物,所以不需计算
247 // body.SetMassFromShapes();
248 }
249
250 private function showDebug(): void
251 {
252 spriteToDrawOn = new Sprite();
253 addChild(spriteToDrawOn);
254 var dbgDraw:b2DebugDraw = new b2DebugDraw();
255 // 绘制图形
256 dbgDraw.m_sprite = spriteToDrawOn;
257 // 缩放比例
258 dbgDraw.m_drawScale = RATIO;
259 // 填充线的颜色透明度
260 dbgDraw.m_alpha = 1.0 ;
261 // 填充区域的颜色透明度
262 dbgDraw.m_fillAlpha = 0.5 ;
263 // 线型粗细
264 dbgDraw.m_lineThickness = 1.0 ;
265 // 绘制图形位
266 dbgDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit;
267
268 world.SetDebugDraw(dbgDraw);
269 }
270
271 private function createWorld(): void
272 {
273 // 边界
274 var worldAABB:b2AABB = new b2AABB();
275 worldAABB.lowerBound.Set( - 3000 / RATIO, - 3000 / RATIO);
276 worldAABB.upperBound.Set( 3000 / RATIO, 3000 / RATIO);
277 // 重力
278 var gravity:b2Vec2 = new b2Vec2( 0 , 10 );
279 // 允许休眠
280 var doSleep:Boolean = true ;
281
282 world = new b2World(worldAABB, gravity, doSleep);
283 }
284
285 private function onLoopHandler(e:Event): void
286 {
287 if (world == null ) return ;
288 // 刷新物理空间
289 world.Step(TIME_STEP, ITERATIONS);
290
291 for (var bb:b2Body = world.m_bodyList; bb; bb = bb.m_next)
292 {
293 if (bb.m_userData is MovieClip)
294 {
295 bb.m_userData.x = bb.GetPosition().x * RATIO;
296 bb.m_userData.y = bb.GetPosition().y * RATIO;
297 bb.m_userData.rotation = bb.GetAngle() * 180 / Math.PI;
298
299 if (bb.IsSleeping())
300 {
301 MovieClip(bb.m_userData).gotoAndStop( 1 );
302 } else
303 {
304 MovieClip(bb.m_userData).gotoAndStop( 2 );
305 }
306 }
307
308 if (bb.GetPosition().y * RATIO > stage.stageHeight)
309 {
310 tip_txt.text = ' 有物体掉落,游戏失败,请按R键重置游戏 ' ;
311 removeChild(bb.m_userData);
312 bb.m_userData = null ;
313 world.DestroyBody(bb);
314 }
315 }
316 }
317
318 public function getScrollTip(arr:Array):Sprite
319 {
320 var sp:Sprite = new Sprite();
321 for (var i: int = 0 ; i < arr.length; i ++ )
322 {
323 var isp:Shape = new Shape();
324 isp.graphics.beginFill( 0x3399CC , 0.4 );
325 switch (arr[i].type)
326 {
327 case 1 :
328 isp.graphics.drawCircle( 0 , 0 , arr[i].width * 0.5 );
329 break ;
330 case 2 :
331 isp.graphics.moveTo( 0 , arr[i].height * 0.5 );
332 isp.graphics.lineTo(arr[i].width * 0.5 , - arr[i].height * 0.5 );
333 isp.graphics.lineTo( - arr[i].width * 0.5 , - arr[i].height * 0.5 );
334 isp.rotation = 180 ;
335 break ;
336 case 3 :
337 isp.graphics.drawRect( - arr[i].width * 0.5 , - arr[i].height * 0.5 , arr[i].width, arr[i].height);
338 break ;
339 }
340 isp.graphics.endFill();
341 isp.x = i * 50 ;
342 sp.addChild(isp);
343 }
344
345 return sp;
346 }
347
348 public function getData():Array
349 {
350 var arr:Array = [];
351 for (var i: int = 0 ; i < 10 ; i ++ )
352 {
353 var obj:Object = new Object();
354 if (i < 4 )
355 {
356 obj.type = 3 ;
357 } else if (i > 6 )
358 {
359 obj.type = 2 ;
360 } else
361 {
362 obj.type = 1 ;
363 }
364
365 obj.width = 40 ;
366 obj.height = 40 ;
367 arr.push(obj);
368 }
369 return arr;
370 }
371 }
372
373 }

代码运行结果截图(发现不是cnblogs的没注册用户看不到swf,下次不传swf了)

代码运行结果

 

贴图的刷新

bb.m_userData.x = bb.GetPosition().x * RATIO;

bb.m_userData.y = bb.GetPosition().y * RATIO;

bb.m_userData.rotation = bb.GetAngle() * 180 / Math.PI;

为了效果更好一点,可用Body.IsSleeping()来判断是否处于稳定状态来表现不同的效果

 

注:游戏结束在这里只是提示有物体脱离舞台并未锁定。

 

点击这里下载源码

转载于:https://www.cnblogs.com/ispooky/archive/2010/11/15/1877619.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值