あけましておめでとうございます、FICC安藤です。
やっと通常業務が落ち着いたので、去年の末からずっと気になってたBox2DFlashAS3のエントリーです。
サンプルを見ながら四角や丸を一通り降らして見たので今度は自由な形状、安易に「F」「I」「C」の文字を降らしてみたいと思います。
まず基本となる入れ物 worldを用意します。
var worldAABB:b2AABB = new b2AABB(); worldAABB.minVertex.Set(-1000.0, -1000.0); worldAABB.maxVertex.Set(1000.0, 1000.0); var gravity:b2Vec2 = new b2Vec2(0.0, 300.0); var doSleep:Boolean = true; m_world = new b2World(worldAABB, gravity, doSleep);
最初のステップから意味がわからなくて躓きましたが、お約束やおなじみらしいのでわからなくても次に行きましょう。
参考:Box2DFlashAS3 の単純なサンプルと使い方 - てっく煮ブログ
では早速「F」を追加します。
最初にb2PolyDefで「F」を描いたところ、当たり判定が大変な事になってしまいました。
TestBed内のサンプルでも凹んだ形状は複数の物を組み合わせて表現していたのでBoxを3つ使って「F」にしてみます。
// 縦棒 var bd1:b2BoxDef = new b2BoxDef(); bd1.extents.Set(8, 20); bd1.density = 1.0; bd1.friction = 0.1; bd1.restitution = 0.1; // 上段横棒 var bd2:b2BoxDef = new b2BoxDef(); bd2.extents.Set(24, 4); bd2.localPosition.Set(16, -16); // 下段横棒 var bd3:b2BoxDef = new b2BoxDef(); bd3.extents.Set(20, 4); bd3.localPosition.Set(12, 0); // 入れ物 var bd:b2BodyDef = new b2BodyDef(); bd.userData = new Object(); bd.userData.fillColor = randomColor(); bd.AddShape(bd1); bd.AddShape(bd2); bd.AddShape(bd3); //bd.position.Set((Math.random() * 360 + 20) / m_physScale, START_POS_Y); //bd.rotation = Math.random() * Math.PI; m_world.CreateBody(bd);
色をランダムにしたいのでuserDataに色を入れておきます。
userDataの使い道として正しいのかどうかわかりませんが、とりあえず。
「I」「C」も「F」と同じ感じなので割愛して次に地面です。
var bodyDefP:b2BodyDef = new b2BodyDef(); var polyDef:b2PolyDef = new b2PolyDef(); bodyDefP.userData = new Object(); bodyDefP.userData.fillColor = 0xFFFFFF; polyDef.vertexCount = 5; polyDef.vertices[0].Set(180, 0); polyDef.vertices[1].Set(360, 10); polyDef.vertices[2].Set(360, 100); polyDef.vertices[3].Set(0, 100); polyDef.vertices[4].Set(0, 10); bodyDefP.position.Set(20, 300); bodyDefP.AddShape(polyDef); m_world.CreateBody(bodyDefP);
地面用と落下用(変な表現ですが)とでは使うクラスの差があるわけではなく、density の値が0または指定しなければ固定になります。
毎ループ時のupdate
public function update():void{
updateMouseWorld();
mouseDrag();
m_world.Step(m_timeStep, m_iterations);
var fillColor:int;
var bb:b2Body;
var s:b2Shape;
var stageWidth:int = Main.rootStage.stageWidth;
var stageHeight:int = Main.rootStage.stageHeight;
var xOffset:int = (stageWidth - 400) / 2;
var yOffset:int = (stageHeight - 400) / 2;
for (bb = m_world.m_bodyList; bb; bb = bb.m_next){
if(bb.m_position.y > 400 + yOffset || bb.m_position.x < 0 - xOffset || bb.m_position.x > 400 + xOffset){
if(!Input.mouseDown){
// 画面外で尚かつドラッグ中でなければ削除
m_world.DestroyBody(bb);
}
}
}
// 描画
for (bb = m_world.m_bodyList; bb; bb = bb.m_next){
if(bb.m_userData){
fillColor = bb.m_userData.fillColor;
}else{
fillColor = 0xFFFFFF;
}
for (s = bb.GetShapeList(); s != null; s = s.GetNext()){
drawShape(s, fillColor);
}
}
}
TestBed/Test.as のupdateと大差ありませんが画面外に消えた時に削除する処理を加えています。
メインループ内で DestroyBody すると画面がちらついてしまったので無駄に2ループしてしまっています。
実際のレンダリングをするdrawShape
public function drawShape(_shape:b2Shape, _fillColor:int = 0xFFFFFF):void{
var i:int;
var v:b2Vec2;
var poly:b2PolyShape = _shape as b2PolyShape;
var tV:b2Vec2 = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[i]));
m_sprite.graphics.beginFill(_fillColor, 1);
m_sprite.graphics.lineStyle(0, 0, 0);
m_sprite.graphics.moveTo(tV.x * m_physScale, tV.y * m_physScale);
for (i = 0; i < poly.m_vertexCount; ++i){
v = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[i]));
m_sprite.graphics.lineTo(v.x * m_physScale, v.y * m_physScale);
}
m_sprite.graphics.lineTo(tV.x * m_physScale, tV.y * m_physScale);
m_sprite.graphics.endFill();
}
これもTestBed/Test.as と大差なく、塗りを加えただけです。
最後にやっぱりマウスで掴んで振り回したり、飛ばしたりしたいのでマウスイベント周りもごっそりTestBed/Test.as クラスから拝借してますので
その辺はソースをご覧ください。
Source:box2d_letterfic.zip
*パブリッシュにはBox2D以外にサンプルに含まれたGeneral/FRateLimiter.as, General/Input.as が必要です。
実際に触ってみると思ってたより使い勝手がよかったのでこれでゲーム作ったら楽しそうですね。
BEYESのサイトでも使われてますね:BEYES Watch the world | RECOMMEND 60 BEYES EDIT STORE

コメントする