My Footprint -2ページ目

My Footprint

どんな靴を履いてても、歩けば僕の足跡。
目標に向かって歩き続ける日々を書いていくブログです。

以前ふらふらとネットサーフィンをしていたときにcocos2dの興味深い記事を見つけたので
暇つぶしに日本語訳&cocos2d-x対応をしてみました。

まぁ英語力は決して高くないので間違いが多々あるとは思いますが、そんなときは
原文を読んでください(笑)

内容はcocos2dで軟体のオブジェクトをシミュレートするという話です。
最近cocos2d-xをやっているのでこれをcocos2d-x用に変換したものをGitHubで公開しています。

まだ完成してませんが、順次アップデートして行きます

Box2Dによる軟体の物理演算 Part 1 / 4

剛体と軟体

このパートはBox2Dでの軟体物理オブジェクトのシミュレート方法を説明する4パートからなるシリーズの最初のパートです。
完全にマッピングした、ぐにゃぐにゃする物体の描画を試して行きます。


Box2Dは剛体の物理エンジンです。つまり、物体は変形不可です。
しかし、変形可能な物体が欲しくなる場合があると思います。
いい例として水風船があげられます。
水風船はグニャグニャとしていて、地面にぶつかったときには変形するはずです。
軟体物理エンジンはこのような物体を扱うことが出来ます。
あいにく、Box2Dは軟体物理エンジンではありません。
しかしディスタンスジョイントを使ってBox2Dでこれらをシミュレートする方法があります。


ディスタンスジョイント


ディスタンスジョイントは2点間の一定の距離を保ちます。
軟体物理シミュレーションを可能にするのに役立つディスタンスジョイントの重要な特徴は、弾力的接続をシミュレートするために
柔らかくすることができるということです。
まずBox2Dで骨組みのようなホイールを作ります。そして柔軟性をシミュレートする為に
全ての物体を弾力的ディスタンスジョイントで接続します。


ディスタンスジョイントに関する詳細はこちら


ホイール構造

My Footprint


上の形状がBox2Dで作ろうとしている物です。
外輪の円の数が多いほど、円に見えます。
チュートリアルの後半で、このBox2D上のホイール構造にマッピングする為にOpenGLでのポリゴン生成を学びます。

ホイールは内側の円を囲むように構成されています。
全ての円は互いにディスタンスジョイントで接続されています。
それらのディスタンスジョイントはバネのようになるように設計されています。
こちらを読むといいでしょう。cocos2dでのOpenGLを使った円の描画についての記事です。
数学的な話はこちらでするのがいいでしょう。


さぁ、やってみよう!

Cocos2DのBox2Dプロジェクトを作りましょう。
デバッグモードでジョイントが見れるようにb2DebugDraw::e_jointBitをオンにしたくなると思います。
ここではワールドの設定方法については割愛します。もしどうやるか分からなければ、このサイト上で
説明している記事を見つけることができます。また、よく参照できるようにソースコードも投稿されるでしょう。
HelloWorldLayer.mmファイルで以下のコードが見つかります。MyNodeは軟体オブジェクトを扱う為のカスタムノードです。

レイヤーに追加し、スクリーンの中央に移動します。

// MyNodeは軟体オブジェクト
MyNode *node = [MyNode node];
node.position = ccp(240, 160);
[node createPhysicsObject:world];
[self addChild:node];


MyNodeのソースです。
外側の円を作成し、中央の円の周りに円状に配置します。
そのときにそれら全てをディスタンスジョイントで接続します。
コードには何をしているか理解できるようにコメントをつけてあります。



#import "CCNode.h"
#import "Box2D.h"


typedef struct {
GLfloat x;
GLfloat y;
} Vertex2D;

static inline Vertex2D Vertex2DMake(GLfloat inX, GLfloat inY) {
Vertex2D ret;
ret.x = inX;
ret.y = inY;
return ret;
}

@interface MyNode : CCNode {
}

- (void) createPhysicsObject:(b2World*)world;
@end





#import "cocos2d.h"
#import "MyNode.h"

#define PTM_RATIO 32.f


@implementation MyNode

- (id) init {
self = [super init];

return self;
}

// 外輪の円の数 (増やすとよりスムーズな丸になる)
#define NUM_SEGMENTS 12

