サイトのトップへ戻る

libGDX ドキュメント 日本語訳

サイト内検索

ゲーム素材を管理する



AssetManagerを使いましょう

あなたのゲームがとてもシンプルでリソースの読み込みに大した時間がかからない場合、AssetManager (code)を使う必要はありません。 それ以外の場合は、以下のような優れた挙動のためAssetManagerを使用することをお勧めします:

  • ほとんどのリソースの読み込みが非同期で行われるので、リソースを読み込む間に対応したローディング画面を表示できます
  • ゲーム素材への参照がカウントされます。二つのゲーム素材AとBが他のゲーム素材Cに依存している場合、AとBが破棄されるまで C は破棄されません。 これはまた、複数回ゲーム素材を読み込む場合は自動的にそれを共有して1回分のメモリしか占有しないことも意味しています!
  • 全てのゲーム素材を一箇所に格納します。
  • 特に意識せずにキャッシュのような実装ができます(以下のFileHandleResolver を参照してください)

皆さん付いて来れてますか? では、続きを読んでみましょう。



AssetManagerを作成する

この部分はとても簡単です:

AssetManager manager = new AssetManager();

上記では、現時点でlibgdx が持つ全てのローダーが含まれた標準のAssetManagerを設定しています。それでは、ローダーがどのように動作するのか見てみましょう。

注意: 適切に管理しないのであれば、 AssetManager やその他リソース(Textureなどのような) をstaticにしないでください。 例えば、以下のようなコードでは問題が発生します:

public static AssetManager assets = new AssetManager();

static 変数のライフサイクルは必ずしもアプリケーションのライフサイクルと同じではないので、Androidでは上記コードで問題が発生します。 リソースが使えなくなっているにも関わらず、アプリケーションが前に使っていたAssetManagerインスタンスがまた使われてしまうことがあります。 これは一般的に黒い欠落Textureや誤ったゲーム素材が読み込まれてしまいます。

Androidでは、Activityの複数のインスタンスを同時に起動することさえも可能なので、適切にライフサイクルメソッドを制御したからといった安全だとは思わないでください! (詳細については StackOverflow のこの質問 を参照してください。)



ゲーム素材を読み込む

ゲーム素材を読み込むには、指定したゲーム素材タイプの読み込み方法をAssetManager が知っている必要があります。 この機能は AssetLoadersを介して実装されています。 そのために二つの variant型, SynchronousAssetLoader と AsynchronousAssetLoaderがあります。 SynchronousAssetLoader は描写用スレッド上で全ての素材を読み込みます。 AsynchronousAssetLoaderは素材の一部(例えばTextureに必要なPixmap )は別のスレッド上で読み込み、OpenGL 依存部分は描写用スレッド上で読み込みます。 以下のリソースについては、上記のようなAssetManager の枠に縛られずに読み込むことができます。

特定のゲーム素材を読み込むのは簡単です:

manager.load("data/mytexture.png", Texture.class);
manager.load("data/myfont.fnt", BitmapFont.class);
manager.load("data/mymusic.ogg", Music.class);

これらの呼び出し処理は、読み込みのためにキューに格納されます。 ゲーム素材は、 AssetManager#load() メソッドを呼び出した順に読み込まれます。いくつかの読み込みメソッドでは、 AssetManager#load()に引数を設定することもできます。 では、textureを読み込みために既定以外のフィルターとmipmapping の設定を行います:

TextureParameter param = new TextureParameter();
param.minFilter = TextureFilter.Linear;
param.genMipMaps = true;
manager.load("data/mytexture.png", Texture.class, param);

各引数の役割について知りたい場合は、読み込みメソッドの注釈を調べてください。

今のところは、ゲーム素材を読み込むためにキューに格納しただけです。AssetManager はまだ何も読み込んでいません。 読み込むを開始するには、ApplicationListener#render()メソッド内でAssetManager#update()を呼び出し続ける必要があります:

public MyAppListener implements ApplicationListener {

   public void render() {
      if(manager.update()) {
         // we are done loading, let's move to another screen!
      }

      // display loading information
      float progress = manager.getProgress()
      ... left to the reader ...
   }
}

AssetManager#update() がfalseを戻り値として返した場合は、まだゲーム素材を読み込んでいるということです。 読み込みの具体的な進捗状況を確認するには、 AssetManager#getProgress()を使用します。AssetManager#getProgress()は、現時点のゲーム素材の読み込み状況のパーセンテージを表す0~1の範囲の値を戻り値として返します。 AssetManager には他にも、 AssetManager#getLoadedAssets() やAssetManager#getQueuedAssets()のような同様の情報を取得するメソッドがあります。 読み込みを続けるには AssetManager#update() を呼び出す必要があります!

処理を一旦止めて全てのゲーム素材が読み込まれるまで待ちたい場合は、以下を呼び出します:

manager.finishLoading();

