だいたい47度

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

PageTop

Box2Dを知るためLearning Cocos2Dを読む(5)Part IV Physic Engines - 1

cocos2dの物理エンジン周りの勉強&cocos2dの復習のため、Learning Cocos2Dを読んだメモを残していきます。

全5部17章構成で、今回は4部の10-11章を読みます。ようやく本題の物理エンジンに来ました。内容としては、10章でBox2Dの基本解説と直方体や円を使ったステージ3の作成。11章で車輪のついたカートを動かすステージ4の作成。

【過去】
Learn Cocos2Dを手にとった理由
Part I Getting Started with Cocos2D
Part II More Enemies and More Fun
Part III From Level to Game

11章を読んでいる内に、b2BodyDef→b2Body→b2Shape→b2FixtureDefの一連の流れに慣れてきました。こうなるとBox2Dのコードを読むのが簡単になりますし、色々作るイメージもできてきますね。意外とここが最初の壁かも。

あと今回改めて、設計をよく考えて作らなくてはいけないと思いました。Box2Dを使うため、オブジェクトの動きが前章までとかなり異なるものになるにも関わらず、以前作ったGameCharacterクラスがあるお陰でとても可読性のよいコードになっています。オブジェクトの状態が変わる際に常にchangeStateを呼び出すのはよいですね(実装としてはchangeStateの中にspriteとbodyの両方の処理が書いてあります)。

Chapter 10 Basic Game Physics: Adding Realism with Box2D
Box2Dの基礎を解説後、ステージ3を実装します。Box2Dは物理エンジンを使って本物っぽい動きを自動計算してくれるので、それにあわせてSpriteを変更してくださいね、という基礎から説明開始。

まず、画面をタップしたら四角いbodyが落ちてくるという簡単なアプリを作ります。このへんの説明はEverGismOさんの記事が詳しい。更に画面のgravity方向をアクセラレータに反応させて変化させてみたりします。

