だいたい47度

スポンサーサイト

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

PageTop

cocos2dのCCLabelクラス比較

CCLabelAtlasを使おうとしたのだけど、あまり資料がなかったのでメモ。

ラベル系クラスとしては、CCLabelTTF、CCLabelBMFont、CCLabelAtlasがあります。それぞれ、表示するフォントをどこから取ってくるかが異なり、そのため使い分けが必要です。

CCLabelTTF
CCLabelTTFは、フォントファイルを使ってラベルを描画するクラスです。otfファイルなどをAddしてplistに設定してあげるだけで使えます。

メリットとしては、よいフォントがあれば準備が必要ないこと、数多くの文字に対応できること、フォントサイズの変更が効くことなどが挙げられます。デメリットとしては、ゲーム内でのラベル書き換えが高コストであること、フォントまるまる入れるのでサイズが数MBは増えることなどが挙げられます。特に、CCLabelTTF書き換えコストは要注意です(CCLabelTTFはstringが書き換えられるごとにテクスチャを再作成します)。

以前作った百人一首アプリではこれを使っています。僕のゲームでは文字列をよく使いましたが、ほとんど書き換えが行われません。百人一首に使われている文字を全てチェックしてCCLabelBMFontにするのが面倒だったこともあり、CCLabelTTFを使いました。

CCLabelBMFont
CCLabelBMFontは、描画したい文字すべてを含んだビットマップフォントを使ってラベルを描画するクラスです。ビットマップフォント画像はHieroやGlyph Designerなどのアプリケーションを使ってつくるようです。

メリットとしては、なんといっても描画の高速性です。テクスチャの入れ替えだけなので速いです。既存のフォントを元に自分の大事にしたい文字のみを修正したりできるのもいいですね。世界観にフォントからこだわることができます。デメリットとしては、ビットマップフォント分だけのメモリを食うこと、ファイルサイズも大きいこと、フォントサイズを変更することができない(できるけど汚くなる)ことなどが挙げられます。サイズの問題から、自分が使う文字だけに絞る作業が必須であると思います。特に日本語。

CCLabelAtlas
CCLabelAtlasは、簡易なCCLabelBMFontのようなものです。Xcodeでプロジェクトを作ると自動的に入っているfps_images.pngがまさに良い例です。「./0123456789」という文字列が入っていますが、これはASCII文字順に並んでいます。使うときには各文字の幅と「.」から始まる文字列ですよ、と指定して使います。数値の他に特別にGとかだけ使いたいのなら「/」や「:;」にGを振ってしまうのもありですね。メリット・デメリットはCCLabelBMFontに近いですが、サイズが小さいことで幾つか違います。

CCLabelAtlasを作ってみる
まずルーラーを作ります。下のようなもの。後で横幅とかが必要になるので、先に横幅を決めてルーラーを作ってしまいます。Retina対応があるので、想定している大きさの倍で作ります。最後に画像で必要な部分を切り出すときも、ルーラーにあわせて切り出せるので楽。
ruler.png

あとはルーラーに合わせて、数字や文字をあわせていきます。できたものがこちら。とりあえす数字しか必要なかったので、記号は略。この画像はnumbers-hd.pngとして保存し、半分のサイズの画像をnumbers.pngとして保存しました。
damagenum-hd.png

コードは簡単。startCharMapで最初の文字を指定します。

CCLabelAtlas* label = [CCLabelAtlas labelWithString:@"987056" charMapFile:@"numbers.png" itemWidth:12 itemHeight:16 startCharMap:'0'];
label.position = ccp(160, 200);
[self addChild:label];


表示されました。アトラスに入っていない文字は空白扱いになります(上記で@"987.056"といれると「987(空白)056」という表記になります)。
cclabelatrassample.png

スポンサーサイト

PageTop

Box2Dでアニメーションのテスト(cocos2d)

Box2Dのシンプルなbodyにアニメーションをつけてみました。

前回、関節の動きによって移動する物体を作りました。その結果、パラメータ制御が面倒だけどキチンと制御しないとまともに動かないことが分かりました。また、最終型でも動きが不安定すぎてゲームには向かなそうでした。

動き自体はマヌケでよかったのですが、ゲームを成立させるために、もうちょっとシンプルな物体を使ってみようと考えました。その結果が下記の動画です。



今回の実装
今回は単純なボディを作りました。動画の中盤に表示していますが、四角に回転する円を一つつけただけです。倒れないように、毎Stepごとに角度を感知しインパルスをぶつけて補正してやっています(こちら参照)。また、同じ位置に20Step以上いた場合は方向を変えるようにしています。

アニメーションとしては下の5つの画像をテキストアトラスに入れて動かしました。うん、まぁなんとなく歩いているように見える。
penguin_anim1penguin_anim3penguin_anim2penguin_anim5penguin_anim4

アニメーションの管理は、以前の記事のchapter 3で述べたようにplistを使って行なっています。ペンギンクラスのinitでanimationをplistから読み込み、クラスの状況とCCSpriteのnumberOfRunningActionsが0かどうかを確認しながらCCAnimateを実行しています。このへんは完全にLearning Cocos2Dで学んだ通り。

アニメーションで使っているpngファイルのbodyへの貼り付けは、cocos2dのBox2Dテンプレートを開いた時にあるPhysicsSpriteを利用しています。上述のアニメーション管理や状態管理のため、CCSpriteを継承したGameObjectクラスを作り、PhysicsSpriteの親クラスをCCSpriteからGameObjectに切り替えます。あと、PhysicsSpriteのプロパティとしてworldも持たせておくと便利です。最後にPhysicsSpriteを継承したペンギンクラスを作ってやればOK。

わかったこと
安定した移動は作れる。がちょっとつまらん?
思ったより安定して動いていました。また物理エンジンを使った効果として適度に傾いてくれるので、5枚しか画像を用意しなかったにしてはそれなりに動いているように見えます。ただ、前回の方が動きの面白みがありますね……。

アニメーションのノウハウが必要
画像そのもののノウハウと、アニメーションするためのノウハウと両方必要そうです。とりあえず気づいたことを書きますが他にも多くのノウハウがあるのだろうな。

