Categories

  • Android開発
    android marketで目指せ億万長者(ウソ)
  • cocos2d
    pythonでも使えるゲームフレームワーク
  • Google
    ここには未来を開くためのAPIがたくさん用意されている。
  • GoogleAppEngine
    どこまでもスケールアウトするクラウドサービス。使いこなすのが大変
  • Hack
    様々な電子機器を本来の用途とは別の用途に使ってみる。
  • iPhone開発
    app storeで目指せ億万長者(ウソ)
  • python
    LightWeightLanguageで一番難しいがLispにも通じるところがある面白い言語。
  • TIPS
    覚えておくともしかしたら役に立つかもしれないチョットしたこと。
  • うまくいきません
    やってみたけど、うまくいかなかった失敗記事
  • ネット世界
  • 夢見るソフトウェア
    こんなのいいな、できたらいいな、いつかつくろう
  • 開発環境
    開発するまえに環境を整えた記録、次に同じことをするためめの忘備録
無料ブログはココログ
My Photo

August 16, 2009

cocos2dの練習 Game Demo Tutorial #3: Collisions & Particle Systems をやってみた

Game Demo Tutorial #3: Collisions & Particle Systems

前回に行き続き、MAC DEVのチュートリアル3番
Mac Dev » Game Demo Tutorial #3: Collisions & Particle Systems

このエントリーではchipmunkを使った衝突検出を使う。そして、パーティクルも使う。
その前にソースコードをダウンロードしてrock.pngをリソースに追加する
まず、小惑星を表示したいので、makeSpaceRockXをbullet同様に書く。
collisionのところにNEWのコメントがついているが、まだ衝突検出しないので実装しない。


//破壊すべき小惑星を作ってみる
-(void) makeSpaceRockX: (float) x y:(float)y
{
     Sprite *rock = [[SpritespriteWithFile:@"rock.png"] retain];
     rock.position = cpv(x,y);
     [selfaddChild: rock];
     cpVect verts[] = {
          cpv(-54,-43),
          cpv(-54, 43),
          cpv(54, 43),
          cpv(54,-43),
     };
     cpBody *rockBody = cpBodyNew(200.0f, INFINITY);
     rockBody->p = cpv(x, y);
     rockBody->v = cpv(0, 0);
     cpSpaceAddBody(space, rockBody);
     cpShape * rockShape = cpPolyShapeNew(rockBody, 4, verts, cpvzero);
     rockShape->e = 0.9f; rockShape->u = 0.9f;
     rockShape->data = rock;
     //rockShape->collision_type = 0; //New!
     cpSpaceAddShape(space, rockShape);
     //cpSpaceAddCollisionPairFunc(space, 0, 1, &bulletCollision, self); //Also new!
}
ここで実行。よーし、絵が出た。楽勝だ。

次に衝突検出だ


まずは先ほどのコメントを外して小惑星のcollision_typeを0
rockShape->collision_type = 0; //New!
おなじく衝突検出のコールバック設定もコメント解除
0とか1とかはcollision_typeで設定した数値。2つしか設定できない。だってPairだもん。
cpSpaceAddCollisionPairFunc(space, 0, 1, &bulletCollision, self); //Also new!

弾のcollision_typeを1
laserShape->collision_type = 1; //this is new!

衝突検知したときにコールバックされる関数は、クラス外に置く
staticint bulletCollision(cpShape *a, cpShape *b, cpContact *contacts, int numContacts, cpFloat normal_coef, void *data)
{
GameLayer *game = (GameLayer*) data;
a->body->p = cpv(800,800);//画面外へ
b->body->p = cpv(800,800);//画面外へ
//[game createExplosionX:200 y:200];//これはまだ実装していないのでコメントアウト
return0;
}

これで実行、弾を打って小惑星にあ当たると、弾も小惑星も消える。
さて、衝突したら爆発して欲しいので、パーティクルを使った爆発を作る。
新しいソースでRockExplosionを追加します。名前がかっこいい。

