cocos2d-iphone 2.0でのARC対応(2013-02-17追記)

※はじめに書いておくと、この記事は以下の記事に書いてあることを紹介しているだけです。最初から以下の記事を読んでもらえばこの記事は読む必要ないです。大して英語力は必要ないです。
http://www.learn-cocos2d.com/2012/04/enable-arc-cocos2d-project-video-tutorial/

結論から書きます。
cocos2dで自分が書くソースでARC使いたいなら、以下の2つの方法が簡単です。
①上記チュートリアルを真似して、cocos2dライブラリと自分のソースを分離し、自分のソースだけARC化
②learn-cocos2d.comで公開されているhttps://github.com/LearnCocos2D/cocos2d-iphone-arc-templates をダウンロードしてプロジェクトの雛形として使う。


cocos2d-iphone 2.0は、ARCと共存可能(compatible)ですが、cocos2dのライブラリ自体はARCに対応していません。

すなわち、自分が書くソースはARC使えるけど、cocos2dのライブラリはARCに基づいて書かれてないってことです。
最新のXCodeにはソースをARC対応させる機能があります。
[Edit]→[Refactor]→[Convert to Objective-C ARC...] です。

cocos2dライブラリはARC化してないので、この機能をプロジェクトに使うと大量の警告が出ます。
自力で対応させるのは現実的ではありません。
というか、自力で対応させたら是非cocos2dのgithubにPullRequest送ってあげてください。


cocos2d 2.0でXcodeにインストールしたテンプレートは、ライブラリ部分以外(ライブラリを使う側、アプリ部分、main.mとか)もARCに対応していません。
なので、main.mでautorelease poolが指定されており、CCArrayやNSMutableArrayといった配列を定義して要素を格納しても、次のフレームには格納した要素が解放されているということが生じます。

そこは、autoreleaseを意識したソース書けば解決ですが、せっかくARCという便利な機能があるのだから使っちゃいましょう!

という訳で、既にcocos2dのテンプレートで作成済みのプロジェクトをARC化したいなら①をやってください。
慣れればすぐできます。

最初からARC対応したプロジェクトを作りたいなら②を使うのが簡単でしょう。
②は、①が既に行われた雛形、というだけのものだと思います。


ちなみに、最新のcocos2d本(和訳はまだ出版されてません)のソースコードのzipファイルには最初から②が入ってます。
http://www.learn-cocos2d.com/store/book-learn-cocos2d/
学習の出発点としてはこの本のソースはとてもいいと思います。
記事内の「Cocos2D Source Code (ARC) (Cocos2D v2.0; includes 12 Cocos2D ARC templates)」からダウンロードできます。

(2013-02-17追記)
以上の方法をとった場合、シミュレータだと実行出来ますが、iOS Deviceだとリンクエラーが起こります。
ld: library not found for -lcocos2d-library
というメッセージです。
以下のページのコメントのやりとりに解決策がありました。
http://www.learn-cocos2d.com/2012/04/enabling-arc-cocos2d-project-howto-stepbystep-tutorialguide/
自分のアプリとcocos2dライブラリの両方のBuild Settingで、Build Active Architecture OnlyをNoにしてください。
cocos2dライブラリを作ったときはデフォルトでYesになっています。

cocos2d-iphone 2.0でのHD画像を用意しない簡単なRetina対応

(ここではiPhone4SまでのRetina対応に関する知見を書きます。
アスペクト比の変わるiPhone5でどうすべきかは未調査です。)

cocos2d-iphone 2.0でのRetina対応ですが、
Retina向けの高精細画像では以下のようにファイル名を変更するだけです。

Retina用:xxx.png
Retina用:xxx-hd.png

iPadの場合はxxx-ipad.png、iPadRetina用にはxxx-ipadhd.pngです。
ソースコード内ではxxx.pngというファイル名で扱っていても、デバイスによってcocos2d側で勝手にファイル名を変換して読み込んでくれます。

と、ここまでのことはAppDelegate.mのapplicationメソッド内のコメントに書いてあり、このサフィックスについてもそこのソースを編集すれば変えられます。

さて、わざわざ高精細画像を用意しない場合、つまりResourceフォルダ内にxxx-hd.pngなどを置かないと、Retinaディスプレイであってもcocos2dはxxx.pngを使います。
これはフォールバックと呼ばれているようです。

