Categories

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

« June 2009 | Main | September 2009 »

August 24, 2009

pygletの大幅な方向転換

 pygletの昔のサンプルと今のサンプルの構造が大きく違うことに気がついた。どうやら1.0から1.1になったときにメインループの作りがかわったらしい。これは1.0から2.0ぐらいの違いじゃないかと思う。

pyglet プログラミングガイド

アプリケーションイベントループ

pyglet 1.0を用いた全てのアプリケーションは、以下の様に、独自のイベントループを提供していた:

while not window.has_exit:  
  dt = clock.tick()
  update(dt)

window.dispatch_events()
  window.clear()
  draw()
  window.flip()

幾分くどい形式である上に、このイベントループの形式はより多くのウィンドウに拡張することが難しく、アプリケーションが何もしていなくても全ての有効なシステムリソースを使い果たす。

新しい pyglet.app モジュールはCPUにほとんど依存せずユーザイベントの応答を良くしているアプリケーションイベントループを提供している。空のウィンドウが開く完全なアプリケーションは以下の様に書ける:

window = pyglet.window.Window()

@window.event

def on_draw():

    window.clear()



pyglet.app.run()

注目してほしいのは、新しい on_draw イベントである。これは各ウィンドウに異なる描画関数を設定することを容易にする。 pyglet.app イベントループはイベントの送出、クロックの作動、描画関数の呼び出し、ウィンドウバッファの反転の処理をする。

この流儀に従って1.1の基本部分を書き直すと以下のようになる。

#

import pyglet

from pyglet import clock

window = pyglet.window.Window()

@window.event

def on_draw():

window.clear()



def update(dt):

print "UPDATE"



clock.schedule(update)



pyglet.app.run()

on_draw関数はしょっちゅう呼ばれて再描画されている。つまりは画面のリフレッシュレートにゲームの進行をあわせなくても良いということだ。
 ちょっと気持ち悪いけどね。

 

August 23, 2009

pygletを使おうとしたら、エラーが出ます

 cocos2dをインストールする時にpygletを前もってインストールする。
pygletとは何?と調べてみたら結構良くできたライブラリであることがわかった。
pyglet プログラミングガイド
これはぜひ使ってみなければ。

Hello worldをテストしたら、以下のようなエラーが出た。

pyglet.gl.lib.MissingFunctionException: glGenBuffers is not exported by the available OpenGL driver.
VERSION_1_5 is required for this functionality.

調べてみると、pygletのバグらしい。
pyglet.gl.lib.MissingFunctionException - pyglet-users | Google グループ

C:\Python25\Lib\site-packages\pyglet にある __init__.pyの
'graphics_vbo': をFalse,にすれば直った。

アクセラレーションを無効にするということかな。

August 22, 2009

iphone向けではないcocos2d のHello, World

リンク: Hello, World.

cocos.layer.Layer から派生させてLayerを作成
labelをcreateしてLayerにadd

directorを初期化
先ほど作成したLayerを引数にSceneを作成して準備完了

directorを実行

というわけで、addしておけばdirectorが勝手に実行しているというのはcocosの基本構造みだいだ。

August 19, 2009

cocos2dはもともとiphoneだけのものではない

チュートリアル以降 cocos2d iphoneの解説を探しているのだが見つからない。
そもそもcocos2dってなんだ、ということで調べてみたら、pythonをベースにしたマルチプラットフォームのゲームフレームワークだったみたいだ。
cocos2d

 あらかじめpythonでプロトタイプが作れれば便利かもしれない。
macではcocos2dとpigletをインストールしたらあっさり動いた。

windowsではちょっと面倒だ。

File "hello_world.py", line 11, in
import cocos
File "..\cocos\__init__.py", line 64, in
pyglet.resource.reindex()
File "C:\PythonPackages\pyglet\pyglet\resource.py", line 327, in reindex
'Backslashes not permitted in relative path'
AssertionError: Backslashes not permitted in relative path

というようなエラーがーでたら、cocosの__init__.pyを修正しないといけない。
pyglet.resource.path.append(os.path.join(os.path.dirname(__file__), "resources").replace('\\', '/'))

情報元:
Issue 121 in los-cocos: AssertionError: Backslashes not permitted in relative path - cocos2d issues | Google グループ

openGLのドライバーの問題もあって、すんなり動かないかも。

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 を使い始めてみた

« June 2009 | Main | September 2009 »