SuperAnimationConverterの使い方メモ

最近cocos2d-xでSuperAnimationConverterを使っています。

SuperAnimationConverterとは、簡単に言うと、FlashProffesionalで作ったSWFをcocos2dシリーズで再生させるためのツールとライブラリです。
SWFをスプライトシート化するツールは多くありますが、キャラクタの体をパーツに分けてモーションさせるタイプのSWFを、パーツごとの画像に分割して再生できるのは、これとspineくらいでしょう。
spineは独自オーサリングツールですが、SuperAnimationConverterはFlashProffesionalでSWFを作って、それを変換するやり方なので、Flasherが慣れたツールを使えるという点でメリットがあるかと思います。

この記事ではツール側の細かな紹介は行いません。
githubからzipをダウンロードすると、中に説明書きのpdfが入っていますのでそれを読めばわかります。
https://github.com/raymondlu/super-animation-samples


基本的な使い方はsyuhariさんが紹介されています。
http://blog.syuhari.jp/archives/2428

ツール側はpdfを読めばわかるのですが、ソースコード側は全くリファレンスがありません。
ソースコードとサンプルを読めというスタンスですね。
なので、ソースを読んで調べたことをメモとしてまとめることにしました。


・スプライトシートの使い方
吐き出された画像をTexturePackerでスプライトシートにまとめて使うことができます。
ダウンロードしたzip内にあるpdfに使い方と注意点が書かれてますね。
スプライトシートを使わない場合は、Resourcesフォルダには、samファイルとバラバラ画像を置くことになりますが、
スプライトシートを使う場合はsamファイルと同名のplistファイルとスプライトシート画像ファイルを置けばよいです。
スプライトシートがある場合は、CCSpriteFrameCacheに登録され、そちらが使われるようになっています。

・アニメーションをループさせる方法
OnAnimSectionEndを使ってループ、、、させる必要はありません。
PlaySectionメソッドの第二引数にtrueを指定してください。デフォルトではfalse扱いになってます。

・終了時以外にもコールバック呼びたい!
タイムイベントを登録できます。
void registerTimeEvent(const std::string &theLabel, float theTimeFactor, int theEventId);
void removeTimeEvent(const std::string &theLabel, int theEventId);

使い方は、引数を見ればだいたいわかるかと思いますが、ダウンロードしたzipについてくるサンプルにサンプルコードが含まれています。
ラベルがタイムラインのラベル、イベントIDはタイムイベントごとに独自につけるID、タイムファクターは、タイムライン開始地点が0.0f、終了地点が1.0fです。

登録すると、指定した時間が経つとInit()でリスナーとして登録したクラスの以下のコールバックが呼び出されるので、実装しておきましょう。
void OnTimeEvent(int theId, std::string theLabelName, int theEventId);

現状、OnAnimSectionEndとOnTimeEvent以外にコールバックはありません。

・他のActionとの競合について
SuperAnimationConverterはcocos2d-xのActionは使っていません。
CCNodeのupdateとdrawをオーバーライドして処理を行なっています。
ですので、Actionとの競合は発生しません。つまり、stopAllActionsメソッドなどには反応しません。
中断したい場合は、Pause、Resumeなどのメソッドがあるのでそちらを使ってください。

SuperAnimationConverterのcppファイルのcocos2d-x2.1.4への対応

SuperAnimationConverterという、FlashProffesionalで作ったswfアニメをcocos2dシリーズで再生制御するためのライブラリがあります。

ccoos2d-x2.1β3までは対応しているようですが、2.1.4に組み込んだらビルドエラーが出たので、解消方法をメモします。

エラーが出たのはSuperAnimNodeV2.cppファイル内の1箇所です。

SuperAnimNodeV2.cpp:750:123: No member named 'fullPathFromRelativePath' in 'cocos2d::CCFileUtils'; did you mean 'fullPathFromRelativeFile'?
というエラーメッセージが出ます。

fullPathFromRelativePathというメソッドは2.1.4ではもうなくなっています。
fullPathForFilenameメソッドに置き換えてください。

cocos2d-xを学習する方法:和書の書評

cocos2d-x関連の和書で、発刊が周知されていた3冊が出揃いました。
この記事では、それらを紹介し、個人のレベルに合わせてどれを読んでいけばいいかお勧めを書きたいと思います。