画像そのものについては、今回はテストなので適当に作るはずだったのですが、それでも何度か作り直しがありました。まず、最初に完全に真横を向いたキャラクタを作ったのですが、それよりちょっとこっちを向いた方が可愛いような気がして作り直しました。マリオとかもそんな感じだし。あとは、画像には枠線をつけたほうが良さそうです。足とかは枠線がないと動いているように見えないです。ただ今回のペンギンは何となく汚いので、枠線の付け方は考えなきゃいけなそう。

アニメーションのノウハウとしては、まず画像数を増やさなきゃいけません。ちょっとカクカクして見える。大体9-10枚くらいは必要そうです。また、画像ごとに細かい違いをいれなきゃいけないようです。たとえば歩くときは頭が上下動するものですが、今回は不動なのでリアルさも可愛さもなくなっています。

次のステップ
もうちょっとアニメーションに凝ってみようと思います。今回安定した動きでゲームとしても成立しそうですが、前回に比べてペンギンの動作の楽しさが減りました。ここをアニメーションの改善でカバーしたいです。ただ、アニメーションについてはどこまでもいってしまう話のような気がするので、とりあえず最低限のラインを超えれるように頑張ります。

また、物理エンジンを使って動くパーツを追加してあげる事で、動作をリッチに見せたいと思います。その際flipXのことを忘れないようにしないといけません。今回は羽もつけてみようと思ったのですが、flipXしたときにjointする点を変更しなきゃいけなかったため実装しなおしになり心が折れて辞めました。

上記2つでキャラクタがまともに動作するようならゲームの実装をしていこうかなー。

PageTop

Box2Dで二足歩行のテスト(cocos2d)

cocos2dのBox2Dを使った実験として、さっそく2足歩行のキャラクタを作ってみました。ペンギンのとてもアホらしい動きとなっています。動画の後半はデバッグモードの動画を載せています。


実装方法
実装としては、Prismatic Jointを4本使っています。

まず、ペンギンの横方向に動く四角AをPrismatic Jointでペンギン本体に紐付けます。各StepごとにhorizonalRevJoint->SetMotorSpeed(HOLIZONAL_SPEED);で横方向にモータを駆動させます。また、ペンギンの中心と四角Aの中心の距離を毎Step測定し、一定以上離れたら逆方向へモータが動くようにしています。

2つ目の四角Bを、四角Aと同じ位置に配置し、これも横向きのPrismatic Jointでペンギン本体に紐付けます。こちらは各Stepごとに、四角Aと反対の方向へモータを駆動させます。ただし、動いている内に四角Aと四角Bの位置がズレてきてしまうので、四角Aの鏡像の位置と四角Bの位置が0.1m以上離れた場合は、四角Aの鏡像の位置に向かってモータを駆動させます。

次に足Aを縦向きのPrismatic Jointで四角Aに紐付けます。衝突しないように、足Aにはペンギン本体と同じfixtureDef.filter.groupIndexを振っておきます。足Aには基本的に下向きのモータを駆動させておきます。ただし、四角Aが進行方向に向かっており、かつ四角Aがペンギンの中心に差し掛かっていない場合のみ、上向きにモータを駆動させます。こうすることで足は三角形の軌道を描き、足Bと交互に踏み出させることで進むわけです。

足Bは縦向きのPrismatic Jointで四角Bに紐付け、足Aと同じ実装にします。

ペンギン自体はただの四角ですが、倒れないように毎Stepごとに角度を感知して、適当なインパルスを与えてやっています(こちら参照)。あとmouseJointをできるようにはしてあります。バカっぽくするために卵のカラの帽子もかぶせました。

penguin2.png

penguin1.png

今回わかったこと
下手にGearを使うより、毎Step調整する方がうまくいったりする
一番最初の設計として、ひとつのRevolute jointを軸として、その回転をGear jointで四角A、Bに伝えるようにしていました。しかし、関わる要因が増えたためか、横移動がガタガタになってしまいました。そのため上記の設計をしたのですが、こっちの方が安定しているように思います。Gear jointのパラメータをうまく合わせればもうちょっとうまくいったのでしょうか。

パラメータ調整がめんどくさい、しかし大事
摩擦や重さなど、一つ一つのbodyのパラメータ調整がとても面倒くさいです。しかしながら、ひとつのbodyのひとつのパラメータを変えるだけで全体の動作も変わってきてしまうので、気を使わなくてはなりません。なんか地獄な気がするのですが、いい方法はあるのでしょうか……。

ダイナミックな動作をするには関節を増やすか、簡略化するしかなさそう
可動域を考えると、今回の設計ではちょっとした段差や坂道を超えられません。ので、やっぱり関節をふやしてやらなきゃいけないようです。が、それはパラメータが増えることを意味します。うーん。いっそのこと、キャラクタは四角にタイヤをつけたようなものにして、アニメーションでそれっぽく見せるのもありかもしれません。

jointの破壊の制御がめんどくさい
前回、「jointの破壊は紐付いているbodyの破壊によっても行われますが、基本的には手動で破壊しましょう」と書いたのですが、これ面倒くさいです。オブジェクト同士をつなぐものなので、deallocに書くにしてもどっちに書くか迷います。Learning Cocos2Dだと無視しちゃってるんだよなぁ……。Gear Jointだけ気をつけておくか……。

iPhone画面狭い
関節の多いものをたくさん使って物理系のゲームやろうとするとPTM_RATIO 32じゃキツイですね。上の動画は16でやっています。

コードの可読性が低いと死ぬ
パラメータの数も多く、その上できたあとの微調整もとても多いので、可読性が低いと死にます。Learning Cocos2Dで教えてもらったパターンや、HelloWorldのPhysicsSpriteなどを使って大分楽しているはずですが、もっと頭の中にパターンを作る必要がありそう。

次はどうする?
ということで結構色々面倒くさいことが分かりました。また、見ている分にはなかなか楽しい動きではあるのですが、ゲームとしてはイライラしそうです。

次は、キャラクタをもっと単純に設計してみようと思います。四角に円の車輪だけを付ける感じ。そこにアニメーションを追加してみて歩いている感じが出せるかどうかを試してみます。
試しました