キューに格納されたゲーム素材が全て読み込まれるまで、処理が一旦停止されます。 ちょっと非同期読み込みの目的に反している気がしますが、場合によってはこの処理が必要な時もあるでしょう (例えば、ゲーム素材の読み込み時に読み込み画面を表示する必要がある、など)。



ゲーム素材を取得する

これも簡単です:

Texture tex = manager.get("data/mytexture.png", Texture.class);
BitmapFont font = manager.get("data/myfont.fnt", BitmapFont.class);

これはもちろん、ゲーム素材の読み込みが既に成功していることが前提です。特定のゲーム素材が読み込まれたかどうかを確認したい場合は、以下を実行します:

if(manager.isLoaded("data/mytexture.png")) {
   // texture is available, let's fetch it and do something interesting
   Texture tex = manager.get("data/mytexture.png", Texture.class);
}


ゲーム素材を破棄する

これも簡単で、以下のようにしてAssetManagerの実力を見ることができます:

manager.unload("data/myfont.fnt");

このフォントが既にあなたが手動で読み込んだTexture を参照している場合、そのTexture は破棄されません! It will be reference counted, getting one reference from the bitmap font and another from itself. このカウントがゼロでない限り、texture は破棄されません。

  • AssetManager で管理しているゲーム素材は手動で破棄してはいけません。代わりに AssetManager#unload()を実行してください!*

全てのゲーム素材を一度に削除したい場合は、以下を実行します:

manager.clear();

もしくは

manager.dispose();

両方とも、現在読み込まれている全てのゲーム素材を破棄し、キューに格納されてまだ読み込まれていないゲーム素材を削除します。 AssetManager#dispose() メソッドを使うと、 AssetManager 自身も破棄されます。このメソッドを実行したら、以降は そのマネージャは絶対に使用しないでください。

And that's pretty much everything there is. Now for the nitty-gritty parts.



I only supply Strings, where does the AssetManager load the assets from?

全てのローダーは FileHandleResolverへの参照を持っています。これは以下のようなシンプルなインタフェースです。:

public interface FileHandleResolver {
   public FileHandle resolve(String file);
}

既定では、全てのローダーは InternalFileHandleResolverを使用します。 これは Gdx.files.internal("data/mytexture.png")のようなinternal タイプのファイルを参照するFileHandle を戻り値として返します。 あなた独自のResolverを作成して使用することができます! FileHandleResolver の詳細に実装については assets/loaders/resolvers パッケージを見てください。 この場合のユースケースの一つは、キャッシュ機能です。まずはより新しいバージョンがダウンロードされていないか外部ストレージを確認し、特に変更がない場合は内部ストレージのバージョンを使用します。このような機能は、非常の多くの場面で役立つでしょう。

使用する FileHandleResolver は、AssetManagerの第二コンストラクタに引数として設定します:

AssetManager manager = new AssetManager(new ExternalFileHandleResolver());

これで、上記一覧にある全ての既定ローダーはこのFileHandleResolver を使用するようになります。



あなた独自のローダーを作成する

あなたが他にどういったタイプのリソースを読み込みたいのは私には分からないので、ある程度のところまで行くと、あなたは独自のローダーを作成したくなるかもしれません。 あなたは、SynchronousAssetLoader インタフェースとAsynchronousAssetLoader インタフェースの二つを使ってこれを実装できます。 読み込みが速い素材の場合は前者を使用し、進捗を示す読み込み画面を表示したい場合は後者を使用してください。 独自ローダーを作成する際には、前述のローダー一覧のうちのどれか一つを基して作成することをお勧めします。 SynchronousAssetLoaderの簡単な実装方法について知りたい場合はMusicLoader のソースを見て、 AsynchronousAssetLoaderの簡単な実装方法について知りたい場合はPixmapLoader のソースを見てください。 BitmapFontLoader のソースは、asynchronous ローダーを作成する際の良い例になるでしょう。BitmapFontLoader では、ゲーム素材を読み込む前に依存関係のあるファイル(この場合は文字イメージを格納したTexture)を読み込む必要があるからです。 繰り返しますが、これでほぼ全てのことが行えます。

ローダーの作成が完了したら、AssetManager へローダーに関する指示を出します:

manager.setLoader(MyAssetClass.class, new MyAssetLoader(new InternalFileHandleResolver()));
manager.load("data/myasset.mas", MyAssetClass.class);


アプリ再開時の読み込み画面

Android では、アプリの一時停止と再開を行えます。この場合、Textureのような OpenGL管理のリソースは再読み込みをする必要はありませんが、復帰に多少時間はかかります。 アプリ再開時に読み込み画面を表示したい場合は、AssetManagerを作成した後に以下を実行します。

Texture.setAssetManager(manager);

ApplicationListener#resume() メソッド内で、読み込み画面に切り替えて、全てが復帰するまで改めて AssetManager#update()を呼び出します。

上記コードのようにAssetManager を設定しない場合は、通常のtexture 管理メカニズムが起動するので、心配は要りません。

そして、これでやっと AssetManagerに関する記事は終わりです。