しかし、そのまま使うと、画面全体のサイズに対して、画像が半分のサイズで表示されてしまいます。
縦横のピクセル数をそのまま反映すると考えれば自然なことです。

画像の精細度が半分になってもいいから、Retinaでも同じように表示したい、という場合はapplicationメソッド内で以下をコメントアウトすればOKです。

if( ! [director_ enableRetinaDisplay:YES] )
CCLOG(@"Retina Display Not supported");

cocos2d 2.0のテンプレートでは上記の処理が含まれています。
cocos2dの古いバージョンでは、上記はコメントアウトされていたようですね。少なくとも0.99.5では。
(どのバージョンからコメントが外されたかは未調査です。)


applicationメソッドの中では各種初期設定を行なっているので、理解するとためになると思います。

cocos2d-iphone 2.0で縦画面と横画面を切り替える方法

先の記事
http://d.hatena.ne.jp/DiegoTristan/20130102/1357135643
で、縦画面表示になってしまう理由が不明だと書きました。
その解答が見つかりました。
バージョンはcocos2d-iphone 2.0.0です。

結論から言うと、Info.plistのSupported Interface OrientationでPortraitにしてれば縦画面で表示されるし、Landscapeにしてれば横画面に表示されます。
(BOOL)shouldAutorotateToInterfaceOrientationメソッドは何も影響しません。
このメソッドは、起動時にも端末の回転時にも呼ばれないことをデバッガで確認しました。
調べていませんが、他の用途のためにあるのでしょう。


ここまでだと、何でわざわざこのような簡単なことではまり、わざわざ記事を書いたのかと疑問に思われるでしょうが、
答えは簡単で、
参考にした下記の書籍のサンプルソースで回転が有効になっていなかったからです。

Learn cocos2d 2: Game Development for iOS

Learn cocos2d 2: Game Development for iOS

おそらくcocos2d 2.0のベータバージョンか何かを元にしているのでしょうか、
AppDelegate.mのdidFinishLaunchingWithOptionメソッド内で
[window_ addSubView:navController_.view]としています。
これだと、必ず縦画面になってしまい、info.plistを編集しても変わりません。
(原因は未調査です。)

現在は、cocos2d 2.0のテンプレートでプロジェクトを作ると、
[window_ setRootViewController:navController_];
となっていますが、これでしたらOKです。

まあ、おそらくは単に、古いバージョンのソースを参考にしていてはまってしまったというだけですね。

cocos2dのtmxファイルの1レイヤー1タイルセット制限

AIRで作っていたブロック崩しシューティングゲームを放っておいて、
最近はcocos2d-iphoneやTiledMapEditorを触っていました。

今回、TiledMapEditorを使っていてはまったことの一つがタイトルの件でした。
1つのレイヤーに複数のタイルセット画像を用いていたのですが、そうすると実行時に
TMX: Only 1 tilset per layer is supported'
というエラーメッセージが吐かれます。
で、タイルの読み込みあるいは表示のどちらが失敗してるか調べてませんがともかく表示に失敗します。
これはおそらくCocos2dの仕様なのですが、ドキュメントは確認していません。
cocos2d-iphoneのバージョンは2.0.0です。


これの対処方法はまさにそのまんまというか、1レイヤーにつかうタイルセットを1枚にするしかありません。
使う画像は一枚の画像ファイルにまとめておけ、ということですね。
逆に、一枚のタイルセットを複数のレイヤーで使用する分には問題ありません。


僕は、同じタイル画像を複数持って、それらに別々のタイルプロパティの値を持たせる、ということがやりたかったので、1レイヤーに同じタイルセット画像を名前を変えて複数使おうとして上記のエラーにはまりました。
なぜ一枚のタイルセット画像に同じタイル画像を複数含めなかったのかというと、タイルセット画像の作成に用いているTexturePackerがそれを許さなかったからです。
TexturePackerは、たとえファイル名が違っていても、データ上全く同じ画像だと、複数並べてくれません。
バージョンは現在最新の3.0.4です。
ここら辺は、どなたか解決策をご存知でしたら教えて下さい。