いつものNSObjectから派生させるのではなく、PointParticleSystemから派生させる。
#import "TextureMgr.h"
をRockExplosionに追記するのを忘れないように
positionが見つからないのでコンパイルエラーになる。コメントアウトしちゃえ。

GameSceneにcreateExplosionXを実装して、先ほどのコメントを解除。
RockExplosionの後ろについているnodeってなんだ?


-(void) createExplosionX: (float) x y: (float) y
{
     ParticleSystem *emitter = [RockExplosion node];
     emitter.position = cpv(x,y);
     [self addChild: emitter];
}

今回の爆発で使用したパーティクルシステムは初期化しかない。
そのかわり初期化で設定するものが大量にある。


-(id) initWithTotalParticles:(int)p
{
if( !(self=[superinitWithTotalParticles:p]) ) return nil;
// duration
duration = 0.1f; //パーティクルを発生させている期間
// gravity
gravity.x = 10; //重力
gravity.y = 10;
// angle
angle = 90; //発射する角度 0で右水平
angleVar = 360; //発射する角度の広がり 360すなわち全方向
// speed of particles
speed = 200; //発射速度
speedVar = 40; //発射速度のばらつき範囲
// radial
radialAccel = 0; //放射するときの加速度
radialAccelVar = 0;//上のばらつき範囲
// tagential
tangentialAccel = 0; //接線方向への加速度、これを設定すると渦を巻きながら飛んでいく
tangentialAccelVar = 0;//上のばらつき範囲
// emitter position
/*position.x = 160;//これは,setPositionで設定することになったみたい。
position.y = 240;
*/
posVar.x = 0; //与えられた初期位置からの横方向のばらつき
posVar.y = 0; //与えられた初期位置からの縦方向のばらつき
// life of particles
life = 10.0f; //パーティクルを発生し続ける時間
lifeVar = 2;
// size, in pixels
startSize = 40.0f; //発生源の大きさ?
startSizeVar = 20.0f;
// emits per second
emissionRate = totalParticles/duration;
// color of particles
startColor.r = 0.99f; //初期カラー
.....endColorVar.a = 0.0f; //終了時のカラー
//テクスチャーの割当。 TextureMgrを使えばいちいちファイルからロードしない?
self.texture = [[TextureMgrsharedTextureMgr] addImage: @"rock.png"];
// additive
blendAdditive = NO; //不明
return self;
}

blendAddtiveだけがわからない。発生個数を4ではなく、20ぐらいにすると気持ちいい.

ということでMAC DEVのチュートリアル終わっちゃった。続きでないかな。

今回も参考にさせていただきました
shukujitsuの開発ブログ : MAC DEVのサンプルを読む その2 - livedoor Blog(ブログ)

cocos2dの練習 Game Demo Tutorial #2: Hello Spaceをやってみた

どこから取り組んだらいいのかよくわからないcocos2dのとっかかりとして、Mac DEVでチュートリアルが提供されている。

Mac Dev » Game Demo Tutorial #2: Hello Space

読んでいるだけでなく、実際にやってみた。
もともとのチュートリアルはcocos0.72をベースにしている。現時点での最新バージョンは0.81だ。
ダウンロードしたサンプルを実行して確認した後、0.81のテンプレートに入れて動かす

まずは LandscapeをFALSEにして縦横を修正
resourceにbg.pngおよびship.pngを追加する。しかしながら、何故かターゲットディレクトリにコピーされないので手動でコピーした。

retainというのはなんだろうな。ソースコードを調べてみるとテクスチャーデーター管理で、頂点データーのバッファーを確保するときに頂点サイズに掛け合わされている。どこで定義されているかはわからないが、増減すると書いてあるので変にいじらない方がよさそうだ。
Sprite *bg = [[Sprite spriteWithFile:@"bg.png"] retain];

表示位置は以下のように指定する。いやbg.position=で代入してもいいんだけどね。オブジェクトに大しては中心点。
cpvは物理エンジンchipmunkのベクター型らしい。中にはx,yのfloat

[bg setPosition:cpv(160,240)];