- (void) createPhysicsObject:(b2World *)world {
// Centerは中央の円の位置
b2Vec2 center = b2Vec2(240/PTM_RATIO, 260/PTM_RATIO);

b2CircleShape circleShape;
circleShape.m_radius = 0.25f;

b2FixtureDef fixtureDef;
fixtureDef.shape = &circleShape;
fixtureDef.density = 0.1;
fixtureDef.restitution = 0.05;
fixtureDef.friction = 1.0;

// より大きな値を設定すればより弾力をもつ
float springiness = 4.0;

// Delta angle to step by
float deltaAngle = (2.f * M_PI) / NUM_SEGMENTS;

// ホイールの半径
float radius = 50;

// ジョイントを接続する時に参照し直せるように
// ボディを保持しておく必要がある

NSMutableArray *bodies = [NSMutableArray array];

// 各セグメントの処理
for (int i = 0; i < NUM_SEGMENTS; i++) {
// 現在の角度
float theta = deltaAngle*i;

// θからx、y座標を計算する
float x = radius*cosf(theta);
float y = radius*sinf(theta);

// Box2dの座標に変換する為にPTM_RATIOで割ることを覚えておいてください。
b2Vec2 circlePosition = b2Vec2(x/PTM_RATIO, y/PTM_RATIO);

b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
// ポジションは中央に関連づけられるべきです
bodyDef.position = (center + circlePosition);

// ボディとフィクスチャを生成する
b2Body *body;
body = world->CreateBody(&bodyDef);
body->CreateFixture(&fixtureDef);

// 後でジョイントを接続する為に配列に追加します。


// b2BoydはC++のオブジェクトなのでNSMutableArrayにインサートする場合には
// NSValueでラップしなければなりません。

[bodies addObject:[NSValue valueWithPointer:body]];
}

// 内側の中央の円
b2BodyDef innerCircleBodyDef;
innerCircleBodyDef.type = b2_dynamicBody;
// ポジションを中央に
innerCircleBodyDef.position = center;
b2Body *innerCircleBody = world->CreateBody(&innerCircleBodyDef);
innerCircleBody->CreateFixture(&fixtureDef);

// ジョイントを接続
b2DistanceJointDef jointDef;
for (int i = 0; i < NUM_SEGMENTS; i++) {
// 隣
int neighborIndex = (i + 1) % NUM_SEGMENTS;

// 現在と隣のボディを取得する
b2Body *currentBody = (b2Body*)[[bodies objectAtIndex:i] pointerValue];
b2Body *neighborBody = (b2Body*)[[bodies objectAtIndex:neighborIndex] pointerValue];

// 外輪の円をそれぞれ接続する
jointDef.Initialize(currentBody, neighborBody,
currentBody->GetWorldCenter(),
neighborBody->GetWorldCenter() );
jointDef.collideConnected = true;
jointDef.frequencyHz = springiness;
jointDef.dampingRatio = 0.5f;

world->CreateJoint(&jointDef);

// 中央の円を外側の円と接続する
jointDef.Initialize(currentBody, innerCircleBody, currentBody->GetWorldCenter(), center);
jointDef.collideConnected = true;
jointDef.frequencyHz = springiness;
jointDef.dampingRatio = 0.5;

world->CreateJoint(&jointDef);
}

}

@end



ふー、以外とブログに載せるの大変だなぁ・・・。
ブログに載せる用にプラグインでもいれるかぁ。

part2は訳とプログラムは出来ているのでちょっとまってください。
ではでは。
を作成しました。

Android用です。

メニューボタン押したり横にスライドしたりすると左と右から別画面のメニューが出てくる
あれです。


サンプルも公開しました。
表示したいFragmentを指定するだけで動くようにしてあるので多分便利だとは思います。たぶんね^^;

不備が色々あると思いますが、オープンソースなので直してくれると助かりますww

ソースはgithubで公開してます。

Github :
SlideMenu
サンプル
最近「Coders at Work」という本を読んでます。

たまたま先週本屋によって技術本を探していたら見つけました。

最初はなんとなくデザインが気に入って手に取ってみたんですが、これが
なかなか面白い。

内容としては凄腕プログラマー15人へのインタビューを載せたもの
なんですが、どうやってプログラミングを始めたのか、どんなことをしてきたか
どうやってプログラムを設計、デバッグするとかそんな話がのってます。

それらの話も参考になるし、やっぱりトップで活躍する人たちの意見は参考に
なります。

耳が痛くなるような意見も多々あります(笑)
自分はまだまだ理解が足りないなと思わされます。

最近はプログラミングというかコンピュータを根源から
理解しないでかく人が多くなっているのは事実で(自分も含め)
この辺は本当にもっと理解しないとダメだなと思いました。

これはこの本を読んだからって訳じゃなく、仕事をしてても
思うことでした。よりそうあるべきだなと思うようになりましたね。

もっと学生の頃に勉強すべきだったと思います。
勉強したつもりではいたんだけど、つもりでした^^;

まぁ実はまだ4人分しかよんでいないんですが(笑)
それでも160ページよみました。かなり長いです・・・

でも読む価値はあると思うので正月にでもゆっくり読もうと思います。

気になったら是非手に取ってみてください。

Coders at Work プログラミングの技をめぐる探求/オーム社

¥2,940
Amazon.co.jp