複数アセットをまとめて扱う
ゲームが複雑になると、利用するアセットも多くなり、それを扱うコードも煩雑になりがちです。 Akashic Engine は、アセットを複数まとめて管理しやすくするためのいくつかの機能を提供しています。
assets/ ディレクトリ
これまでの文書では、画像アセットは image/
、オーディオアセットは audio/
など、アセットの種類別にフォルダが分かれていました。 これは akashic scan asset
コマンドが、それらのディレクトリを検索する仕様になっているためです。 しかし複雑なゲームでは、アセットを種類ではなく意味で分類・整理したいかもしれません。 たとえばステージごとにマップデータと BGM と画像をまとめて保存する、という形にしたくなるかもしれません。
このような場合には、 assets/
ディレクトリが利用できます。 これは akashic scan asset
コマンドがアセットを検索するディレクトリの一つです (akashic-cli v1.14.3 から) 。 ただし他のディレクトリと次の点で異なります:
- アセットの種別が、ファイルの拡張子から自動的に決定される
- image: 拡張子が png, jpg, jpeg のファイル
- audio: 拡張子が ogg, m4a, aac のファイル
- script: 拡張子が js のファイル
- text: 上記以外の拡張子のファイル
- アセット ID が不定になる
これによりたとえば次のようなフォルダ構造が可能になります:
- assets/
- stage1/
- map.json
- background.png
- bgm.m4a
- bgm.ogg
- stage2/
- map.json
- background.png
- bgm.m4a
- bgm.ogg
- stage1/
assets/
以外のディレクトリでは、アセット ID はファイル名の basename (拡張子を抜いた部分) になります。 しかしこれには「basename が重複するアセットを一切作れない」という制限がつきます。 たとえば上の例に似た audio/stage1/bgm.m4a
と audio/stage2/bgm.m4a
を置くと、アセット ID が bgm
で重複してエラーになります。
assets/
ディレクトリは、この問題を回避するため、そもそもアセット ID を保証しません。 これにより basename の重複したアセットを許容します。ただしアセット ID でのアクセスはできなくなります (不定のため)。
複数アセットの一括ロード指定
ここまでの文書では assetPaths
にファイルパスを全て書いていましたが、glob を使って一括で指定することもできます。
const scene = new g.Scene({
game: g.game,
assetPaths: ["/image/character01.png", "/assets/**/*"]
});
この例でも使っているように、アセットパス形式では glob のサブセット文法(**
, *
, ?
) をサポートしています。
**
はあらゆるファイルや 0 個以上のディレクトリ、サブディレクトリにマッチします。*
は 0 文字以上任意の文字列にマッチします。?
は任意の 1 文字にマッチします。
上記サンプルコードの assetPaths
のグロブ指定("/assets/**/*"
)では、assets ディレクトリに下記のようなファイルが存在する場合、全てのファイルが対象となります。(対応するアセットが game.json に登録されている必要は引き続きあります)
- /assets/scenarios/scenario1.txt
- /assets/scenarios/scenario2.txt
- /assets/map.json
TIP
不要なアセットを読み込むとロード時間が延びてユーザ体験が悪化するので、 /**/*
のような指定は注意してください。
複数アセットの一括取得
複数アセットの一括ロード同様に、アセットの取得もグロブを利用して一括で取得することができます。 これには getAllImages()
, getAllAudios()
などのメソッドを利用します。getAllImages()
などの glob による複数検索では、該当するアセットの配列を返します。 アセットの指定には assetPaths
と同様に glob のサブセット文法(**
, *
, ?
) を利用できます。
// 複数の画像アセットの取得
const thumbnails = scene.asset.getAllImages("/assets/**/*.png");
for (let i = 0; i < thumbnails.length; i++) {
const thumbnail = new g.Sprite({
scene: scene,
src: thumbnails[i],
width: thumbnails[i].width,
height: thumbnails[i].height
});
...
}
// 複数のオーディオアセットの取得
const audios = scene.asset.getAllAudios("/audio/bgm*");
for (let i = 0; i < audios.length; i++) {
audios[i].stop();
}