Spriteの定義をするのは、Ver0.81ではGameSceneではなくGameLayerのほうがよさそうだ。
Bulletを後回しにしてビルド、宇宙船が左右に移動する。

@selectorはセレクターをオブジェクトのメソッドから取得する。関数へのポインタみたいなものか?Objective-C良くわからない。
 schedule にセレクターを渡すと、定期的に呼び出してくれるみたいだ。

[self schedule: @selector(moveShip:)];

呼び出されるmoveShip関数にはdtが引数としてついてくる。前回呼び出されたときの時間との差分らしい。
もっと精度が必要であればdoubleで再定義しろとマニュアルに書いてある。

-(void) moveShip: (ccTime) dt{

次は後回しにした弾つまりBulletに取り組む。なんと、いきなり物理エンジン登場

cpInitChipmunk();
space = cpSpaceNew(); //空間を定義
cpSpaceResizeStaticHash(space, 400.0f, 40);//演算の高速化のためのハッシュ領域の大きさを調整
cpSpaceResizeActiveHash(space, 100, 600);
space->gravity = cpv(10, 0); //重力の方向
space->elasticIterations = space->iterations;//弾性物体の反復処理、デフォルトを使う
//Update Chipmunk
[self schedule: @selector(step:)]; //スケジューラーに定期的にstepを呼び出してもらう。

//弾10個分を初期化する
bullets = [[NSMutableArrayalloc] init];
for(int i = 0; i <10; i++)
{
Bullet *b = [[Bullet alloc] initWithCPBody:[self makeBulletX:-50 y:-50]];//初期位置は画面外
[bullets addObject: b];
[b release];
}

bulletsは配列、各要素を呼び出すときは以下のようなループが使える。
 for(Bullet *b in bullets){}
ここでようやくObjective-Cがかっこいいと思う

BulletクラスにはcpBodyとreadyのフラグしかない。NSMutableArrayに直接格納できないのでラッパーとしての役割の方が大きい。
bulletBodyに対して直接外から代入しても良さそうなものだが、BulletはinitWithCPBody:でオブジェクトを作成する。

(id) initWithCPBody: (cpBody *) bodyIn
{
self = [super init];
if(self != nil){
bulletBody = bodyIn;
ready = YES;
}
return self;
}

cpBodyの定義はこちら 
http://code.google.com/p/chipmunk-physics/wiki/cpBody
cpShapeの定義はこちらをみたほうが早いかも
http://code.google.com/p/chipmunk-physics/wiki/cpShape

-(cpBody *) makeBulletX: (float) x y:(float) y
{
Sprite *laser = [[SpritespriteWithFile:@"laser.png"] retain];
laser.position = cpv(x, y);
[self addChild: laser]; //スプライトとして画像を追加

cpVect verts[] = { //あたり判定で使用するobjectの大きさを定義
cpv(-7,-10),
cpv(-7, 10),
cpv(7, 10),
cpv(7,-10),
};
//質量100.f慣性モーメント無限大で作成
cpBody *laserBod = cpBodyNew(100.0f, INFINITY);
laserBod->p = cpv(x, y);
laserBod->v = cpv(0, 0);
//物理空間に追加 body
cpSpaceAddBody(space, laserBod);
cpShape * laserShape = cpPolyShapeNew(
laserBod, //cpBody
4, //頂点数
verts, //頂点座標
cpvzero //中心点
);
laserShape->e = 0.9f;// Elasticity つまり弾性。0.0で無反射、いかなる場合も1.0を超えるな
laserShape->u = 0.9f;// Friction coefficient つまり摩擦係数。0がツルツル
laserShape->data = laser;// ユーザーデーターにSpriteを関連づける
//物理空間に追加 shape
cpSpaceAddShape(space, laserShape);

return laserBod;
}
摩擦係数の設定に関してはこちらを見るといいらしい。
http://www.roymech.co.uk/Useful_Tables/Tribology/co_of_frict.htm


物理エンジンは定期的に呼び出してあげないと動作しない。
呼び出しの頻度が多いほどシミュレーションは正確になるが、CPUの負担になる。
このサンプルでは、呼び出し回数を2倍にしている。
http://code.google.com/p/chipmunk-physics/wiki/cpSpace

-(void) step: (ccTime) delta
{
int steps = 2;
cpFloat dt = delta/(cpFloat)steps;
for(int i=0; i cpSpaceStep(space, dt); //物理エンジンをすすめる
}
cpSpaceHashEach(space->activeShapes, &eachShape, nil);//ハッシュの更新
cpSpaceHashEach(space->staticShapes, &eachShape, nil);//ハッシュの更新
[self updateBullets];
}
cpSpaceHashEachについてはドキュメントに記載されていない。

最後にupdateBulletsが呼び出されている。これは画面外に出た弾を初期化して次の発射に備えて再利用するためのものだ。
弾の位置を更新するというような作業は物理エンジンがやってくれる。でも、方向ベクトルは処理されているのに、グラビティが無視されているのは何故だろう。次のチュートリアルで考える。

-(void) updateBullets
{
for(Bullet *binbullets)
{
if([bgetY] >500)
{
[b resetPosition];
[b setReady: YES];
break;
}
}
}

タッチしたら弾を発射するようにするには、まずisTouchEnabled = YESが初期化で行われていなければならない。
幸い、フレームワークを使うと既に入っているので、特に追加することはない。
フレームワークでは、画面をタッチするとメニューに戻るようになっているのだが、戻ると困るのでこれはなくす。
そういえばiphoneのゲームの基本構造として、起動画面→メニュー→ゲーム開始→終了→メニューとなっているので、ゲーム内のどこかにメニューに戻る仕掛けが必要になるのか。
 その場合、次のゲームでSceneとかLayerの初期化とかどうなるんだろう。前回のものを解放しないで、再初期化すればいいんだろうか。addObjectで追加しまくっているので、これを全部管理して解放するなんてぞっとする。
 なんてことは後で考えるとして、弾を撃たなきゃ。

- (BOOL)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for(Bullet *b in bullets) //foreachみたいなもの、かっこいい
{
if([b ready])//唯一のメンバ変数 ready 使用可能な状態
{
[b fireFromX:ship.position.xy:ship.position.y+12];//自機の前から発射
[b setReady: NO];//@synthesizeで自動生成されたセッター
break;
}
}
return kEventHandled; //処理が終わりましたというフラグを返さないといけない
}
もちろん10個全部を撃ったら、再利用が可能な状態になるまで弾が出ない。