より初心者向けのものから書いていきます。

cocos2d-x入門

cocos2d-x入門

cocos2d-x.jp代表やってる清水さんの書いた初心者向けの本。
C++文法についても簡単に触れています。
cocos2d-xとは、というところから書いています。
全くcocos2dシリーズを知らないならこれで始めるといいでしょう。
プログラミング初心者もこれが一番。

cocos2d-xによるiPhone/Androidアプリプログラミングガイド (for Smartphone Developers)

cocos2d-xによるiPhone/Androidアプリプログラミングガイド (for Smartphone Developers)

やはり清水さんの本。
上の本に比べて、基本的概念の解説が少し簡略化されて密度が濃くなってますが、そこまで難しさは変わりません。
他の2dスプライトのフレームワークFlashとか)を触ったことがある人なら、これで始めて全く問題ないと思います。
GlyphDesigner、CocosBuilder、PhysicsEditorを使ったゲームサンプルが1つずつが載っています。


上の2つの本は写経用であり、サンプルソースを全て写経すればcocos2dをリファレンス見ながら書けるレベルまで到れるでしょう。
写経しながら、周辺ツールの使い方も覚えられると思います。


Cocos2d-x開発のレシピ

Cocos2d-x開発のレシピ

こちらは、逆引きリファレンスといったものです。
業務や趣味で既にcocos2d-xを使っている人、cocos2d-iphoneを使っていて
、cocos2d-xとの違いを知りたいだけの人はこの一冊で十分です。
逆引きリファレンスといえどノウハウのかたまりなので、全て読み通しておくと、何か困ったときに、「あの辺りに書いてあったかな」と辞書をひくように読み直せると思います。
cocos2d-xはまだ日本語の情報が少なく、リファレンスのDoxygenも記述が少ないので、英語の公式サイトやTestCppやcocs2d-xのソースを読めば十分!という人もこれは買っておくと良いと思います。

この本は最高ですが、欲を言えば、TiledやCocosBuilderなど周辺ツールの記載が簡略です。
値段を高くしていいから、もっと量が充実していると嬉しかった。

この本に書いてないTipsについて、今後このブログでも共有して行きたいと思います。




cocos2dで作る iPhone&iPadゲームプログラミング

cocos2dで作る iPhone&iPadゲームプログラミング

この本は、Cocos2d-iphoneの本であり、しかも、バージョン0.9に基づいた本です。(現在のバージョンは2.1)
翻訳書であり、原書の方はバージョン2に対応したものが出ています。
Cocos2d-iphoneは新規機能開発が行われないことはほぼ確定しているようなものであり(iOS7の2Dフレームワークのせい ゲフンゲフン)、Cocos2d-iphone使用者が減ることを考えると、和書が改訂されることはないでしょう。

それでも僕は入門にはこの本を一番におすすめできます。
理由を順不同に挙げます。
・量と質の差。周辺ツールおよび機能をくまなく取り上げている。上の本はタイルやパララックスのことを詳しく取り上げていない。
・ゲーム開発の基本的考え方や、良いゲームプログラミング、とは、といったところまで踏み込む。上で紹介した本が、あくまでcocos2dを使いこなせるようになるための本であるとするなら、この本は、cocos2dを道具としてゲーム開発そのものを学べる本だと思う。
・cocos2d-xのAPIはcocos2d-iphoneAPIとほぼ同じ。cocos2d-iphoneができる人はcocos2d-xもできる。
・原書のバージョン2向けのサンプルソースを読みながら、この本の0.9向けのソース解説を読むことは十分に可能(僕がそうやって学んだので)。このブログ内でも、関連する記事を書いていますので読んでみてください。


今更cocos2d-xのためにcocos2d-iphoneの本を使って学びたい、という人はいないでしょうが、この本が読者をひきあげてくれるレベルが他よりも高いので、やはりこの本が初心者向けにはベストと言わざるを得ません。

以上です。

cocos2dの派生クラスで気をつけること2つ

また釣りっぽいタイトルになってしまった。。。
短いキーワードでタイトルを作ると自ずとそうなるのだろうか。