PageTop

Box2DのJointまとめ(cocos2d)

Box2DのJOINTについて、理解が足りないことに気づきました。ちょっと複雑な動きのものを作ろうとしたのですが、なかなか難しい。「Distance JointとRevolute Jointがあればそれらを組み合わせてできるはず」という考えは甘っちょろかったか……。

マニュアルの8章の重要そうなとこのメモと思ったことを以下に書きます。jointとはなんぞやから、それぞれのjoint説明まで。英語が苦手な方も、図がよいのでそこだけは見ておくと良いかも。

Jointの基本
Jointは、body同士もしくはbodyとworldをつないで、bodyの動作に制御を加えるものです。それらの衝突可否はcollideConnectedで設定されます。

Jointにはモータとして働かせることができるものもあります。モータとインパルスが、Box2Dでbodyを動かすために推奨される2つの方法でしたので、これは重要です。

Jointの破壊については気を使いましょう。まず、DestroyJointしたあとはJointのポインタをnullにすることが推奨されています。破壊したjointによってゲームがクラッシュすることを防ぐためです。これはdeallocでworldをdeleteするときもやったりしますね。また、繋げているbodyが破壊されるとjointも自動的に破壊されますが、基本的にはjointを破壊してから、bodyを破壊する順番で処理しましょう。

Jointのメソッドを幾つか。まず、GetBodyAやBでbodyを取得したり、それらの接続点をGetAnchorAやBで呼び出せます。body2にかかる力やトルクもGetReactionForceやGetReactionTorqueで取得できるそうな。他にもモータとして使えるjointでは、SetMotorSpeed(float32 speed);などはかなり大事です。

Jointの種類として、b2JointDefのサブクラスが幾つかあります。Distance Joint、Revolute Joint、Prismatic Joint、Pulley Joint、Gear Jointなど。詳しくは以下で見ます。

Distance Joint
b2DistanceJointDefで定義されるDistance Joint。ふたつの物体の接続点を一定距離にするようにつなぐjointです。

といっても単に棒のようにつなぐというより、バネのようにつなぎます。バネの性質は周波数(jointDef.frequencyHz)と減衰(jointDef.dampingRatio)で制御できます。周波数はFPSの半分以下にするのが普通とのこと(60なら30)。ナイキスト周波数がその理由だとのことですが、まぁ考えて見ればFPSに近い数字(およびそれ以上)じゃ意味無いですね。減衰は0から1を指定してやり、1以上だと全く振動しないです。棒のようにしたければjointDef.dampingRatio = 1としてやればいいと。

Revolute Joint
b2RevoluteJointDefで定義されるRevolute Joint。ふたつの物体を一点でつないで、そこを中心に回転できるようにします。回転角はInitializeされたときを0として、反時計回り方向を正に、ラジアンで扱われます。回転角の最大値と最小値を制限できます。

Revolute Jointはモータとしても働けます。モータとして使う場合は最大トルクは定義しておきましょう(無限の力は恐ろしいもの)。また、速度は0にしながらも最大トルクを小さめの値で渡しておけば、回転への摩擦を持つようなRevolute Jointを描画することもできます。

モータの回転速度は毎Stepごとに決められるので、三角関数を用いた以下の様な記述もありだそうな。なるほど。
myJoint->SetMotorSpeed(cosf(0.5f * time));

Prismatic Joint
b2PrismaticJointDefで定義されるPrismatic Joint。2つの物体を一つの直線軸上で動かせるようにします。直動ジョイントともいうらしいです。Initializeされたときの位置関係が0となり、Initialize時の引数のベクトルにそって動作します。動作の上限下限もlowerTranslation、upperTransitionで決められます。

Prismatic Jointもモータとして使えます。ちょっと感覚的に変ですが、これは便利です。Distance JointとRevolute Jointを組み合わせて直線運動を作成するのは至難の業です。

Pulley Joint
b2PulleyJointDefで定義されるPulley Joint。片方の物体が上昇すると片方が下降するといったような、滑車の動きを実現するjointです。片方がnだけ上昇したとき、もう片方が2n下降するといったような、倍率をかけた制御もできるとのこと(その分、掛かる力は反比例します)。小学生くらいに勉強したなー、滑車。

Initializeのときには、それぞれのbodyと滑車の紐の接続点を渡します。ratioはbody2の方の滑車の長さにかかります。GetLengthAやBなどのメソッドもあります。

jointDef.Initialize(myBody1, myBody2, groundAnchor1, groundAnchor2, anchor1, anchor2, ratio);
//length1 + ratio * length2 == constant

片方の滑車が引き出されすぎて、もう片方の滑車の長さが0にならないように注意とのこと。それぞれの下に何か台でもつけてやるのが普通ですけど、上端に何か設置してやるのもかっちょいいかもしれません。

Gear Joint
b2GearJointDefで定義されるGear Joint。2つのjointを連動させる歯車のような仕組みが簡単に作れます。たとえば、Revolute Jointがxだけ回るとPrismatic Jointがyだけ進む、といったような仕組みです。組み合わせられるjointは、Revolute JointおよびPrismatic Jointのみです(Revolute JointとRevolute Jointの組み合わせなども可能)。

比率はPulley Joint同様ratioで設定。マニュアルではjointDef.ratio = 2.0f * b2_pi / myLength;としていますが、単純に数値をいれてしまう(jointDef.ratio = 2.0f;)ことも多いようです。

Gear Jointは、連動させているJointを破壊する前に破壊しなければなりません。順番を間違えるとクラッシュするそうです。Jointの基本で述べたように、きちんと順番通り破壊しましょう。

Flashですが、Flashで遊ぼう!さんの記事が動くサンプルもあってわかりやすいです。

その他
マニュアルで説明が適当なのでここでも簡単に。

Mouse Joint。マウス(タッチポイント)と物体をつなぐJoint。結構面白い動きになったり、デバッグに楽だったりするので、書籍やWebにある説明には詳しく書いてあったりします。aabbで走査したりする必要があるため、実装はちょっと面倒。最初は、マウスで物体を動かす時にまさかJOINT使うとは思わないよね。