fireFromXは弾の初期位置と速度を設定する。
-(void) fireFromX: (float) x y:(float)y
{
 bulletBody->p = cpv(x,y);
 bulletBody->v = cpv(0, 200);
}

 物理計算を行うだけでスプライトの位置も一緒に更新されるのは実にありがたい。
不思議な現象は、物理上の位置と表示上の位置がずれていることに起因するケースがあるからだ。

さて、次はチュートリアルの#3をやるか。

以下のブログを参考にさせていただきました。
shukujitsuの開発ブログ : MAC DEVのサンプルを読む その1 - livedoor Blog(ブログ)


余談だが、ココログにプログラムのソースコードを掲載するのは、インデントも強調表示も色分けも何もかも難しい。

August 15, 2009

cocos2dのリファレンスマニュアル

 cocos2dのリファレンスマニュアルはdoxygenで作るらしい。
Integrating cocos2d API reference into XCode « cocos2d for iPhone
リンク先のページにあるように、doxygenをインストールしたら、cocos2d-iphoneの中にあるプロジェクトを開いて、アクティブターゲットをcocos2d-documentation を選択してビルドしたらおわり。
ヘルプからリファレンスマニュアルを検索できるようになった。
Inherit__graph__3

ちょっとはわかってきたかも。

マップエディター Tiled

cocos2d v0.81betaでTMXがサポートされました。で、TMXって何だ?
Tiledというマップエディターがあるらしい。早速ダウンロードしてみた。javaなのでwinでもmacでも実行可能。
20090815_0947