後、現在はまっているのが、作成したcocos2dアプリがなぜか横画面表示できないという問題です。
info.plistのSupported Interface OrientationをPortraitにしても、
AppDelegate.mのshouldAutorotateToInterfaceOrientationを

  • (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

{
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}

にしても全く聞きません。
というかデバッグで追いましたが、shouldAutorotateToInterfaceOrientationがそもそも全く呼ばれないので上記の意味がありません。
cocos2d-iphone 2.0.0のテンプレートそのまんまのHelloWorldアプリは、横画面表示でHelloWorldLayerが出てきて、そこから大きく変えていないのに、なぜ必ず縦画面で表示されるのか不思議でなりません。

ちなみに、以下書籍のサンプル(和書じゃないですよ!洋書の最新版のサンプルです)でも同じ問題が発生しますんで、自分のソースのせいではないと思います。
何かご存知の方がいたら教えて下さい。

Learn cocos2d 2: Game Development for iOS

Learn cocos2d 2: Game Development for iOS

Eclipseでgithubリポジトリをチェックアウトするメモ

自プロジェクトをアップロードする記事はあっても
他者のプロジェクトをチェックアウトする方法が書いてある記事がなかなか見つからなかったのですが、以下がよかったです。

http://rough-and-ready-co-jp.blogspot.jp/2012/02/giteclipsegithub.html

プロジェクトをインポート、Import as General Project が肝ですね。

自分の環境だと、例えばLWFのインポートには相当な時間がかかりました。
2時間くらいかかった記憶が。。
単に特定リビジョンをダウンロードするのと違い、これまでの全リビジョンの情報をとってくるからだと思います。

FlashBuilderもEclipseベースなので同様の方法です。


最近頻繁にxcode触ってますが、xcodeはどうするんでしょうね。

自分のキャリアに用いる開発環境を定める

ITエンジニア(ゲーム開発エンジニアを含む意味で)は職務経歴書
自分の得意な分野、開発環境、言語を書くわけですが、
自分もweb系を始めて1年半。DBにサーバに、一部クライアントにと他の同僚と違い広く浅く経験してきましたが、やはり方向性を絞らねばなりせん。

自分が組み込み系エンジニアだったときはCかC++一択だったし、サーバという概念はありませんでした。

ゲームのクライアントエンジニアならばやはりC++一択ですね(一部C#もあるようですが)。下手すると組み込みより低レイヤーです。

組み込みとゲームは似てるところが多いと思ってます。
一つはwebのコンテンツ会社と違って扱うのがより低レイヤーなことです。
webは何かにつけオープンでapachetomcatみたいなミドルウェアにオープンなDBが普及してますが、組み込みやゲームは何かにつけプロプライエタリで、ミドルにあたる部分は他社から買ってくるか自社で作っているのが当たり前です。
その分、使う環境というのが特定の環境に捕らわれたりします。

webはというと、あまりに環境が乱立しています。
クライアントはHTML5Flash、Obj-C、etc、etc、、、サーバもですけどまだクライアントほどではない。

自分はクライアントスキル中心に生きたいし、サーバは1年以上やってみて、「必要だからしょうがなくやる」、以上のやる気と興味が出ませんでした。
これはもう向き不向きであり性格だと思います。30年生きていて自分の好き嫌いは大体把握しているので、1年半やらなくてもとっくにわかっていたことではありました。


本当にいろいろやってきた自分ですが、とりあえずしばらくは以下にフォーカスしたいと思います。

・クライアント:JS(HTMLとHTML5中心、CocosとUnityのJSも動向監視はしていく)
・サーバも他の人がやってくれなかったらやる:JS
・グラフィック用オーサリング:Blendar、FlashCS(フリーでいいものが出たら代替)、GIMPInkscapeも必要があれば
・クライアント用ミドル部分に手を出していく:C++
・簡単なツールやアプリをささっと作る:AdobeAIR

正直、クライアントもサーバも、C++とかの低水準な言語でがりがり書きたいですが、時代の流れと、他の同僚に使ってもらうことを考えるとJSを選びました。必要な部分にはC++を使っていけばいい。
Obj-Cには非常に興味がありましたが、仕事でやる機会が無さそうなのでこだわっていてもしょうがない。
仕事でやらず趣味に限定されてしまうと極度に成長が遅れます。

AIRは今後そこまで発展するとも業界で支配的地位を得るとも思いませんが、一回書けばwebでもスマホでもデスクトップでもOSを問わずどこでも互換性問題なく安定して動き、環境が乱立しておらず、かつ言語として学びやすくコンパクトでコンパイル言語なのは最高です。
プロプライエタリなのはマイナスですが、他にここまで扱いやすい環境を知りません。
ゲームのモックも作りやすい。
JSは当分そこまでには至らないと思います。


逆に言うと、これ以外の技術やツールになるべく時間を取られずにすむように仕事とキャリアを整理していかねばなりません。
今は特定の言語と環境にかなり人生の時間を割いていますが、その言語には本質的に興味が無いので少しずつ減らしていきたい。
必要は必要ですが、自分は状況を改善するために自分のやりたいことを犠牲にして何にでも手を出してしまい破綻しがちなので、必要性以上に時間を割かないように意識して注意していきたいと思います。

AdobeAIRでのマルチスクリーンサイズ対応

これまでiOS用のアプリしか作ってきませんでしたが、ちょっとしたきっかけでAndroid用の簡単なアプリを作ることになりました。

手馴れているのでAIRで作ることにしましたが
Androidといえば、やはり様々なスクリーンサイズ対応が問題になってきます。
ちなみにマルチスクリーンに対応して画面パーツのレイアウトが変わるようなものをリキッドレイアウトと呼ぶらしいです。
今回は簡単なリキッドレイアウトがやりたいわけですね。

Flexは画面サイズが違っていてもiPhoneのようにアスペクト比が違うだけなら(今はiPhone5もありますが)基本的に勝手にフィットさせてくれます。
フットサルボードはFlexで作りました。
iPhoneであれば解像度が違っていても無問題です。
ですが、アスペクト比が違うiPadだと想定どおりにうまくリキッドレイアウトしてくれなくて困った記憶があります。

ですので、今回は最初からFlexを使わないことにしました。
FlexFlexのSWCを含めると12MB程度ネイティブよりサイズ上乗せだというのもあります(最近は3G回線でも50MBまでのアプリならダウンロードできるようになりあまり気にならなくなってきましたが)。
AIRだけだと8MB程度です。


さて、リキッドレイアウトをやるためには、デバイスの画面サイズを取得できなければなりません。
それができれば後は適当な位置を計算してパーツを配置するだけです。
そこで結構はまりました。
この記事はそのはまりで得た知見のメモです。

結論から言ってしまうと、以下の情報源が非常に参考になります。
http://www.adobe.com/devnet/air/articles/multiple-screen-sizes.html

最終的には、resizeイベントのイベントハンドラーの中でstage.full
ScreenWidth,fullScreenHeightを取得しました。
起動して数フレームはstageのwidthとheight(fullScreenWidthとfullScreenHeightにも)には正しい値が入ってないというのは本当で、知らなければはまるポイントだと思います。
起動して数フレームで必ずresizeイベントが発行され、そのときには正しい値が入るそのとき値を取得します。
ていうか、これバグに近いですね。回避策もバッドノウハウです。

他にはCapabilities.screenResolutionX,screenResolutionYでも値がとれます。
こちらはresizeイベントを待つ必要はないようです。
ただしこちら、PC上のシミュレータで実行すると、PCの画面のサイズがとれますwww なんでやねん
まあデバイスではちゃんと動くのでしょうが、開発がやりにくいので使うのをやめました。

今回のソースは後ほどgithubで公開します。


FlexもFlashProも使わないと、ちょっとしたコンポーネントさえ無いので、使いどころが限られてきますが、アプリサイズが小さくなるという恩恵を受けます。
フットサルボードではFlexに頼りっぱなしだったのでいい勉強になりました。

個人的にはFlexを使う必要性に迫られなければFlexは使う必要ないと思います。


後、今回、スプラッシュ画面を適用したいのですが、iPhoneならFlexだとスプラッシュ用のattributeがあるし、
Flex使わなくてもDefault.pngを使えばOK。
しかし、Androidはどうもデフォルトでスプラッシュというものが存在しないらしいのです。
情報を探すと以下のように強引にやってる人もいますが、もっと簡単にやりたいですね。
http://swfhead.com/blog/?p=817
http://forums.adobe.com/thread/764981
http://forums.adobe.com/message/3691229
いい情報があったら皆さん教えてください。