次にJOINTを使ってbodyをドラッグできるようにします。クリックポイントの走査のために、Box2DではAABB (axis-aligned bounding box) を使うのが普通のようです。各bodyを内接するような直角四角形を考え、タッチポイントとそれらの四角形を調べていきます。もしヒットするものがあれば、より詳しく、bodyの形とタッチポイントが触れているかをTestPointメソッドで調べます。こんな方法があるんだなぁ。
//MyQueryCallback.h
class MyQueryCallback : public b2QueryCallback{
public:
b2Vec2 pointToTest;
b2Fixture* fixtureFound;

MyQueryCallback(const &b2Vec2& point){
pointToTest = point;
fixtureFound = NULL:
}

bool ReportFIxture(b2Fixture* fixture){
if ( (fixture->GetBody())->GetType() != b2_dynamicBody ) return true;
if (fixture->TestPoint(pointToTest)){ // 2nd test
fixtureFound = fixture;
return false; //stop looking for matches
}
return true;//keep searching
}

//GameLayer.mmのccTouchBegan
b2AABB touchAabb;
b2Vec2 delta = b2Vec2(1.0 / PTM_RATIO, 1.0 / PTM_RATIO);
touchAabb.lowerBound = locationWorld - delta;
touchAabb.upperBound = locationWorld + delta;
MyQueryCallback callback(locationWorld);
world->QueryAABB(&callback, aabb);//SimpleQueryCallbackを全bodyに適用

if (callback.fixtureFound){
b2Body* foundBody = callback.fixtureFound->GetBody();
......//b2MouseJointの作成
}

そのあとは、density、friction、restitutionの説明。重さがsize x densityであることや、2つの物体がぶつかったときはrestitutionの大きいほうが適用されることなど、明確にしておいてくれると助かることが書いてありました。

あとsensorというものを知らなかったです(cocos2dで作る iPhone&iPadゲームプログラミングにも書いてあったかな)。あるbodyが特定の領域に来たかどうかをチェックする際に、collisionは感知するけど衝突はしないbodyを使うことができます。b2FixtureDefのisSensorプロパティをtrueにするだけで、そのbodyはセンサとして働きます。ただこの方法だと、1フレーム中にセンサ領域を通過した場合には検知できないそうで、必要であればマニュアルのcontact listenerを見ろとのこと。物理エンジンゲームは出っ張りなどに引っかかると途中でゲームが停止してしまいがちなので、遊びにセンサを挟んで救済措置にしておくのは大事そうですね。

Chapter 11 Intermediate Game Physics: Modeling, Racing, and Leaping
スクロールする画面をカート(トロッコかな?)で移動する、ステージ4を実装していきます。

Box2Dの世界では、①モータ、②インパルスのいずれかでbodyを動かしてやるのが良いそうです。直接横向きの力を与えたりするのは危険とのこと。こういう風に選択肢を明らかにしてもらえると迷わないからいいですね。

モータは以下のように設定します。すすめるときはSetMotorSpeedしてあげるのですが、motorSpeedはR_PIが180度にあたるラジアン表示なので、2*R_PIに係数をかけて制御してあげるのがよさそうですね。
b2RevoluteJointDef revJointDef;
revJointDef.Initialize(cartBody, wheelBody, wheelBody->GetWorldCenter());
revJointDef.enableMotor = true;
revJointDef.maxMotorTorque = 1000;
revJointDef.motorSpeed = 0;
wheelJoint = (b2RevoluteJoint*) world->CreateJoint(&revJointDef);

インパルスは、衝撃を与えてbodyを動かす他に、カートがひっくり返らないように抑えこむような使い方もできるようです。linearインパルスとangularインパルスの内、angularインパルスを使って実装しています。なるほどなー。
float32 minAngle = CC_DEGREES_TO_RADIANS(-20);
float32 maxAngle = CC_DEGREES_TO_RADIANS( 20);

double desiredAngle = body->GetAngle();
desiredAngle = MIN(desiredAngle, maxAngle);
desiredAngle = MAX(desiredAngle, minAngle);
float diff = desiredAngle - body->GetAngle();

if (diff != 0){
body->SetAngularVelocity(0);
float angimp = body->GetInertia() * diff;//bodyの慣性に差分を掛ける
body->ApplyAngularImpulse(angimp * 2);
}

凸凹の地面を作成するときは、ポリゴンを使わず、edgeを使うとよいらしいです。ポリゴンはパフォーマンスの関係上、八角形以上が作れないので、それらをあわせて地面を作るのは膨大な時間がかかります。そうではなく、地面spriteをVertex Helperにつっこんで頂点を取得し、以下のように凸凹の地面を作るのが簡単です。なるほどなー。本の中では複数の地面spriteをつなげるように書いてありますが、簡単のため一つだけの処理を書きます。
b2BodyDef groundBodyDef;
groundBodyDef.type = b2_staticBody;
groundBodyDef.position.Set(0, 0);
groundBody = world->CreateBody(&groundBodyDef);

CCSprite* ground = ......//地面spriteを取得

b2PolygonShape groundShape;
b2FixtureDef groundFixtureDef;
groundFixtureDef.shape = &groundShape;
groundFixtureDef.density = 0.0f;

//地面spriteの頂点verts[]をたどる
for (int i = 0; i < vertsMax - 1; i++){
b2Vec2 offset = ......//ground.contentSizeの中心
groundShape.SetAsEdge(verts[i] + offset, verts[i+1] + offset);
groundBody->CreateFixture(&groundFixtureDef);
}


ということで2章だけですが盛り沢山でした。実はcocos2dで作る iPhone&iPadゲームプログラミングの物理エンジンを使ったピンボールゲームは流し読みしかしていないので、そういう意味でも新しいことが多かったのかもしれません。

12章では障害物やら敵やらを作ったり、トロッコに主人公を載せたりするようです。13章はChipmunkに触れるみたいです。この2章だけなので短くなる予定。ということで、また次回
そろそろ読み進めるだけじゃなく何か作りたいな……。


Learning Cocos2D: A Hands-On Guide to Building iOS Games with Cocos2D, Box2D, and ChipmunkLearning Cocos2D: A Hands-On Guide to Building iOS Games with Cocos2D, Box2D, and Chipmunk
(2011/07/07)
Rod Wenderlich, Ray Strougo

商品詳細を見る
関連記事
スポンサーサイト

PageTop

コメント


管理者にだけ表示を許可する
 

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。