Wheel Joint。b2WheelJoint.hとCar.hを見てね、とのこと。どうも、回転体と直動体を組み合わせてサスペンションみたいに働くようです。円運動と直動運動を変換できるわけですが、Gear Jointなどもあるし、使いどころがピンとこない。

Weld Joint。Cantilever.hを見てね、とのこと。weldは溶接という意味で、ゲームのどこかでバラバラになるものをくっつけておくのに使うようです。一つのbodyに複数fixtureをくっつけておいてバラバラにすると、bodyの再initializeが必要になるので、何かをバラバラにしたい場合はこれを使うようです。

Rope Joint。b2RopeJoint.hとRopeJoint.hを見てね、とのこと。2つの物体が一定以上の距離に離れないようにするそうです。鎖でつながれた犬のような感じですね。

Friction Joint。b2FrictionJoint.hとApplyForce.hを見てね、とのこと。例としてはこんな感じのようです。ちょっと面白い。

PageTop

Box2Dを知るためLearning Cocos2Dを読む(7) 総括&感想

物理エンジンの勉強のために買ったLearning Cocos2Dでしたが、予想外にcocos2Dを使ったゲームの作り方に学ぶことが多かったです。

まず、とても汎用性の高い作り方を示してくれています。例えば、UIレイヤとアクションレイヤの2つでゲームを構成する部分や、ゲームキャラクタの基礎クラスの作成部分などは、そのままのコードを僕のゲームでも使えそうですし、そうやって書くことでコードもキレイに書けそうです(長くなるので感想ではちょっと触れた程度でしたが)。一つの機能を説明するために汎用性のないプログラムを書く本が多い中、とてもありがたい本でした。

また、実装例を示す際に、やり方をただ示すのではなく、選択肢を提示してくれるので、頭の中がすっきりしました。「Aをやることで実装できます」と書いてあると、似たような状況は解決できますが、ちょっと状況が変わった時にA以外にもっといい方法がないかと不安になります。しかしLearning Cocos2Dでは「A,B,Cという方法があります、Dは◯◯なのでできません、この中で××なのでここではAを選びます」と書いてくれているところも多く、迷ったらBやCも試してみることができます。

もちろん物理エンジンゲームの部分も学ぶことが多かったです。詳細は過去の感想に譲りますが、複数のゲームの実装例が載っているので、いろいろなパターンが理解できてよかったです。

Learning Cocos2Dは洋書ですが、コード中心&親切すぎるくらいの記述&明るい文体なので、英語苦手でもスラスラ読めるのではないかと思います。カラーなので色分けされているコードも読みやすいし、キャプチャが多いから飽きも来ない、アプリを落として実際の動作を見ながら読める、と他にも読みやすい理由がいくつも挙げられます。値段も3000円台と安い。この本はオススメです。

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

商品詳細を見る


さっそく物理エンジンゲーム作ってみます。それが終わったら次のステップとしては3DとかOpen GLあたりでしょうか。3D学んだらARアプリ作ってみたいなー。


【Learning Cocos2Dに関する過去記事】
Learn Cocos2Dを手にとった理由
Part I Getting Started with Cocos2D
Part II More Enemies and More Fun
Part III From Level to Game
Part IV Physic Engines-1
Part IV Physic Engines-2

PageTop

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

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

全5部17章構成で、今回は4部の12-13章と5部の16章を読みます。12章では前回学んだ物理エンジンゲームを進化させ、13章ではChipmunkを使って新しいステージを一つ作ります。「Part V Particle Systems, Game Center, and Performance」は14-17章からなりますが、14章のパーティクルや15章のゲームセンターは日本語の書籍も充実しているし飛ばします。ただ16章のパフォーマンスについては知っておきたいので読んでおきます。

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

今回みていて学べたのは、すべての物体をバカ正直に正確な形で定義しなくていいことです。例えば、ドリルを持った敵ロボットを作りますが、四角の身体に円の車輪をつけ、ドリルは三角形のセンサを左右につけるだけです。確かに微妙な凸凹などを表現しても意味無いですね。なるほどなー。

Chapter 12 Advanced Game Physics: Even Better than the Real Thing
まずトロッコに主人公を乗せます。主人公は複数のパーツからなっていて、トロッコの動きにあわせてリアルに動きます。パーツはそれぞれrevolute jointやprismatic jointでつながっており、enableLimitで動作範囲を絞っています。

・パーツを組み合わせるときは、回転を考慮するため、GetWorldPointを使うべきとのこと。AにBを追加する場合のBの位置合わせは、A.GetPosition().x + offset.xなどを使うのではなく、A->GetWorldPoint(offset)を使うのですね。

・パーツ接続点の決定は画像編集ツールを使えばいいけど、Mekanimo、LevelSVGなどのツールを使うとかなり楽になるとのこと。動作テストもできコードも生成してくれるらしいですが、日曜プログラマには高い……。TexturePackerならまだ手が出るかな。

・パーツはトロッコ等と衝突してはいけないので、fixtureDefのfilteringで幾つか設定をします。ここは珍しく説明が適当で、マニュアル読んだ方がいいです。マニュアルは必要十分な例が挙がっていてわかりやすいです。

・パーツのSpriteはbatchNodeに突っ込みましょう。layerクラスでキャラクタクラスをallocした後に、layerクラスが管理するbatchNodeにaddするような形です。

ある程度ゲームサイズが大きくなっていくと、updateが起こる秒数にブレが出てきて、updateごとに1回Stepを呼ぶ単純なやり方だと挙動がおかしくなっていきます。そこで以下のように、各updateに複数Stepの処理もさせてやり、また時間が飛びすぎた時の対応を書いてやるといいそうです。
static double UPDATE_INTERVAL = 1.0f/60.0f;
static double MAX_CYCLES_PER_FRAME = 5;
static double timeAccumulator = dt;

if (timeAccumulator > MAX_CYCLES_PER_FRAME * UPDATE_INTERVAL)
timeAccumulator = UPDATE_INTERVAL;//飛びすぎた時の処理

