[Flash] Box2DFlashAS3 を学習 (2)
Environment:
- Adobe AIR SDK 22
- Box2DFlashAS3 v2.0.2
- FlashDevelop 5.2
- Windows 7 64bit
Physics Engine(物理演算エンジン)の学びを継続。
Box2DでActionScript物理プログラミング 技術評論社 の記事をひねってみる。
Learn
- 第2回 物理エンジンをセットアップし,箱を落とすFlashを作る
- 第3回 マウスのドラッグ&ドロップで,好きなサイズの箱を作る
- 第4回 いろいろな形の物体を作る
をまとめてみた。
実Flash。操作可。マウスドラッグで物体の大きさを決める。シフトキーでスロー(5分の1)になる。
SourceCode
Main.as
package{
import Box2D.Collision.Shapes.b2CircleDef;
import Box2D.Collision.b2AABB;
import Box2D.Collision.Shapes.b2PolygonDef;
import Box2D.Common.Math.b2Vec2;
import Box2D.Dynamics.b2Body;
import Box2D.Dynamics.b2BodyDef;
import Box2D.Dynamics.b2DebugDraw;
import Box2D.Dynamics.b2World;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
/**
* ...
* @author foo
*/
[SWF(width = "480", height = "480", frameRate = "30", backgroundColor = "#02143")]
// 480px -> 4.8m
public class Main extends Sprite {
private var wld:b2World = null; //world
private var wldfps:int = 30; //30 fps
private var items:Array = [];
private const PIXELS_PER_METER:Number = 100; // 100pixel for 1m
private var objPt:Point = null; // object point
private var tf:TextField = null;
private var shp:Array = ['box', 'circle', 'triangle'];
public function Main() {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUP);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(e:Event):void {
if (wld == null) {
setupPhisycsWorld();
}
wld.Step(1 / wldfps, 10); //30fps, PhisycsEnginePrecision: more than 10 -> more precise, slower
// remove objects out of world
var obj:b2Body = wld.GetBodyList();
while (obj) {
if (obj.GetWorldCenter().y * PIXELS_PER_METER > 1000) {
wld.DestroyBody(obj);
}
obj = obj.GetNext();
}
// drag temp box
if ( ! objPt) return;
graphics.lineStyle(1, 0xCCCCCC, 0.3);
graphics.beginFill(0x888888, 0.3);
graphics.drawRect(
objPt.x,
objPt.y,
Math.abs(stage.mouseX - objPt.x),
Math.abs(stage.mouseY - objPt.y)
);
graphics.endFill();
if (tf) tf.text =
"mouseX = " + stage.mouseX
+ "\nmouseY = " + stage.mouseY
+ "\nstartX = " + objPt.x
+ "\nstartY = " + objPt.y
}
private function onKeyUP(e:KeyboardEvent):void {
wldfps = 30;
}
private function onKeyDown(e:KeyboardEvent):void {
if (e.shiftKey) wldfps = 150; // 5 times slower
}
private function onMouseDown(e:MouseEvent):void {
if ( ! objPt) objPt = new Point();
objPt.x = e.stageX;
objPt.y = e.stageY;
}
private function onMouseUp(e:MouseEvent):void {
var center_x:Number = (e.stageX + objPt.x) / 2.0 / PIXELS_PER_METER;
//mouseX(250px)÷DebugDraw.m_drawScale(100) -> 2.5m from left
var center_y:Number = (e.stageY + objPt.y) / 2.0 / PIXELS_PER_METER;
//monseY(100px)÷DebugDraw.m_drawScale(100) -> 1m from top
var w:Number = Math.abs(e.stageX - objPt.x) / PIXELS_PER_METER;
var h:Number = Math.abs(e.stageY - objPt.y) / PIXELS_PER_METER;
if (w < 0.05) w = 0.1;
if (h < 0.05) h = 0.1
objPt = null;
var objPos_m:b2BodyDef = new b2BodyDef(); // BoxPosition_meter
objPos_m.position.Set(center_x, center_y);
items.push(wld.CreateBody(objPos_m));
var cur:int = items.length - 1; // current item
var polShp_m:b2PolygonDef = null;
var ccShp_m:b2CircleDef = null;
var i:int = 0;
if (shp[cur % shp.length] == 'box') {
// setup box
polShp_m = new b2PolygonDef(); //BoxShape_meter
var slant_r:Number = (Math.random() * 3.14 - (3.14 / 2)) / 360 * 30; //slant radian
// radian 0to+3.14 -> radian -1.62to+1.62 -> degree -15to+15
polShp_m.SetAsOrientedBox(w/2.0, h/2.0, new b2Vec2(0, 0), slant_r);
// Oriented = slanted(傾き)
// width 0.6m, height 0.4m, rotate Center, 0.8radian=45degree
polShp_m.density = 1; // weight 1kg/m^2 for 1m^2 box; now 0.24kg(240g) for 0.24m^2 box
polShp_m.restitution = 0.2; // rebound: 0:no_rebound to 1:rebound_forever
items[cur].CreateShape(polShp_m);
} else if (shp[cur % shp.length] == 'circle') {
ccShp_m = new b2CircleDef();
ccShp_m.radius = Math.sqrt(Math.pow(w / 2.0, 2) + Math.pow(h / 2.0, 2));
ccShp_m.density = 1.0;
ccShp_m.restitution = 0.5;
items[cur].CreateShape(ccShp_m);
} else if (shp[cur % shp.length] == 'triangle') {
polShp_m = new b2PolygonDef();
var pt:Array = [];
pt.push(new Point(center_x - (w / 2.0), center_y - (h / 2.0)));
pt.push(new Point(center_x + (w / 2.0), center_y - (h / 2.0)));
pt.push(new Point(center_x + (w / 2.0), center_y + (h / 2.0)));
polShp_m.vertexCount = pt.length;
for (i = 0; i < pt.length; i++) {
polShp_m.vertices[i].Set(pt[i].x - center_x, pt[i].y - center_y);
}
polShp_m.density = 1.0;
polShp_m.restitution = 0.5;
polShp_m.friction = 0.5;
items[cur].CreateShape(polShp_m);
}
items[cur].SetMassFromShapes(); // set weight
}
private function setupPhisycsWorld():void {
//log
var tfmt:TextFormat = new TextFormat('Courier New', 16, 0xFFFFFF, true)
tf = new TextField();
tf.x = 10;
tf.y = 10;
tf.autoSize = TextFieldAutoSize.LEFT;
tf.defaultTextFormat = tfmt;
tf.text = 'Drag with your mouse button!';
addChild(tf);
// setup Phisycs Engine
var wldPos_m:b2AABB = new b2AABB(); // worldPosition_meter: Axis-aligned(not slanted) BoundingBox
wldPos_m.lowerBound.Set( -100, -100); // left top -100m,-100m (length 200m)
wldPos_m.upperBound.Set(100, 100); // right bottom
var gv_mps:b2Vec2 = new b2Vec2(0, 10); // gravity_meterPerSec: 0m/s^2 to right, 10m/s^2 to bottom
wld = new b2World(wldPos_m, gv_mps, true); // doSleep: improve performance by not simulating inactives
// setup floor
// floor position
var flrPos_m:b2BodyDef = new b2BodyDef(); // floorPosition_meter
flrPos_m.position.Set(2.5, 4); // 2.5m from left, 4m from top
// floor shape
var flrSh_m:b2PolygonDef = new b2PolygonDef();
flrSh_m.SetAsBox(2, 0.1); // width 4m, height 0.2m(20cm)
// put floor (unmovable)
var flr:b2Body = wld.CreateBody(flrPos_m);
flr.CreateShape(flrSh_m);
// box2d draw
var dd_m:b2DebugDraw = new b2DebugDraw(); // debugDraw_meter
dd_m.m_sprite = this;
dd_m.m_drawScale = PIXELS_PER_METER; // 100pixel for 1m
dd_m.m_fillAlpha = 0.3; // alpha(see-ability): 0:no_see(transparent) to 1:see(no_transparent)
dd_m.m_lineThickness = 1; // line width 1pixel
dd_m.m_drawFlags = b2DebugDraw.e_shapeBit;
wld.SetDebugDraw(dd_m);
}
}
}
0 件のコメント:
コメントを投稿