iPhone用2Dゲーをやたら簡単につくれるcocos2dの紹介とTips

iPhoneゲー開発日記その3。


今回は、iPhone用の2Dゲーム開発フレームワーク「cocos2d for iPhone」を簡易紹介してみます。

ぼく自身が「つくる前に読んで見たかったなあ」と思う、あえて細かい話は置いといて、雰囲気だけ伝える感じでまとめます。またぼくが作ったゲームで使った機能が中心になります(といっても、基本的なところのみだと思いますが)


その1
個人でかんたんiPhoneゲーム制作、愛と勇気とかしわもち、cocos2dについてのまとめ - カタテマ日記

その2
2011-10-07 - カタテマ日記


cocos2d for IPhoneとは

ぼくはもともとObjective-Cは全く知らなかったし、できればObjective-Cは避けたいなあ...と思っていたのですが、いざやってみると、言語周りはあまり苦になりませんでした。

間違いなく、cocos2dがゲーム制作まわりのいろいろを面倒をみてくれたおかげで、本質的でない部分の負荷が減ったおかげだと思います。

ぼくがcocos2dでつくったやつ

「愛と勇気とかしわもち」

http://itunes.apple.com/jp/app/love-mochi/id464653777

いわゆるマッチ系パズルに属すると思います。


cocos2dのインストール

インストールはすぐ終わります(必要なもの:Mac)

http://www.cocos2d-iphone.org/download

最新版(現在は「cocos2d-iphone-1.0.1.tar.gz」)をダウンロードしてどっかに展開。

コマンドラインから以下を実行でインストール完了。

sudo ./install-templates.sh

これだけで、Xcodeのプロジェクト新規作成からcocos2dプロジェクトが作れるようになります。


ビルドするだけで「Hello World!」がうごきます。

縦持ち専用にする

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
	return NO; // この行を追加
	...

これは任意ですが、単にぼくが作ったゲームではこうしているので、とりあえず。

とりあえず絵を出す

とりあず細かい話は置いておいて、HelloWorldLayer.mのinitメソッドの後ろに足していけば、いろいろ遊べます。

// 160,240の位置に絵を出す
CCSprite *s = [CCSprite spriteWithFile:@"Icon.png"];
s.position = ccp(160, 240);
[self addChild:s];



すげー簡単ですね。

必要ならz軸も指定することができます。

CCSprite *s = [CCSprite spriteWithFile:@"Icon.png"];
s.position = ccp(160, 240);
[self addChild:s z:1]; // z軸指定

z軸が同じだと、後から追加されたのが上に表示されるっぽいです。

グラフィックは、勝手にキャッシュされて、次回以降は使い回されます。

アクション

「N秒かけてXXする」みたいなのが簡単に処理できます。

3秒かけて(10,20)の位置に移動する。

CCSprite *s = [CCSprite spriteWithFile:@"Icon.png"];
s.position = ccp(160, 240);
[self addChild:s z:1];

CCMoveTo *m = [CCMoveTo actionWithDuration:3 position:ccp(10,20)];
[s runAction:m];

3秒かけて、今の位置から見て(100,20)の位置に移動する。

CCSprite *s = [CCSprite spriteWithFile:@"Icon.png"];
s.position = ccp(50, 100);
[self addChild:s z:1];

CCMoveBy *m = [CCMoveBy actionWithDuration:3 position:ccp(100,20)];
[s runAction:m];

全体的に〜Toだと最終的な値そのものを指定、〜Byだと今の状態からの相対的な値の指定になります。


他にも、CCScaleTo/CCScaleBy(拡縮)、CCRotateTo/CCRotateBy(回転)、CCFadeTo(透明度)などなど用意されています。

この辺は便利すぎる必須機能で、ぼくが作ったゲームでもあらゆるところで使っています。

アクションの組み合わせ

複数のアクションを順番に実行したり、同時に実行したりするには、CCSpawnやCCSequenceを使います。

CCSprite *s = [CCSprite spriteWithFile:@"Icon.png"];
s.position = ccp(50, 100);
[self addChild:s z:1];


同時に
// 1:移動
CCMoveBy *a1 = [CCMoveTo actionWithDuration:3 position:ccp(100,200)];
// 2:5倍に拡大
CCScaleTo *a2 = [CCScaleTo actionWithDuration:2 scale:5];
// ..を、同時に実行
CCSpawn *m = [CCSpawn actions:a1,a2,nil];
[s runAction:m];


順番に

CCSprite *s = [CCSprite spriteWithFile:@"Icon.png"];
s.position = ccp(50, 100);
[self addChild:s z:1];

// 1:移動
CCMoveBy *a1 = [CCMoveTo actionWithDuration:3 position:ccp(100,200)];
// 2:5倍に拡大
CCScaleTo *a2 = [CCScaleTo actionWithDuration:2 scale:5];
// ..を、順番に実行
CCSequence *m = [CCSequence actions:a1,a2,nil];
[s runAction:m];


他にも、くりかえすためのCCRepeatとかCCRepeatForeverといったものもあります。