さて、cocos2d-xの書籍として「cocos2d-x 開発のレシピ」というのが発売されてまして、先日ひと通り読みました。
その上で、CCObjectを継承したクラスを作るときに、気をつけなければいけないと思った点が2点ありましたので紹介します。
つまり自分で調査した訳ではなく単なる抜粋です。すみません。

Cocos2d-x開発のレシピ

Cocos2d-x開発のレシピ


コンストラクタに例外が発生するような処理を書かない

軽量化のために、コンストラクタでは例外は扱わないようにしているらしいです。
ソースについては未調査です。
調査したら追記します。

基本的に、初期処理はinitXxx()メソッドを作ってそちらに書きましょう。
CCObject派生クラスにはinitXxx()メソッドは必ず用意するのがcocos2d-xの慣習(というか、cocos2d-iphoneから来たiOSの慣習だと思う)だと思うので用意するべきです。
あ、initXxx()は戻り値をboolにしてください。


create系メソッドを作ったらretain&autorelease

クラスを作ろときは (new Hogehoge())->init(); していらなくなったらretain、でもいいのですが、便利のためにコンビニエンスコンストラクタを作るのもいいですね。
cocos2d-xの命名規則ではcreate()やcreateWithXxx(Xxx xxx)が慣例のようです。

中では以下のようにします。
Hoge* ret = new Hoge();
if (ret != NULL && ret->init()) {
ret->autorelease();
return ret;
}

CC_SAFE_DELETE(ret);
return NULL;


CCSpriteとかのcreate()もこうなってるので見てみてください。

 

cocos2d-xでxcodeプロジェクトを作成した時に最初にすべきこと

意図せず釣りっぽいタイトルになってしまった。。。

ここではinstall_template.shで導入したテンプレートを使ってxcodeプロジェクトを作成した時に最初にすべきことを書きます。

一言で言うと、それはResourcesグループとClassesグループのPathを設定することです。

XCodeのプロジェクトは、ファイルを入れるフォルダのことをグループと呼んでいて、このグループの木構造はプロジェクト不フォルダの実際のなフォルダ構造そのままとは限りません。
グループの場所が、プロジェクトフォルダ外の全く別の場所に結びついていても構わないわけです。

XCodeのウィンドウの左側(NavgatorのProjectNavigator)でフォルダのアイコンをマウスでフォーカスすると、ウィンドウの右側(Utilitiesのinspector)のIdentityというところに情報が出ます。
この中のPathが、ResourcesフォルダとClassesフォルダではNoneになっています。
つまり設定されていません。

このままの状態だと、[Add Files To...]でグループにファイルを作成すると、プロジェクトフォルダ直下に入ってしまい、実際のResourcesフォルダ内に作成されません。


対処方法は簡単で、Noneと書かれている部分の右にあるアイコンをクリックして、Resourcesフォルダの場所を教えてあげてください。
(Relative to Groupを選択した状態で行なってください)
そうすると、Resourcesグループに最初から入っていたファイルたちが、ProjectNavigatorで赤文字になると思います。
これは、格納されていたグループのPathの値が変わったことで一時的にファイルのPathがわからなくなっているのです。
それらに対しても、ProjectNavigatorですべてフォーカス選択した状態で、inspectorでNoneの右のアイコンをクリックし、Resourcesフォルダの場所を教えてあげると、赤文字状態は解消されます。


この問題は、project_creator.pyでは発生しません。
install-template.shが悪いんだから修正してPullRequestしろよ、という話なのですが、僕が面倒くさがってるだけです。
誰かやってくれると嬉しいな〜

cocos2d-xで等角タイルマップを扱うときのはまりどころ

■必須設定
http://www.cocos2d-x.org/boards/6/topics/25129
に設定を記載してくださった方がおり、この記事はその紹介です。

cocos2d-xバージョン2.1.3rc0(5/1リリース版)で等角タイルマップを扱うための必須設定は以下となります。
AppDelegate.cppに以下を加えます。

CCDirector *pDirector = CCDirector::sharedDirector();
pDirector->setDepthTest(true);
pDirector->setProjection(kCCDirectorProjection2D);

前者はCCNode::setVertexZ()を用いて、Z座標を操作する場合にのみ必要です。
前者はcocos2d-iphoneでは不要でした。