while (timeAccumulator >= UPDATE_INTERVAL) {
timeAccumulator -= UPDATE_INTERVAL;
world->Step(UPDATE_INTERVAL, velocityIterations, positionIterations);
}

ボスの敵ロボットは上述のように簡単に作ります。体当たりで吹っ飛ばせるように、densityは低くする一方、ひっくり返らないようにSetAngularDampling(1000)として回転への耐性をあげています。ここは切り離して制御できるんですね。

最後に、ボス戦開始時の前に演出を入れる方法を説明して終わりです。ボス戦の開始位置にセンサを設置、updateメソッドで感知することで演出を開始します。演出の開始時に、主人公に対してsetMotorSpeed:0とSetLinearVelocity(b2Vec2(0,0))を実行して動作を止めます。前回記述した通り、SetLinearVelocityを使うと動きがおかしくなるのであまり使わないほうがいいのですが、動きを全て止めるなどのときは良いよとのことです。あとはCCActionで適当に。

Chapter 13 The Chipmunk Physics Engine (No Alvin Required)
Box2DからChipmunkに頭を切り替えてステージ5を実装します。

Box2DとChipmunkの比較から。worldがspaceだったりと言葉は違うのですが基本的な流れは一緒なんですね。違いとしては、Cで書かれているかC++で書かれているか、位置制御をポイントでやるかメーターでやるか、などが挙げられるようです。また、Chipmunkの方が簡潔な関数が多いため一つ一つのプログラム記述量は少ないけれど、Box2Dよりもjointなどの既製品が少ないので全体的な記述量では多くなることもあるようです。あと、Chipmunkだとオブジェクトに直接速度を渡してもキレイに動くらしいですが、一方で偶に物体同士が突き抜けてしまったりもするそうです。どうも一長一短ですね。

さっそくspaceを作ってみます。Chipmunkはspaceをgridにわけ、違うgridにあるオブジェクトは衝突していないとみなすそうです。
cpInitChipmunk(); //Chipmunkの開始
space = cpSpaceNew();
space->gravity = ccp(0, -750); //重力 ポイントで指定
//第二引数はgridのサイズ、第三引数はgridの数
cpSpaceResizeStaticHash(space, 400, 200);
cpSpaceResizeActiveHash(space, 200, 200);

このあとはオブジェクトを作ったり、Spriteを載せたりして基礎を確認した後、ステージ5を実装していきます。衝突時の返り値の形がBox2Dとは異なったりする部分や、どんなJOINTがあるかなどを50ページくらいかけて説明してくれます。概ね空気は分かったので、残りは読み飛ばし。というかBox2Dでとりあえず何か作って遊びたくて気がそぞろになってしまい読めません……。

Chapter 16 Performance Optimization
iPhoneゲームを作る際、パフォーマンスが意外とネックになったりします。ちょっと凝った動作を作ってみたら実機テストをしてみるとカクカクだったりしてがっかりします。そうなると全体的に見直しが必要になったりして本当に面倒です。のでここはとても重要なのです。

まずSprite系で知ってたTIPs。CCSpriteBatchNodeを使いましょう。テクスチャアトラスには空きスペースがないようにしましょう。場合によっては小さな画像をテクスチャアトラスに登録し、拡大して使いましょう。FlipXやFlipYで作れる画像は片方だけ登録しましょう。spriteはlayerのinit時にallocしましょう。そして再利用できるSpriteは再利用しましょう。要らなくなった画像はキャッシュから消しましょう。なおこの辺については、cocos2dで作る iPhone&iPadゲームプログラミングも弾幕を詳しく説明してくれていて良いです。

Sprite系であまり知らなかったTIPs。Bit depthは小さくしましょう。PVR形式は圧縮したままメモリに載せられるので使えたら使いましょう(リアル調の絵や写真に有効)。gzipされているPVR.CCZ形式も有効。

蛇足ですが、Sprite系TIPsで書いてなかったけど、以前実験したとき有効だったものも書いておきます。spriteのpositionを取得して画面外だったらvisible=NOとするだけで処理速度が変わります。特に事情があってCCSpriteBatchNodeが一部spriteに使えないときはかなり変わります。

処理の時間が計測したい時はCCProfilingTimerが便利。Nameには適当に独自名をつける。
//timerをretain
CCProfilingTimer* timer = [CCProfiler timerWIthName:@"timer" andInstance:self];
//計測開始
CCProfilingBeginTimingBlock(timer);
//計測終了 時間を標準出力
CCProfilingEndTimingBlock(timer);

あとはXcode付属のInstrumentsについて幾らか書いてくれています。これはUser's guideを読むのが良さげですが、とりあえず取っ掛かりに。


ということで、読み終わりました。お疲れ様でした。次回、総括しておしまいです。


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

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

Box2Dを知るためLearning Cocos2Dを読む(4)Part III From Level to Game

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

全5部17章構成で、今回は3部の7-9章を読みます。内容としては、Part IIまでで作ったゲームにメニュー画面・音楽を追加します。また、スクロール機能を使ってステージ2を実装します。スクロール部分は僕が以前作ったアプリでは実装しなかったので学ぶことが多そうです。

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

前回はcocos2dで作る iPhone&iPadゲームプログラミングに従ってSingletonもどきのコードを書いたのですが、Learning Cocos2Dではallocで処理していてよりSingletonっぽかったのでメモっておきます。synchronizedアノテーションを使ってマルチメソッドも考慮してます。
//GameManager.m
static GameManager* _sharedGameManager = nil;

+ (GameManager*)sharedGameManager{
@synchronized([GameManager class]){
if (!_sharedGameManager) [[self alloc] init];
return _sharedGameManager;
}
return nil;
}

+ (id)alloc{
@synchronized([GameManager class]){
NSAssert(_sharedGameManager == nil, @"Attempted to allocate a 2nd instance");
_sharedGameManager = [super alloc];
return _sharedGameManager;
}
return nil;
}

Chapter 7 Main Menu, Level Completed, and Credit Scenes
SingletonのGameManagerを使って各シーンの移動を実装します。メインメニューのためのCCMenuの説明もあります。

