wonderfl用Box2Dテンプレートを作ってみたい。Ver0.2
wonderfl用Box2Dテンプレートを作ってみたい。Ver0.2
多角形作成関数と、距離ジョイント・回転ジョイント・直動ジョイント関数を作ってみた。
なんとなく概念はわかってきたけど、慣れが必要だなぁ。
最近少し忙しいのでちょこちょことやる予定。
Box2Dはいろいろ手続きが面倒すぎるので、楽しいところだけ弄れるようにしたい。
ここを大いに参考にしてるというか、ほぼそのままで、拡張中。
http://hokori.net/2009/02/18/box2dflashas3_base/
package
{
import flash.display.Sprite;
import Box2D.Collision.*;
import Box2D.Common.Math.*;
import Box2D.Dynamics.*;
import Box2D.Dynamics.Joints.*;
import Box2D.Collision.Shapes.*;
import flash.events.Event;
/**
* wonderfl用Box2Dテンプレートを作ってみたい。Ver0.2
*
* 多角形作成関数と、距離ジョイント・回転ジョイント・直動ジョイント関数を作ってみた。
* なんとなく概念はわかってきたけど、慣れが必要だなぁ。
*
*
* 最近少し忙しいのでちょこちょことやる予定。
* Box2Dはいろいろ手続きが面倒すぎるので、楽しいところだけ弄れるようにしたい。
*
* ここを大いに参考にしてるというか、ほぼそのままで、拡張中。
* http://hokori.net/2009/02/18/box2dflashas3_base/
*/
[SWF(width=465,height=465,frameRate=60,backgroundColor=0x000000)]
public class Test extends Sprite
{
//固定プロパティ
private var _world:b2World;
private var _catalystObj:B2DCatalyst;
//設定用プロパティ
private const WIDTH:Number = 465;
private const HEIGHT:Number = 465;
private var _fps:Number = 60;
private var _timeStep:Number = 1.0 / _fps;
private var _scale:Number = 100;
private var _gravity:Number = 10;
//各自追加プロパティ
private var cnt:Number = 0;
private var _prismaticLiftBody:b2Body;
private var _prismaticLiftJoint:b2PrismaticJoint;
public function Test()
{
init();
}
private function init():void {
_catalystObj = new B2DCatalyst(true, _fps, _scale, _gravity);
this.addChild(_catalystObj);
_world = _catalystObj.world;
////////////////////////////////////////////////
//////////// 以下、設定用コード ////////////
////////////////////////////////////////////////
//床を作成
_catalystObj.makeB2BodyBox(465, 30, 232.5, 435, 0, 0, 0.5, 0.5);
//多角形を作ってみる
_catalystObj.makeB2BodyPolygon(220, 200, [[0.0, 0.0], [25, 25], [25, 50],[-25, 50],[-25, 25]], 0, 0.2, 0.5);
//距離ジョイントを使って二つの物体を結びつける
var dJObj1:b2Body = _catalystObj.makeB2BodyBox(40, 40, 150, 100, 0, 1, 0.5, 0.5);
var dJObj2:b2Body = _catalystObj.makeB2BodyBox(40, 40, 250, 100, 0, 1, 0.5, 0.5);
var anchor1:b2Vec2 = _catalystObj.createB2Vec(dJObj1.GetPosition().x*_scale, dJObj1.GetPosition().y*_scale);
var anchor2:b2Vec2 = _catalystObj.createB2Vec(dJObj2.GetPosition().x*_scale, dJObj2.GetPosition().y*_scale);
_catalystObj.makeDistanceJoint(dJObj1, dJObj2, anchor1, anchor2);
//回転ジョイント
var rJObj1:b2Body = _catalystObj.makeB2BodyCircle(50,400,150,0,0,0);
var rjObj2:b2Body = _catalystObj.makeB2BodyBox(40, 40, 400, 200, 0, 1, 0.5, 0.5);
var anchor:b2Vec2 = _catalystObj.createB2Vec(rJObj1.GetPosition().x*_scale, rJObj1.GetPosition().y*_scale);
_catalystObj.makeRevoluteJoint(rJObj1, rjObj2, anchor,true,100,1,true,0,120);
//直動ジョイント
var pJ_anchorObj:b2Body = _world.GetGroundBody();
var pJ_moveObj:b2Body = _catalystObj.makeB2BodyBox(60, 10, 200, 300, 0, 1, 0.5, 0.5);
var pJ_moveObjAnchor:b2Vec2 = _catalystObj.createB2Vec(pJ_moveObj.GetPosition().x*_scale,pJ_moveObj.GetPosition().y*_scale);
var pJ_Vector:b2Vec2 = new b2Vec2(1.0, 0);
_prismaticLiftJoint = _catalystObj.makePrismaticJoint(pJ_anchorObj, pJ_moveObj, pJ_moveObjAnchor, pJ_Vector);
_prismaticLiftBody = pJ_moveObj;
////////////////////////////////////////////////
//////////// 以上、設定用コード ////////////
////////////////////////////////////////////////
_catalystObj.addEventListener(Event.ENTER_FRAME, onEnterFrameHandler);
}
private function onEnterFrameHandler(e:Event):void
{
_world.Step(_timeStep, 10);
////////////////////////////////////////////////
//////////// 以下、描画更新用コード ////////////
////////////////////////////////////////////////
//30フレームごとに四角と丸を作る
if (cnt == 30) {
create();
cnt = 0;
} else {
cnt++;
}
//直動ジョイント制御
var pj_PosX:Number = _prismaticLiftBody.GetPosition().x * _scale;
var pj_SpeedX:Number = _prismaticLiftJoint.GetMotorSpeed();
if (pj_PosX > 400 && pj_SpeedX > 0) {
_prismaticLiftJoint.SetMotorSpeed(pj_SpeedX * -1);
} else if (pj_PosX < 100 && pj_SpeedX < 0) {
_prismaticLiftJoint.SetMotorSpeed(pj_SpeedX * -1);
}
////////////////////////////////////////////////
//////////// 以上、描画更新用コード ////////////
////////////////////////////////////////////////
//画面外に行ったオブジェクトを削除する
var marginX:Number = 50;
var marginY:Number = 50;
for (var b:b2Body = _world.GetBodyList(); b; b = b.GetNext()) {
var xPos:Number = b.GetWorldCenter().x * _scale;
var yPos:Number = b.GetWorldCenter().x * _scale;
if (xPos > WIDTH + marginX || xPos < -marginX || yPos > HEIGHT + marginY || yPos < -marginY){
_world.DestroyBody(b);
}
}
}
private function create():void {
_catalystObj.makeB2BodyCircle(50, Math.random() * 465, 0, 1, 0.2, 0.5);
_catalystObj.makeB2BodyBox(50, 50, Math.random() * 465, 0, Math.random() * Math.PI * 2, 1, 0.2, 0.5);
}
}
}
//以下、媒介用クラス。なので、拡張する時以外、通常弄る必要なし
//以下のURLをほぼ丸ごと。少しずつ拡張予定。
//http://hokori.net/2009/02/18/box2dflashas3_base/
import flash.display.Sprite;
import flash.geom.Point;
import Box2D.Collision.*;
import Box2D.Common.Math.*;
import Box2D.Dynamics.*;
import Box2D.Dynamics.Joints.*
import Box2D.Collision.Shapes.*;
internal class B2DCatalyst extends Sprite
{
//Box2Dのバージョンは2.0.2
private var m_b2_world:b2World;
//縮尺 1mを何ピクセルで表すか
private var m_b2_physcale:Number = 10;
//演算制度 大きいと正確だけど、負荷が大きい
private var m_b2_iterations:int = 10;
// 演算をfpsに合わせる
private var m_b2_timeStep:Number = 24.0;
//constructor
public function B2DCatalyst(debugModeFlag:Boolean = false, fps:int = 24,
physcale:Number = 10, gravity:Number = 10):void{
//timestep設定
this.m_b2_timeStep = 1.0 / fps;
//スケール設定
this.m_b2_physcale = physcale;
//B2DBoxの世界生成
this.createB2World(gravity);
//debugMode
if (debugModeFlag) startDebugMode();
}
//Box2D世界作成
private function createB2World(gravity:Number):void {
// Creat world AABB
var worldAABB:b2AABB = new b2AABB();
worldAABB.lowerBound.Set(-1000, -1000);
worldAABB.upperBound.Set(1000, 1000);
// Define the gravity vector
var vec_gravity:b2Vec2 = new b2Vec2(0.0, gravity);
// Allow bodies to sleep
var doSleep:Boolean = true;
// Construct a world object
this.m_b2_world = new b2World(worldAABB, vec_gravity, doSleep);
}
/**
* 長方形の物体作成
* @param int w (ピクセル 内部でB2DBox用に変換)
* @param int h (ピクセル 内部でB2DBox用に変換)
* @param Number x(ピクセル 内部でB2DBox用に変換)
* @param Number y(ピクセル 内部でB2DBox用に変換)
* @param Number angle 角度(360度 内部でラジアンに変換)
* @param density 密度 0にすると固定
* @param friction 摩擦 大きいと滑りにくい
* @param restitution 跳ね返り 大きいと、反発しやすい
* @param viewdata 表示用のSprite
* @param viewgroup 表示用のSpriteを入れるSprite
* @return b2Body
*/
public function makeB2BodyBox(w:int, h:int,
x:Number, y:Number, angle:Number,
density:Number,
friction:Number,
restitution:Number,
viewdata:Sprite = null,
viewgroup:Sprite = null) :b2Body {
var b2_boxdef:b2PolygonDef = this.createB2BoxDef(w, h, density,
friction, restitution);
var b2_bodydef:b2BodyDef = this.createB2BodyDef(x, y, w, h, angle,
viewdata, viewgroup);
var b2_body:b2Body = this.m_b2_world.CreateBody(b2_bodydef);
b2_body.CreateShape(b2_boxdef);
b2_body.SetMassFromShapes();
return b2_body;
}
/**
* 多角形の物体作成
* @param int w (ピクセル 内部でB2DBox用に変換)
* @param int h (ピクセル 内部でB2DBox用に変換)
* @param Number x(ピクセル 内部でB2DBox用に変換)
* @param Number y(ピクセル 内部でB2DBox用に変換)
* @param Number angle 角度(360度 内部でラジアンに変換)
* @param density 密度 0にすると固定
* @param friction 摩擦 大きいと滑りにくい
* @param restitution 跳ね返り 大きいと、反発しやすい
* @param viewdata 表示用のSprite
* @param viewgroup 表示用のSpriteを入れるSprite
* @return b2Body
*/
public function makeB2BodyPolygon(x:Number, y:Number, vertex:Array,
density:Number,
friction:Number,
restitution:Number,
viewdata:Sprite = null,
viewgroup:Sprite = null) :b2Body {
var b2_bodydef:b2BodyDef = new b2BodyDef();
b2_bodydef.position.Set(x / m_b2_physcale, y / m_b2_physcale);
var b2_Polydef:b2PolygonDef = new b2PolygonDef();
var len:int = b2_Polydef.vertexCount = vertex.length;
for (var i:int = 0; i < len; i++) {
b2_Polydef.vertices[i].Set(vertex[i][0]/m_b2_physcale, vertex[i][1]/m_b2_physcale);
}
b2_Polydef.density = density;
b2_Polydef.friction = friction;
b2_Polydef.restitution = restitution;
var b2_body:b2Body = this.m_b2_world.CreateBody(b2_bodydef);
b2_body.CreateShape(b2_Polydef);
b2_body.SetMassFromShapes();
return b2_body;
}
/**
* 円の物体作成
* @param diameter 直径(ピクセル 内部でメートルに変換)
* @param x (ピクセル 内部でメートルに変換)
* @param y(ピクセル 内部でメートルに変換)
* @param density 密度 0にすると固定 大きいと、ぶつかったとき強い
* @param friction 摩擦 大きいと滑りにくい
* @param restitution 跳ね返り 大きいと、反発しやすい
* @param viewdata 表示用のSprite
* @param viewgroup 表示用のSpriteを入れるSprite
* @return b2Body
*/
public function makeB2BodyCircle(diameter:int, x:Number, y:Number,
density:Number,
friction:Number,
restitution:Number,
viewdata:Sprite = null,
viewgroup:Sprite = null) :b2Body {
var b2_boxdef:b2CircleDef = this.createB2CircleDef(diameter,
density, friction, restitution);
var b2_bodydef:b2BodyDef = this.createB2BodyDef(x, y, 0, 0, 0,
viewdata, viewgroup);
var b2_body:b2Body = this.m_b2_world.CreateBody(b2_bodydef);
b2_body.CreateShape(b2_boxdef);
b2_body.SetMassFromShapes();
return b2_body;
}
/**
* 長方形の性質設定(形状と素材)
* @param width (ピクセル 内部でメートルに変換)
* @param height (ピクセル 内部でメートルに変換)
* @param density
* @param friction
* @param restitution
* @return
*/
public function createB2BoxDef(width:int, height:int,
density:Number,
friction:Number,
restitution:Number):b2PolygonDef {
var boxdef:b2PolygonDef = new b2PolygonDef();
//B2DBox用単位・中心座標からの距離のサイズに変換して作成
boxdef.SetAsBox(width / 2 / this.m_b2_physcale,
height/ 2 / this.m_b2_physcale);
//密度 0だと動かない 大きいと、ぶつかったとき強い
boxdef.density = density;
//摩擦 大きいと、滑りにくい
boxdef.friction = friction;
//跳ね返り 大きいと、反発しやすい(ゴムっぽくなる)
//小さいと、粘土っぽくなる
boxdef.restitution = restitution;
return boxdef;
}
/**
* 円の性質設定(形状と素材)
* @param diameter (ピクセル 内部でメートルに変換)
* @param height (ピクセル 内部でメートルに変換)
* @param density
* @param friction
* @param restitution
* @return
*/
public function createB2CircleDef(diameter:int,
density:Number,
friction:Number,
restitution:Number):b2CircleDef {
var cdef:b2CircleDef = new b2CircleDef();
//メートル単位・中心座標からの距離のサイズに変換して作成
cdef.radius = diameter / 2 / this.m_b2_physcale; //半径
//密度 0だと動かない
cdef.density = density;
//摩擦 大きいと、滑りにくい
cdef.friction = friction;
//跳ね返り 大きいと、反発しやすい(ゴムっぽくなる)
//小さいと、粘土っぽくなる
cdef.restitution = restitution;
return cdef;
}
/**
* 配置設定
* @param x(ピクセル worldの中心から物体の中心の距離)
* @param y(ピクセル)
* @param angle 角度 (360度単位)
* @param viewdata 表示用Sprite
* @param viegroup 表示用Spriteを入れるSprite
* @return 2BodyDef
*/
public function createB2BodyDef(x:Number, y:Number, w:Number, h:Number,
angle:Number,viewdata:Sprite = null,viewgroup:Sprite = null):b2BodyDef {
var bodydef:b2BodyDef = new b2BodyDef();
//B2DBox用単位に変換して配置
bodydef.position.Set(x / this.m_b2_physcale, y / this.m_b2_physcale);
bodydef.angle = (angle / 180) * Math.PI; //ラジアンに変換
//動かないときはスリープ→止まったらイベント受け付けなくなるので起こす
bodydef.allowSleep = true;
if(viewdata != null){
bodydef.userData = viewdata;
bodydef.userData.width = viewdata.width;
bodydef.userData.height = viewdata.height;
//表示用に追加
if(viewgroup != null){
viewgroup.addChild(bodydef.userData);
}
}
return bodydef;
}
/**
* 座標指定用のベクトル作成(単位をピクセルからメートルに変換)
* @param x
* @param y
* @return b2Vec2
*/
public function createB2Vec(x:Number, y:Number):b2Vec2 {
//単位をb2用に変換
var vec:b2Vec2 = new b2Vec2(x / this.m_b2_physcale,
y / this.m_b2_physcale);
return vec;
}
/**
* ベクトル作成
* @param vx
* @param vy
* @return b2Vec2
*/
public function createB2Axis(vx:Number, vy:Number):b2Vec2 {
var vec:b2Vec2 = new b2Vec2(vx,vy);
return vec;
}
//Joint
/**
* 距離ジョイントの作成(2つの物体を二つのポイントで結びつける)
* @param obj1
* @param obj2
* @param anchor1
* @param anchor2
*/
public function makeDistanceJoint(obj1:b2Body,obj2:b2Body,anchor1:b2Vec2,anchor2:b2Vec2):void
{
var jointObj:b2DistanceJointDef = new b2DistanceJointDef();
jointObj.Initialize(obj1, obj2, anchor1, anchor2);
this.m_b2_world.CreateJoint(jointObj);
}
/**
* 回転ジョイントの作成(2つの物体を二つのポイントで結びつける)
* @param obj1
* @param obj2
* @param anchor
* @param enableMotor
* @param maxMotorTorque
* @param motorSpeed
* @param enableLimit
* @param lowerAngle
* @param upperAngle
*/
public function makeRevoluteJoint(obj1:b2Body, obj2:b2Body, anchor:b2Vec2,
enableMotor:Boolean = false,
maxMotorTorque:Number = 0,
motorSpeed:Number = 0,
enableLimit:Boolean = false,
lowerAngle:Number = 0,
upperAngle:Number = 0):void
{
var jointObjDef:b2RevoluteJointDef = new b2RevoluteJointDef();
jointObjDef.enableMotor = enableMotor;
jointObjDef.motorSpeed = maxMotorTorque;
jointObjDef.maxMotorTorque = motorSpeed;
jointObjDef.enableLimit = enableLimit;
jointObjDef.lowerAngle = lowerAngle * (Math.PI / 180);
jointObjDef.upperAngle = upperAngle * (Math.PI / 180);
jointObjDef.Initialize(obj1, obj2, anchor);
this.m_b2_world.CreateJoint(jointObjDef);
}
/**
* 直動ジョイントの作成
* @param obj1
* @param obj2
* @param anchor
* @param enableMotor
* @param maxMotorTorque
* @param motorSpeed
* @param enableLimit
* @param lowerAngle
* @param upperAngle
* @return jointObj
*/
public function makePrismaticJoint(anchorObj:b2Body, moveObj:b2Body, anchor:b2Vec2, vec:b2Vec2,
enableMotor:Boolean = true,
maxMotorForce:Number = 10000,
motorSpeed:Number = 1,
enableLimit:Boolean = false,
lowerTranslation:Number = -100,
upperTranslation:Number = 100):b2PrismaticJoint
{
var jointObj:b2PrismaticJoint;
var jointObjDef:b2PrismaticJointDef = new b2PrismaticJointDef();
jointObjDef.enableMotor = enableMotor;
jointObjDef.maxMotorForce = maxMotorForce;
jointObjDef.motorSpeed = motorSpeed;
jointObjDef.enableLimit = enableLimit;
jointObjDef.lowerTranslation = lowerTranslation/m_b2_physcale;
jointObjDef.upperTranslation = upperTranslation / m_b2_physcale;
jointObjDef.Initialize(anchorObj, moveObj, moveObj.GetPosition(),vec);
jointObj = this.m_b2_world.CreateJoint(jointObjDef) as b2PrismaticJoint;
return jointObj;
}
private function startDebugMode():void
{
//DebugDrawを有効にする
var debugDraw:b2DebugDraw = new b2DebugDraw();
debugDraw.m_sprite = this;
debugDraw.m_drawScale = m_b2_physcale;
debugDraw.m_fillAlpha = .8;
debugDraw.m_lineThickness = 1;
debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit;
m_b2_world.SetDebugDraw(debugDraw);
}
//getter/setter
public function get world():b2World { return m_b2_world; }
public function set world(value:b2World):void
{
m_b2_world = value;
}
}