後者はcocos2dを2D投影モードなるものに設定するらしいのですが、どういうものかは未調査です。
わかったら追記しようと思います。

Tiledエディタでレイヤーのプロパティにcc_vertexzを設定する必要がありますので、それについては以下を参照してください。
http://www.cocos2d-x.org/projects/cocos2d-x/wiki/TileMap

■tmxファイル(Tiledエディタで作成したファイル)に対する制限
・タイルセット画像は一個しか扱えません。複数使っているとエラーになります。エラーメッセージが吐かれます。
  複数のタイルセット画像を使いたい場合はTexturePackerなどで1ファイルにまとめましょう。

・各レイヤーに必ず一つはタイルが必要です。
  全く無いレイヤーがあるとエラーになります。エラーメッセージが吐かれます。

cocos2d-xの場合はまだ情報が少ないこともあってはまりやすいので、エラーメッセージを見ることがデバッグのポイントになのかもしれませんね。

■おまけ
http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:tiled_maps
cc_alpha_funcの意味がよくわからない。。。
  

createJSでクロスドメインの画像ファイルを使った時のマウスイベントエラーへの対処

createjsでは、クロスドメインの問題で悩まされるときがあります。

その中の一つに、
「JSファイルを実行しているのと別のドメイン(画像を置いてるサーバなど)から画像をロードしたBitmap/BitmapAnimationだとマウスイベントが拾えない」
という問題があります。

ドメインの画像で作ったボタンなどをクリックするとChromeでは以下のJavascriptエラーが出ます。

Unable to get image data from canvas because the canvas has been tainted by cross-origin data.
Uncaught An error has occurred. This is most likely due to security restrictions on reading canvas pixel data with local or cross-domain images.

1行目はブラウザにより報告されているエラーです。
2行目はCreateJSにより報告されているエラーです。

createjsのソースを見ると、これは、DisplayObject.jsの_testHit()メソッドで生じていることがわかります。(easeljsバージョン0.6.0時点)

p._testHit = function(ctx) {
try {
var hit = ctx.getImageData(0, 0, 1, 1).data[3] > 1;
} catch (e) {
if (!DisplayObject.suppressCrossDomainErrors) {
throw "An error has occurred. This is most likely due to security restrictions on reading canvas pixel data with local or cross-domain images.";
}
}
return hit;
}

1行目はcanvasAPIであるgetImageData()で出ていて、2行目はthrowしているエラーメッセージです。
エラーを投げているのでここで処理が止まってしまいます。

getImageData()でエラーが発生しているのですから、suppressCrossDomainErrorsプロパティをtrueに設定しても解決しません。


蛇足ですが、この関数が何をやってるか説明すると、マウスポインタがある座標のピクセルのαが1(完全不透明が255です)より大きければヒットテストに合格した、と判定しています。
Easeljsは透過している部分をマウスイベントの対象から除外するんですよね。
>0でなく>1で判定している理由は不明です。



■対処方法
衝突判定のために衝突判定専用の表示オブジェクトを用意する、という定番の方法を利用します。
簡単なのは、ボタンと同じサイズのShapeを用意することですね。

サンプルソース

var button = new createjs.Bitmap('別ドメイン/button.png');
button.addEventListener("mousedown", buttonMouseDownHandler);
var hitObject = new createjs.Shape();
hitObject .graphics.beginFill("#000000").drawRect(0, 0, button.image.width, button.image.height);
button.hitArea = hitObject;

parentObject.addChild(button);



以下がポイントです。
①hitObjectの位置は、buttonの相対座標としてマウスイベント時に計算されます。なので、buttonと同じ位置に設定したければx=0、y=0でOK。
②マウスイベントリスナーはbuttonにつけてOKです。hitAreaに設定しているオブジェクトがあると、そちらに対して_hitTest()関数で判定されます。
③hitObjectは表示リストに加える必要がありません。なので、ステージ上には表示されません。αが不透明でありさえすれば何色であっても問題ありません。


特に、表示リストに加える必要がない!というのがhitAreaプロパティを使う利点かな、と思います。
表示リストに衝突判定専用のオブジェクトを加えるなら不透明が強制されるのは不便ですからね。