Help us understand the problem. What is going on with this article?

SpineをStarling1.7で使う:AssetManager経由の初期化に苦労する の巻

More than 3 years have passed since last update.

前回の投稿 SpineをStarling1.7で使う:2種類のTextureAtlasに注意 の巻 の続きです。 この投稿では、2種類のテクスチャアトラスのうち、Spine形式のデータを読み込んで初期化する流れを追います。
デモページは前回と同じやつです。

公式のデモではデータファイル3つをソースにEmbedして埋め込んでいますが、

  • raptor.json… キャラクター構造+モーションデータ
  • raptor.atras … Spine形式のテクスチャアトラス設定テキストデータ

  • raptor.png … テクスチャアトラスの画像データ

通常はデータファイルをソース外から動的に読み込むことが多いと思います。それぞれURLLoaderLoaderで読み込みSkeleton初期化する事は可能ですが、面倒なので、starling.utils.AssetManagerを使ってファイルを読み込んでみます。

AssetManager利用の実際のコード

コード例を交えながら、サクサク進めます。

sampple.as
// インスタンスを作ってファイル登録してロード
var assetManager:AssetManager = new AssetManager();
assetManager.enqueue("raptor.png");
assetManager.enqueue("raptor.atlas");
assetManager.enqueue("raptor.json");
ssetManager.loadQueue(function (ratio:Number):void {
    if (ratio == 1.0) {
      createRaptor();
    }
});

↑ ここはいつも通りのコードです。

sample.as
// ロード済みのファイルの取り出し
function createRaptor():void {
    var texture:Texture = _assetManager.getTexture("raptor");
    var json:Object = _assetManager.getObject("raptor");
    var atlasData:Object = _assetManager.getByteArray("raptor");

↑ pngはTextureとして、jsonはObjectとして、atrasデータのテキストは(getString的なメソッドがないため)ByteArrayとして取り出します。

GoblinsExample.as
[Embed(source = "/goblins-mesh.atlas", mimeType = "application/octet-stream")]
    static public const GoblinsAtlas:Class;

↑ Spine公式のデモでもapplication/octet-stream(なんかバイナリデータ)としてEmbedしています。これで大丈夫です。

sample.as
// atlasDataとテクスチャからアトラスを作成して
var spineAtlas:Atlas = new Atlas(atlasData, new StarlingTextureLoader(texture));
// アトラスを元にAttachmentLoaderとやらを作って
var attachmentLoader:AttachmentLoader = new AtlasAttachmentLoader(spineAtlas);
// AttachmentLoaderを元にSkeletonJsonクラスを作って(Jsonそのものではないです)
var json:SkeletonJson = new SkeletonJson(attachmentLoader);
// SkeletonJsonに読み込んだjsonを解釈させて
var skeletonData:SkeletonData = json.readSkeletonData(json);
// skeletonDataからSkeletonAnimationを(やっと)作ります
var raptor:SkeletonAnimation = new SkeletonAnimation(skeletonData, true);
addChild(raptor);

↑ めんどくさい手続きで画面に表示できるSkeletonAnimation(=DisplayObject)を作ります。ほぼ公式のサンプルのままのコードです。お決まり処理になるので、関数かなにかにまとめましょう。。継承ツリーは、SkeletonAnimation extends SkeletonSprite extends DisplayObject と、なっています。

面倒臭いながらも、SkeletonAnimationを生成できたので、これでOK!、と言いたいのですが、実は上記のコードにはエラーがあり、コンパイルは通るものの実行するとランタイムエラーになります。問題は下記の部分です。new StarlingTextureLoader()がエラーとなります。

error.as
var spineAtlas:Atlas = new Atlas(atlasData, new StarlingTextureLoader(texture));

引数の型としてはObject型なので隠蔽されますが、StarlingTextureLoaderはコンスタラクタの引数にBitmapかBitmapDataかBitmap、もしくは(アトラス画像が複数枚の場合)パスをキー名、BitmapかBitmapDataをValueに持つObjectを取ります。Texture型は引数にとりません。

sample.as
//`A Bitmap or BitmapData for an atlas that has only one page, or for a multi page atlas an object where the key is the image path and the value is the Bitmap or BitmapData.`
{
  "hoge1.png":hoge1BitmapData,
  "hoge2.png":hoge2BitmapData
}

と、いう事でraptor.pngをBitmap型としてStarlingTextureLoaderに引き渡したいのですが、、

AssetManagerからBitmapDataの参照は取れない

のです。AssetManagerは画像を読み込むと、その画像を元にすみやかにTextureインスタンスを生成し、画像すなわちBitmapDataを破棄してしまいます。使用メモリを少なくするための処理なのですが、(Spineを使う場合にに限らず)Bitmapを利用したい場合に困ってしまいます。AssetManagerを改造してBitmapを保持するようにしている人もいるようですが、自分はコアなライブラリであるStaling側に変更を極力加えたくないので、下記のような解決策を取りました。

専用のTextureLoaderを作ってしまおう

Textureインスタンスを引数に取るharayoki.spine.starling.MyStarlingTextureLoaderなるものを作りました。implements TextureLoaderです。クラス名はそのうち変えそうですが。。ソースはここにあります。中身はStarlingTextureLoaderをベースに改造して作られたものです)

sample.as
new MyStarlingTextureLoader(texture);
//もしくは
new MyStarlingTextureLoader({path1:texture1, path2:texture2});

↑ このようにインスタンス化が可能です。こちらのクラスを使って書き出したのが、前回と今回のデモページとなります。とりあえず、問題なく動いていますね。やあ、よかった、よかった。

まとめ

今回は専用TextureLoaderを作って問題を解決しましたが、Starling形式のatlasXMLを読み込んでSpineを使う場合はAssetManagerとの相性は抜群です。今回の投稿はSpine形式のatlasデータテキストと画像をAssetManagerで読み込んで使いたい場合のノウハウとなります。自分でパッキングまで行う人には必要ないノウハウですね。でも、他の作業者からデータをもらうような場合って、Spine形式のデータをもらうことになるほうが多いと思うんですよね。

そういうニーズがありそうなので公式でもTextureを引数にできるTextureLoaderを作ってよ、という要望をSpineのフォーラムに投げておきました。そのうち実装されると良いなあ。。
http://ja.esotericsoftware.com/forum/Wish-StarlingTextureLoader-can-be-instantiated-with-starling-6412

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away