cocos2dxのCCSpriteBatchNodeを使って画像を敷き詰めてループ

Pocket

batchbg

えっと、同じ画像を敷き詰めた背景ってなんて言うんでしたっけ?
忘れちゃったんですけど、要は上みたいに同じ画像で背景を敷き詰め、かつそれを動かしたいなって思って作ってみました。

cocos2dxにはCCSpriteBatchNodeというとても便利な表示方法があるんで、それを利用して敷き詰めます。

cocos2dxでの画像の表示方法

その前に、cocos2d-xではどういう画像の表示方法があるかブログらしくおさらいします。
調べてみるとそれぞれの用途に合わせて7〜8くらい方法が用意されてるみたいなのですが、多分その中でも一番よく使うのが以下の3つかと思います。

  • CCSprite(通常)
  • CCSprite(テクスチャアトラス版)
  • CCSpriteBatchNode

CCSprite(通常版)

CCSprite* sprite = CCSprite::create("ファイル名");

超デフォルトなやつです。基本的にこれさえ知ってたらだいたい何でも表示できます。
特にデメリットというものではないのですが、たくさん画像を使う場合はこの方法ではなくテクスチャアトラスを使う方が効率がいいみたい。

CCSprite(テクスチャアトラス使用)

TexturePackerなどのソフトを使っていくつもの画像をくっつけたファイル(テクスチャアトラスまたはスプライトシートというそうです)とそれらの情報を記述したplistファイルを作成すると、簡単にテクスチャアトラスの恩恵を受けられるようになります。

ちなみにテクスチャアトラス(スプライトシート)とは、こんな感じにいくつもの画像をくっつけた画像ファイルになります。上のソフトを使うと作成したいくつもの画像をドラッグ&ドロップするだけで下のように作成してくれ、それらの位置情報を取り扱うplistも吐き出してくれます。
画像のサイズは2の累乗である必要がある(下の画像の場合128×256px)というのと、最大でも4096×4096以内に抑える(ただ端末によってはもっと上限が低いため、大きくても1024×1024px以内に抑えた方が無難みたい)という制約がcocos2dx及びopenGLではあるみたいですが、普通に表示するより断然メモリ使用効率がよくなるそうです。

scoresprite

ちなみにTexturePackerは有料で4000円します。ブログで使い方のレビューを書けばタダになるみたいな噂をあちこちで書いてるけど、実際はどうなのかよくわかんないです(´・ω・`)

使用の流れとしては、

  1. テクスチャアトラスの画像とplistを用意(img.pngとimg.plistみたいな)
  2. 使う前にplistファイルを読み込んでおく
  3. CCSprite::createWithSpriteFrameName()で識別名(フレーム名)を指定して読み込む

という感じです。plistファイルは一度だけ読み込めばキャッシュされるので、同じplist内にある画像を使う場合、二度目からはplistを読み込む必要はありません。

また、テクスチャアトラスの画像ファイルを読み込む必要もありません。それらの情報はplist内に入っている為、plistを読み込めば自動的に大元の画像もキャッシュされるみたいです。
あとは、plistに記載されているフレーム名を指定してそれぞれの画像を呼び出します。

//CCSceneなどで事前にplistファイルを読んでおく
CCSpriteFrameCache* cache = CCSpriteFrameCache::sharedSpriteFrameCache();
cache->addSpriteFramesWithFile("texture.plist");

//使用する場合は同じCCSprite
//ここの画像名は実際はplist内に記載されたフレーム名(frame1.pngのフレーム名)
CCSprite* sprite = CCSprite::createWithSpriteFrameName("frame1.png");
CCSprite* sprite2 = CCSprite::createWithSpriteFrameName("frame2.png");
...

//解放したい場合
CCSpriteFrameCache::sharedSpriteFrameCache()->removeSpriteFramesFromFile("texture.plist");

最初にplistを読み込むという点をのぞけば殆ど通常版との違いはないっぽいです。
(なにかCCActionできちんと動作しないのがあったけど、忘れちゃった(´・ω・`) ただ忘れちゃうくらいあまり使わないし通常のと使い勝手が変わらないってことですねきっと)

補足:メモリ効率がよくなる理由