トップビューのマップだけではなく、ヘックスのマップやage of empireのような斜め上視点のマップも編集できる。
こういうのはハウスツールかmodではあったが、ジェネリックなマップエディターというのは初めて見た。

Tiled, a generic tile map editor

August 14, 2009

結局はシェルからコマンド

 xcodeは今ひとつ気がきいていないことがあって、結局はシェルからコマンドを打ち込んだ方が早いことが多い。
 cdでディレクトリを移るのが面倒になるので、複雑なディレクトリ構造を作らず、日本語のディレクトリ名なんてもってのほかというスタンスでやっていたのですが、なんだかそれも大変で。

OpenTerminalHere 2.1というアプリケーションを見つけてしまいました。
 これを、Finderに登録しておくと、開いている場所でターミナルを開きます。最初にcd不要。これは便利だ。

20090814_2057

ダウンロードはここから。
Download OpenTerminalHere for Mac - Open Terminal with currently highlighted directory. MacUpdate Mac AppleScript Software Downloads

やっぱり、横断検索は

find . -name '*' -exec grep 'foo' {} ¥;

のほうがGUIより早い。

August 10, 2009

エリカ様はgitに乗り換えたようです


 iPhone デベロッパーズクックブック (通称 エリカ本)を読んでおります。 エアコンの風が心地よい眠りを誘い、なかなか読了できません。
 iPhone デベロッパーズ クックブック

サンプルを見ようと本人のページを見たところ、ソースコード管理が3.0からgoogleからgitにかわっております。
こちらの方がいいんでしょうか。

ericasadun.com
githubは100Mまで無料で使えます。
erica's iphone-3.0-cookbook- at master - GitHub

使ってみようかな
参考:[観] git と github を使い始めてみた

May 06, 2009

意味不明のエラー

 iphoneの開発をしていると、突然デバッグでiphoneシミュレーターが落ちることがある。存在しないオブジェクトやメッセージの引数が間違っているのが原因だ。元はといえばスペルミスだったりする。

 たかだかスペルミスでここまで派手に落ちることはないと思うが、動的なプログラムが組めるObjective-Cだからエラーの検出が難しいのだろう。

 プログラムをタイプしていて補完されないようなら、一旦消して打ち直す慎重さは必要なのかもしれない。めんどくさいなあ、まったく。

 

UIViewはどこまでマスターすればよいのだろうか

UIButtonなどの多くのGUIで部品はUIViewを継承していたりするわけだが、UIVew自体が巨大なクラスで全部の機能を調べ上げるのは無理かもしれない。なにせ、C++と違ってObjective-Cは本気で隠蔽されてしまうので、ヘッダーを覗いてあれこれというのもできないし。

 適当なタイミングでOpenGL Viewに移行しようかと考えてたら、以下のような記事があった。

無為空間 | OpenGL ESとUIViewの比較

すばらしい。もう少しUIViewを調べてみようと思う。

 

May 04, 2009

iphone開発関連のRSS

iphoneでの開発を実際に行われている方のブログや、開発グループのお知らせなどをまとめました。
opml形式でインポートすれば、そのまま見ることができると思います。

macユーザーの伝統なのか、みんなで集まって直接情報交換することが多いみたいですね。

「export.xml」をダウンロード

May 03, 2009

iphoneにまたも転送できなくなりました。

 iphone実機に転送してデバッグをしようとすると、エラーが出るようになりました。

No provisioned iPhone OS device is connected.

 プロジェクトのプロパティもplistも設定してあります。

エラーメッセージで検索してみたところ、Organizerで見たときにデバッグに使用するiphoneが緑になっていないと転送できないとこと。

よく見ると以下のようなエラーが出ていました。

Your mobile device has encountered an unexpected error (0xE8000001)
Try disconnecting and powering off the device; then power the device on and reconnect it.

エラーメッセージにしたがって、iphoneを再起動したところつながるようになりました。

原因は不明。