CCMenuItemのtagを使うとselectorでの処理がキレイに書けるのですね。selectorに渡す関数では、呼び出し元のCCMenuItemが引数に渡されますが、いままでどのitemが渡されたのかのチェックにちょっと面倒なコードを書いていたので、tagを使う方法が学べてよかったです。

- (void)displayMenu{
CCMenuItem* someItem1 = [CCMenuItem itemWithTarget:self selector:@selector(hoge:)];
[someItem setTag:1];
CCMenuItem* someItem2 = [CCMenuItem itemWithTarget:self selector:@selector(hoge:)];
[someItem setTag:2];
...
}

- (void)hoge:(CCMenuItem*)item{
if ([item tag] == 1) CCLOG(@"CCMenuItem someItem1 is selected.");
if ([item tag] == 2) CCLOG(@"CCMenuItem someItem2 is selected.");
}


Chapter 8 Pump Up the Volume!
音系の話を展開します。機能制限のあるAVAudioPlayerやAPIが煩雑なOpenALの代わりにCocosDenshionが作られ、SimpleAudioEngineが生まれたとか。

本章ではマルチスレッドを使ってバックグラウンドで音楽のロードをしています。マルチスレッドについては使ったことがなかったので、目新しいです。長くなるので省略しますが、NSOperationとNSInvocationOperationを使ってマルチスレッドを実装します。ここらへんは要勉強だな。

CDAudioManagerのinitAsynchronouslyを使うと、他アプリケーションのBGMを引き継いで使ったり、エフェクトだけ鳴らしたりとかもできるらしいです。
//すでに音楽がなっている状態でアプリを起動するとsound effectのみロードする
[CDAudioManager initAsynchronously:kAMM_FxPlusMusicIfNoOtherAudio];

//audio managerの起動待ち
while ([CDAudioManager sharedManagerState] != kAMStateInitialised) {
[NSThread sleepForTimeInterval:0.1];
}
CDAudioManager* audioManager = [CDAudioManager sharedManager];

...省略...//audioManagerの起動確認

[audioManager setResignBehavior:kAMRBStopPlay autoHandle:YES];
soundEngine = [SimpleAudioEngine sharedEngine];

SimpleAudioEngineのAPIでは足りない場合は、CocosDenshion, CDAudioManager, CDSoundEngineを使えば最悪OpenALレベルでの制御ができるそうな。例えば、効果音の早送りや左右どちらかから出すというのは、SimpleAudioEngineのplayEffect: pitch: pan: gain:で呼び出せますが、効果音をfadeoutさせる場合などはCocosDenshionのCDSoundSourceなどが使えるそうです。

Chapter 9 When the World Gets Bigger: Adding Scrolling
さて今回のメイン、スクロールです。段階を追って実装していきます。

まずスクロールをシンプルに実装しています。画面サイズの横幅n倍のスクロールレイヤを作り、キャラクタが画面の中央より右にいれば右にスクロール、左にいれば左にスクロールするようにします。これは、各フレームで呼び出されるupdateの際に、スクロールするlayerのpositionを変えてやるだけです(全キャラクタがスクロールレイヤ上に描かれているという実装の場合)。

ちなみにCCFollowを使う方法もあるそうです。以下のような感じにすれば、targetにitemがついていくので、targetに主人公spriteを渡してやれば良い。ただ、itemにlayerを突っ込む際はX軸方向だけでなくY軸方向も付いて行ってしまうことに注意(ジャンプすると画面も動いてしまう)。

id followAction = [CCFollow actionWithTarget:target];
[item runAction:followAction];


次にParallaxな動きを実装します。近くのものは速く、遠くのものは遅く動くアレです。cocos2dで作る iPhone&iPadゲームプログラミングでは各背景をbatchNodeに登録してそれぞれの動きを実装していましたが、本書ではCCParallaxNodeを使って簡易に実装しています。CCParallaxNodeの位置に、parallaxRatioが比率として掛けられ、positionOffsetが足されることで各レイヤの位置が決められます。
CCParallaxNode* parallaxNode = [CCParallaxNode node];
[parallaxNode addChild:layerSpr1 z:40 parallaxRatio:ccp(1.0f, 1.0f) positionOffset:ccp(0.0f, 0.0f)];
[parallaxNode addChild:layerSpr2 z:20 parallaxRatio:ccp(0.2f, 1.0f) positionOffset:ccp(0.0f, 0.0f)];
[self addChild:parallaxNode];

その次はSpriteをエンドレスに流し続ける方法が説明されていますが簡単なので省略。ここまでの完成品がアプリのステージ2にあたります。

最後にTile Mapsを使ってとても広いシーンを低メモリ消費で作成します。画面全体を覆う画像を2枚も貼ればiPhone4でもFPSが落ちるので、広い画面ではTile Mapsは必須だと思います。ツールはTiled Qtを使います。

Tiledでレイヤを複数作り、tmxファイルとpngファイルを作成、各レイヤをCCParallaxNodeに追加するだけです。CCNodeは親を一つしか持てないので、一時的にretainしてCCTMXTiledMapから外した後、CCParallaxNodeに追加するという手順を踏みます。
CCTMXTiledMap* tiledMap = [CCTMXTiledMap tiledMapWithTMXFile:@"tiledMap.tmx"];
CCTMXLayer* layer1 = [tiledMap layerNamed:@"layer1"];
CCTMXLayer* layer2 = [tiledMap layerNamed:@"layer2"];

CCParallaxNode* parallaxNode = [CCParallaxNode node];

//change the parent of layer1 from CCTMXTiledMap to CCParallaxNode
[layer1 retain];
[layer1 removeFromParentAndCleanup:NO];
[parallaxNode addChild:layer1 z:10 parallaxRatio:ccp(1,1) positionOffSet:ccp(0,0)];
[layer1 release];

......//same process to each layers


ゲームを作るステップの最初として、Tiled上でゲーム画面を描画してしまうとよいと書いてありました。確かにゲームの全体像が見えてから作った方が戻りもないし、キレイな構造になるんですよね。画像を集めるのが先になるのがどうもヤル気を削ぎますが、でも次はそうやって作ってみよう……。