ちなみにどうしてメモリ効率がよくなるかというと、cocos2dxではひとつの画像に対して「縦×横の長さがそれぞれ2の累乗」分の大きさでメモリを割り当てるのだそうです。多分openGLがそうなんでしょうね(よくわかってないですぼくは)。
だから50×50pxの画像を作ったとしても、メモリは64×64pxの画像と同じだけ消費します。257×513pxの画像を作った場合、512×1024pxの画像と同じだけ消費します。

もう見るからにメモリ使用効率悪そうですよね(´・_・`)
だから「ひとつの大きな画像にまとめちゃう方がいい」らしいですよ。ぼくもひとつおりこうさんになれました。

CCSpriteBatchNode

同じ画像を何十個も読み込むという場合は、このCCSpriteBatchNodeを利用する方がいいそうです。
多少の制約はあるのですが、それ以上の恩恵を受けることができます。

CCSpriteBatchNodeを利用するメリット

  • 1回のdrawコールで複数のスプライトを描画する→非常に描画が高速になる

CCSpriteBatchNodeでの制約

  • CCOrbitCamera、CCLens、CCRipple、CCTwirlなど一部のCCActionは対応していない(バグる)
  • 最初に読み込む画像と同じものしか高速描画できない

この「最初に読み込む画像」というのは、通常の画像にもテクスチャアトラスの画像にも対応しています。

/**
 *基本的な使い方
 */
//CCSpriteBatchNodeを作成
CCSpriteBatchNode* node = CCSpriteBatchNode::create("img.png");
//スプライトを作成
CCSprite* spr = CCSprite::create("img.png");
//作成したスプライトをCCSpriteBachNodeの中に入れる
node->addChild(spr);
//スプライトの画像が最初CCSpriteBatchNodeにあるものなら、たとえ1000個登録しても1回のコールで高速描画される

/**
 * テクスチャアトラスにも対応してるみたいだよ
 */
//テクスチャアトラスを読み込む
CCSpriteFrameCache* cache = CCSpriteFrameCache::sharedSpriteFrameCache();
cache->addSpriteFramesWithFile("texture.plist");
//その画像でCCSpriteBachNodeを作成
CCSpriteBatchNode* node = CCSpriteBatchNode::create("texture.png");
//スプライトを作成
//frame1.png及びframe2.pngがtexture.plist内のものであれば、いくつ呼び出しても高速描画される
CCSprite* spr = CCSprite::createWithSpriteFrameName("frame1.png");
node->addChild(spr);
CCSprite* spr2 = CCSprite::createWithSpriteFrameName("frame2.png");
node->addChild(spr2);

最初の呼び出し以外は殆ど変わらないからこれも使いやすそうですね。
それぞれの用途に合わせて使うようにしたらよさげです。

というわけで、CCSpriteBatchNodeでループ背景を作ってみる

本当はコードでも書こうかと思ったのですけど、コーディング下手だしとても長ったらしくなるだけな気がしたのでzipファイルにしてみました。
というかなんかそういうzipファイルにするのとかブログでしてみたかったんですよね。すごい人たちはみんなそういうことしてr(略)

これもそのCCSpriteBatchNodeで実装してます。

MoveTiledSprite.cpp

以下のような感じで使います。
※CCSpriteBatchNodeのテスト用で作った代物なので、バグのチェックはちょっとしかしてません。だから実用には耐えないかもですよ(´・ω・`)

MoveTiledSprite* tileBG = MoveTiledSplite::createWithSprite("image.png" , 動く早さ , 動く角度);
this->addChild(tileBG);

呼び出してみると、こんな感じで動いてくれます。

ちなみに左下のFPSがやたらと遅くなってるのはiOSシミュレータが遅いからです(´・ω・`)
背景のはだいたい同じ画像を90枚くらい呼び出してますが、CCSpriteBachNodeのおかげで描画回数は1回だけとなってることがわかります。

あとどうでもいいのですが、こういう動画のUPとかいうのもすごい人たちはみんなしてるし、やってみたかったんですよね〜。
なんか自己満ばかりですみません。

cocos2dxのCCSpriteBatchNodeを使って画像を敷き詰めてループ” への2件のコメント

  1. ピンバック: 【cocos2d-x】CCScale9Spriteで画像を部分的に引き延ばす | たそがれブランチ

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です