たとえば、タイトルロゴを上下にゆらすのは、上移動アクションとした移動アクションを、CCRepeatForeverしています。

ちょっと変化をつけた動き

ふつうに「N秒かけて(100,200)の位置に移動」みたいに書くと等速運動になりますが、「はじめは勢い良く、最後はゆるやかに」みたいな感じにすることもできます。

そのために使うのは、CCEaseIn/CCEaseOutなど。

CCSprite *s = [CCSprite spriteWithFile:@"Icon.png"];
s.position = ccp(50, 100);
[self addChild:s z:1];

CCMoveBy *a1 = [CCMoveTo actionWithDuration:3 position:ccp(200,200)];
//CCEaseIn *m = [CCEaseIn actionWithAction:a1 rate:5];
CCEaseOut *m = [CCEaseOut actionWithAction:a1 rate:5];

[s runAction:m];


詳しくはこのへん。
http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:actions_ease



アクションと同じ感覚で使える、メソッド実行の「CCCallFuncND」というものがあります。

「アニメーションが終わったときにメソッド実行」みたいなことができるので、「アニメーション終わった後に音をならす」「アニメーション終わった後に解放」などなどが簡単にできます。

BGM

[[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"xxx.mp3"];

効果音としてxxx.wavを鳴らす。

[[SimpleAudioEngine sharedEngine] playEffect:@"xxx.wav"];

画像と同じく音は勝手にキャッシュされるので、2回目移行は高速です。逆に言うと1回目は遅いので、それがまずいときは事前にporeloadしておきます。

[[SimpleAudioEngine sharedEngine] preloadEffect:@"xxx.wav"];

シーン

ここまではガンガン適当にスプライトを追加していっていますが、このまま適当にやっていると破綻します。
複雑なものを分割して管理するために、cocos2dにはレイヤーとかシーン管理機能もあります。

「愛と勇気とかしわもち」では、以下のようなシーンを作りました。

  • Title
  • Play
  • GameOver
  • Text
  • Movie

で、各シーンに応じてLayerを定義して、Scheneが保持します。
(例:TitleシーンはメインとなるLayerを保持し、そこにキャラクターやらアイコンやらロゴやらを配置する感じです。そして、ヘルプ表示時は別途定義してあるHelpLayerを生成して重ねる)


シーンからシーンへの切り替えは、こんな感じで。

// タイトルシーンへ
TitleScene *nextSchene = [TitleScene node];
[[CCDirector sharedDirector] replaceScene:nextSchene];

他、必須すぎるけどソラで書けないコード

定期的に処理
//0.1秒後度にupdateを実行
[self schedule:@selector(update) interval:0.1];
// 定期更新メソッド
- (void) update
{
  // なんかを0.1病後度に実行
}
タッチ
self.isTouchEnabled = YES;

Layerなどで上のコードを書いておいて、以下のようなメソッドを定義しておくと、タッチしたときに勝手にメソッドが実行される。

// タッチ開始
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	UITouch *touch = [touches anyObject];
	CGPoint location = [touch locationInView:[touch view]];
	location = [[CCDirector sharedDirector] convertToGL:location];
	...
// タッチ移動
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
	UITouch *touch = [touches anyObject];
	CGPoint location = [touch locationInView:[touch view]];
	location = [[CCDirector sharedDirector] convertToGL:location];
	...
// タッチ終了
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
	UITouch *touch = [touches anyObject];
	CGPoint location = [touch locationInView:[touch view]];
	location = [[CCDirector sharedDirector] convertToGL:location];
	...


location.x、location.yで、さわったところの位置がとれる。

本作での「さわってからスワイプで回転」する処理は、タッチ開始した位置を覚えておいて、移動イベントで移動距離が一定量を超えたら処理、みたいにわりあい泥臭くやっています。

他、興味深い機能

  • パーティクル
  • 物理エンジン(Box2D/Chipmunk)
  • テキスト表示
  • 高速に描画する工夫(CCBatchNode)

ゆにばーさる

デフォルトでと、iPhone/iPad両対応のユニバーサルなアプリになります。


ただ、iPad/iPhone両対応にすると、縮尺などを両者に合わせて開発するのは大変そうだったので「愛と勇気とかしわもち」では、iPhone(&iPod)専用にしています。こうすると、iPadではエミュレータ上での動作になります。


本作はiPadでもエミュレータ上でプレイできますが、拡大するとちょっと画像が荒くなります。近々Retina対応する予定で、そうすればかなり良い感じになる気がします。


iPhone(iPod)専用にするための設定方法は、わすれました。

まとめ

ここまで紹介した機能だけでも、簡単なゲームなら簡単につくれそうな気がしないでしょうか? はい、実際に、本当に簡単につくれます。

cocos2dには他にもいろいろな機能があるので、本気でつくるかたはぜひ書籍などをあたってみてください。

他、参考資料

素晴らしすぎるcocos2dスライド。

概要
Hello cocos2d ios

実戦テク
Advanced cocos2d