なお、cocos2dで作る iPhone&iPadゲームプログラミングでもTile Mapsの説明がありますが、本書が横スクロールアクションでのTile Maps使用を説明にするのに対し、あちらはRPGのフィールドのようなTile Mapsの説明となります。等角タイルマップについても1章割いて扱っているので、RPG系はあっちの方がよいかもしれんです。


んー今回は思ったより音楽周りがタメになったなー。これで書籍全体の半分が終わりました。
次回はとうとう物理エンジンです!Part IVは長いから何回かに分けると思います。

あと、前に作ったアプリが今日付けで発売となりました!わーい。Learning Cocos2Dを読む前の僕のレベルでもこのくらいは作れるという目安になるかと思います。ぜひご覧ください。ではまた次回


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

Box2Dを知るためLearning Cocos2Dを読む(3)Part II More Enemies and More Fun

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

全5部17章構成で、今回は2部の5-6章を読みます。ちょっと短めかな。
Part Iでゲームの根幹部分ができたので、それを複雑化させていきます。

【過去】
Learn Cocos2Dを手にとった理由
Part I Getting Started with Cocos2D

結構大事なこととして、子クラスから親layerを参照する方法が以前読んだ本と違いました。cocos2dで作る iPhone&iPadゲームプログラミングでは、layerを擬似singletonにし、静的メソッドsharedLayerでlayerを呼び出していましたが、この本だと、各クラスにdelegateプロパティを作ってそこにassignでlayerを渡す方式で書いています。layerにはプロトコルを設定してやることで疎結合を実現しています。javaのinterfaceのような感じです。こっちの方が面倒くさいけど拡張性は高いですね。
/* cocos2dで作る iPhone&iPadゲームプログラミング */
//MyLayer.h
+ (id)sharedMyLayer;

//MyLayer.m
static MyLayer instance;

+ (id)sharedMyLayer {
NSAssert(instance != nil, @"MyLayer instance is not yet initiated!");
return instance;
}

- (id)init{
if (self = [super init]){
instance = self;
...}
}

//MyObject.m
MyLayer* layer = [MyLayer sharedMyLayer];
[layer someMethod];//なんでも呼べてしまうので結合が密
/* Learning Cocos2D */
//SomeMethodDelegate.h
@protocol SomeMethodDelegate
- (id)someMethod;
@end

//MyLayer.h
@interface MyLayer : CCLayer <SomeMethodDelegate> <OtherDelegate>{...}

//MyObject.h
@property (nonatomic, assign) id<SomeMethodDelegate> delegate;

//MyObject.m
[delegate someMethod];//結合が疎だが、protocolを作ってやる必要がある

Chapter 5 More Actions, Effects, and Cocos2D Scheduler
Chapter 4を応用してアイテムや敵を作っていきます。主人公を発見すると追跡しながら弾を発射する敵なども作ります。

Actionの扱いがよいパターンに落ちていて真似しようと思いました。各キャラクタオブジェクトは、changeStateとupdateStateWithDeltaTimesというインスタンスメソッドを持っています(親クラスGameCharacterのメソッドをOverrideします)。changeStateではenumで決めてあるstate(移動中・ジャンプ中など)を受け取り、対応するCCActionを呼び出します(CCAction内で使われるアニメーションについては前回のplist項参照。オブジェクトのinit時に読み込んで保持しています)。もう一方のupdateStateWithDeltaTimesは、親のscheduleUpdateから呼ばれるメソッドです。移動中にダメージを受けたなどstateを強制的に変えるものはchangeStateを呼び出し、そうでない場合はActionが一巡したかどうかを確認して、次のアニメーションを呼び出します。
- (void)changeState:(CharacterStates)state{
if (state == kStateDead) return;//死んでいる場合は無視
[self stopAllAction];
switch (state){......}//stateに応じたactionをrun
}

- (void)updateStateWithDeltaTimes:(ccTime)deltaTime andListOfGameObject:(CCArray*)listOfGameObject{
......//listOfGameObjectを参照し、現在のactionを中止しても他のactionを行うべきか確認
if (haveToChangeState) [self changeState:newState]; return;
......
if ([self numberOfRunningActions] == 0) [self changeState:nextState];
}


Chapter 6 Text, Fonts, and the Written Word
CCLabelTTFとCCLabelBMFontについて簡単に説明し、CCLabelBMFontを使って各キャラクタの頭上にデバッグ用のパラメータを描画します。ビットマップフォント作成ツールとしては、Glyph DesignerとHiero Font Builderを紹介しています。

CCLabelTTFは簡易に使えますが、setTextを行うと新たにテクスチャを作るので処理として重いです。もしフレームごとに更新するなどの処理をするのなら、CCLabelBMFontにしましょう(iOSシミュレータの右下のFPS表示もビットマップフォントですね)。


ということでPart II More Enemies and More Funが終了。いったん一つ目のゲームは開発終了なのかな。今回は短かったけど考えさせられることが多くて楽しかったです。ではまた次回


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

Box2Dを知るためLearning Cocos2Dを読む(2)Part I Getting Started with Cocos2D

cocos2dの物理エンジン周りの勉強&cocos2dの復習のため、Learning Cocos2Dを読んだメモを残していきます。手にとった理由や全体的な印象などは前回参照。

全5部17章構成で今回は1部の1-4章を読みます。

今回の範囲を読んでみて思ったのは、Learning Cocos2Dは「ただcocos2dが使えるようになればいい」という本の一段上を見ている本だなぁということです。たとえば、CCSpriteやbatchNodeの話をするときも、OpenGLだとこう書くので、cocos2dはこうやって書きます、という説明までしてくれています。

また、細かい気を使ってくれる本だという印象も受けました。たとえば、コードサンプルの直後にはWarningとして初心者がミスりそうなポカを指摘してくれています(☓☓を忘れると○○っていうエラーが出るよって感じで)。そういうミスはググっても出てこないからいいですね。

一方でメモリ管理に関しての説明がないのが気になります。cocos2dで作る iPhone&iPadゲームプログラミングだと最初から結構何度も繰り返していたのですが。そこは読む前に把握しておいてね、ってことなのかな。


