Texture Packerを使ってみた

kobold2dのサンプルに入っていたParallax-Side-Scrollerを改造して自分のゲームにしている件です。
前回、Texture Packerのインストールまで進みました
今回、実際にTexture Packerを使ってスプライトシートを作り、kobold2dで作っているゲームのプロジェクトにAddしていきます。

まず、Texture Packerの使い方ですが、凄く詳細に書かれたページ(「ブレイブソフト 技術研究Blog」)があるのでそちらを参照しました。
また、Flashでコマアニメのswfを作ってTexture Packerで書き出す方法が、Texture PackerのTutorialsに掲載されていたので参考にしました。
今回作ろうとしているゲームの元ネタは、過去にFlashで作ったものだったので、swfが読み込めるのはとっても便利です。

130425 0004
Texture Packer自体の作業は簡単でした。swfファイルもpngなどと同様にドラッグアンドドロップでSpritesへボトっとやるだけです。自動的に中のアニメーションをスプライトシートへ展開してくれます。
上記のswfで書き出すチュートリアルの1〜3をやるだけで、スプライトシート(.pvr.cczと.plistのセット)がパブリッシュできました。
<追記>——
この後、swfを基にしたスプライトシートのパブリッシュが不具合を引き起こす問題に直面しました。使用には注意が必要です。
</追記>——

130504 0001
赤丸は、今回設定した箇所です。緑丸は好みで変更ですね。デフォルトでも良いと思います。
swfファイルで生成した際に注意すべき点は、生成されるスプライトフレームの名前が「swfファイル名+/XXXX(0000から始まる数字)」となってplistファイルへ記載される点です。全てのアニメーションを1つのswfでやろうとすると、XXXXの部分でキャラを見分けないと行けないので、Xcodeで呼び出す際に不便です。
Texture Packerではspritesの名前を変えられないようなので、Flashでキャラやキャラのアニメーション毎にシーンを分け、Flashのシーンプレビューでswfファイルをバラバラに書き出すか、flaファイルで分けるのが良さそうですね。

130501 0004
あと、Retina対応のスプライトシートを作る際には、Data fileで名前を付ける際に「-hd」として名前を付けないと、Retina対応の.pvr.cczファイルと.plistファイルのセットがパブリッシュされません。

130514 0003
この後、「AutoSD」という歯車みたいなボタンを押して、開いたウィンドウでそのまま「Apply」をクリックします。

<追記>
Texture Packerでスプライトシートを作ったら、「Save」で保存しておくと良いです。後で、画像を追加したい時に便利です。保存すると.tpsというファイルが生成されます。
</追記>

躓いたのは、kobold2dのサンプル「Parallax-Side-Scroller」で、UFO(monster-a.png)のキャラを自前のキャラ画像と差し替える時でした。

130501 0005
まず、Texture Packerで作った2つずつの.pvr.cczと.plistを、Xcodeのプロジェクトに「Add Files to “”」するのは問題ありませんでした。

次に、game-art.plistやmonster-a.pngとそのフレームに関する部分を、自前のplistやフレームに差し替えました。GameLayer.mのinitメソッド、

[frameCache addSpriteFramesWithFile:@"md.plist"];

EnemyEntity.mのinitWithTypeメソッド、

case EnemyMissile:
	enemyFrameName = @"enemyMissile.swf/0000";

EnemyCache.mのinitメソッドにありました。

	CCSpriteFrame* frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"enemyMissile.swf/0000"];

更に、GameLayer.mから使わなそうな以下をコメントアウトしました。

/*
	ShipEntity* ship = [ShipEntity ship];
	ship.position = CGPointMake([ship contentSize].width / 2, screenSize.height / 2);
	[self addChild:ship z:0 tag:GameSceneNodeTagShip];
*/

あと、bulletCacheメソッドでは中身をコメントアウトしてreturn false;を返すようにしました。

-(BulletCache*) bulletCache
{
    /*
	CCNode* node = [self getChildByTag:GameSceneNodeTagBulletCache];
	NSAssert([node isKindOfClass:[BulletCache class]], @"not a BulletCache");
	return (BulletCache*)node;
     */
    return false;
}

あと、EnemyEntity.mのinitWithTypeとEnemyCache.mのinitにあるswitch文では、自前のキャラをcaseに追加して、それ以外は消しました。

EnemyEntity.m

switch (type)
{
	case EnemyMissile:
		enemyFrameName = @"enemyMissile.swf/0000";
		break;

	default:
		[NSException exceptionWithName:@"EnemyEntity Exception" reason:@"unhandled enemy type" userInfo:nil];
}

EnemyCache.m

switch (i)
{
	case EnemyMissile:
		capacity = 10;
		break;

	default:
		[NSException exceptionWithName:@"EnemyCache Exception" reason:@"unhandled enemy type" userInfo:nil];
		break;
}

1点、どうしても解決できなかったのがスプライトのコマアニメーション(スプライトフレーム)です。EnemyEntity.mのinitWithTypeメソッドに以下があるとSIGABRTになってしまうので、丸ごとコメントアウトしました。

/*
	if (type == EnemyMissile)
	{
		// create an animation object from all the sprite animation frames
		float delay = CCRANDOM_0_1() * 0.04f + 0.1f;
		CCAnimation* anim = [CCAnimation animationWithFrames:@"enemyMissile.swf-anim" frameCount:2 delay:delay];
			
		// run the animation by using the CCAnimate action
		CCAnimate* animate = [CCAnimate actionWithAnimation:anim];
		CCRepeatForever* repeat = [CCRepeatForever actionWithAction:animate];
		[self runAction:repeat];
	}
*/

130501 0006
ここまでやって、何とかUFOを自前のミサイル画像に差し替えることができました!
まだ、コマアニメーションは出来ないし、動きも方向もサンプルのまんま横移動ですが、画像が差し変わったので少しモチベーションが上がってきました。

コマアニメーションは一旦放置して、次は先に簡単にできそうなキャラの動きを調整したいと思います。