Chapter 1 Hello, Cocos2D
cocos2dのインストールからHelloWorldをいじってCCActionなどを使ってみたりします。セットアップ部分についてはバージョンが古いのであまりあてにしない方がよいと思います。

AppDelegate.mの中身についてきちんと書いてあるのが良かったです。適当に流していたので勉強になりました。ただ、いま読むとなるほどなぁという感じですが、いきなりこれ読んでもハードル高く感じるかも……。んー、でも最初から分かってれば変なところでハマったりもしないのかな。


Chapter 2 Hello, Space Viking
さっそくSpace VikingをiPad上で作っていきます。プロジェクトの作成から、背景・キャラクタの描画、SneakyInputを使った仮想ジョイスティック作成まで。最後にテクスチャアトラスについても結構詳しく書いてありますが、使うのはChapter3から。

上にも書きましたが「OpenGLがこう書くから、cocos2dではこう書くのです」という説明が多くて、なるほどと思うことが多いです。単にcocos2dでゲームが作れればよいという本より一段高いイメージです。

Tipsの3本指横スワイプで.mと.hが切り替えられるの知らなかった……。いつもOpt+Cmd+Upでやっていました。ところどころにこういうのが出てくるのも飽きさせません。


Chapter 3 Introduction to Cocos2D Animation and Actions
Chapter 2の基礎を元にゲームを設計し、必要なクラスについて考え、抽象クラスにあたるものを作成します。アプリを先に見ておいた方がよいです。またアニメーションについての説明があります。前回作ったゲームではアニメーションを使わなかったので、アニメーション周りは学ぶことが多かったです。

アニメーションの画像描画管理はplistで行うものなのですね。各オブジェクトごとにplistファイルを作り、その中に各動作のDictionaryを作る。各動作のDictionaryには、表示する画像番号の配列、delayタイム、画像のprefixを格納。- (CCAnimation*)loadPlistForAnimationWithAnimationName: andClassName:のような共通メソッドを作っておいて読み出します。この方法は便利なので覚えておこうと思います。

plist_sample.png


あと細かいですけど、CCAnimationCacheを使うときは勝手にキャッシュが破棄されることがあるから、使う側でretainしないといけないんですね。へぇ。

クラスの配置に関して、Groupを以下のように用意するのはいいなぁと思いました。Constants, Scenes, Layers, GameObjects, EnemyObjects, PowerUps, Singletons。Constantsは、定数を扱うヘッダファイルやプロトコルファイルを置く感じ。


Chapter 4 Collision Detection and the First Enemy
Chapter 3で作った抽象クラスを元に、シンプルな敵と主人公を作ります。主人公が左右に移動し、敵を壊すところまで作れます。

Chapter 3の設計がキレイにハマっていて感心します。やっぱり最初にきちんと青写真を描かないといけないなぁと思いつつも、自分が作っていくと全然違うものになるんだよなぁ……。

#pragma markの説明があり。そういえば「これなんだっけ」と思ったまま放置していました。a formatting guide for Xcode and is not seen by complierとのことです。ソースの栞みたいに使えるんですね。こちらなどが詳しいです。今度使ってみよう。しかし、TODOとかも一覧で見られたのか。



以上でPart I Getting Started with Cocos2Dは終了。ちょうどここまで作成した動画が上がっていました。画面上でできることはしょぼいけど、裏では弾を食らった処理とかも既に記述済みなので、コード自体は結構見るものあります。

最初のパートだから読み飛ばせるかと思ったけど、意外と知らないことが多くて勉強になりました。ちょっとクドいくらいに説明があるけど、そのぶん英語でも読みやすいし、買って正解だったと思ってます。ではまた次回


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

Box2Dを知るためLearning Cocos2Dを読む(1)物理エンジンBox2Dの学習方法の模索

2つ目のゲームは物理演算を作ったゲームにしてみようと思いました。cocos2dはBox2dとChipmunkの2つの物理エンジンをサポートしているので、それを使ってみようと思ったのです。

ネットの記事を参考に幾つかサンプルを動かしてみると、物理エンジンを使った動きというのは中々面白いものです。例えば、以下の動画のようなものを作ったりできます。コードと解説はこちら


しかし、参考となる記事が思ったより見つけられませんでした。基本のところはこのへんの記事で理解できますが、もうちょっとゲーム全体を考えながら物理エンジンについても学んでゲームの形にできるものはないかと。日本語書籍もcocos2dで作る iPhone&iPadゲームプログラミングが一章を割いて基本解説止まりといったところです。

で、結局以下の本を買うことにしました。Open GL ESのバージョンが1.1のままだったりと、ちょっと古いですが、物理エンジンを扱うcocos2dの本では現状これが一番良さそうな感じです。目次によれば、600ページ中200ページくらいを割いて物理エンジンについて扱っています。

サンプルを見た感じ、cocos2dの再勉強という意味でも良さそうです。NoteやWarningなども多く、かなり丁寧に解説してくれていそうだと感じます。英語も平易で、技術系のブログ記事が読めれば問題無いレベルです。しかし如何せん情報が古いのと詳細まで入りすぎている感もあるので、cocos2dの一番最初の本としてはあまりオススメできなそうです。

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

商品詳細を見る

本で出てくるサンプルアプリがAppStoreで公開されています。無料なので落としてやってみましたが、クソゲーすぎてびっくりします。でも、だいたい何ができるかはイメージしやすいので本を買う前に落としてみるといいかもしれません。


余談ですが、電子書籍安いですね。クーポンとかをうまく併用すれば2000円前後で買えそうでした。僕は結局書籍にしたので3500円くらいでした。amazonだとこの値段で、日本の大型書店だと6000円弱だったのも印象的でした。

次回から読んでメモを書いていこうと思います。全5部、17章の作りなので少しずつ……。
【続き】
Learning Cocos2Dを読む(2)Part I Getting Started with Cocos2D
Learning Cocos2Dを読む(3)Part II More Enemies and More Fun
Learning Cocos2Dを読む(4)Part III From Level to Game
Learning Cocos2Dを読む(5)Part IV Physic Engines - 1
Learning Cocos2Dを読む(6)Part IV Physic Engines - 2
Learning Cocos2Dを読む(7)総括

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