2年目のゲームプログラマがゲーム会社でUnityを使用して
スマートフォン向けのゲームを開発して感じたことをまとめておきます
- 【Unity】ゲーム会社でスマホ向けゲームを開発して得た知識 コーディング編
- 【Unity】ゲーム会社でスマホ向けゲームを開発して得た知識 拡張メソッド編
- 【Unity】ゲーム会社でスマホ向けゲームを開発して得た知識 デバッグメニュー編
- 【Unity】ゲーム会社でスマホ向けゲームを開発して得た知識 UI編
- 【Unity】ゲーム会社でスマホ向けゲームを開発して得た知識 アセットバンドル編
アセットバンドル
今回、初めてアセットバンドル周りの実装を行いました
まだ依存関係の仕組みなどがちゃんと理解できていないですが、
今後のためにやったことを書き残しておきます
アセットバンドルの作成
リソースのフォルダ管理
今回開発したアプリにおいて、リソースは大きく分けて次の2種類がありました
- アプリに内包するリソース
- アセットバンドルに逃がすリソース
開発中はすべてのリソースをAssets/Resources
フォルダに格納していました
そして、内包するリソースはAssets/Resources/LocalData
フォルダに格納しておき
JenkinsでAPKやIPAを作成するときに、Assets/Resources
内のLocalData
フォルダに入っていない
すべてのリソースを削除してからAPKやIPAの作成を開始するようにして
アセットバンドルに逃がすリソースがアプリに含まれないようにしました
Switch Platformの時間の短縮
複数のプラットフォーム向けのアプリを開発している場合
各プラットフォーム用にアセットバンドルを作成する必要がありますが
1つのプロジェクトですべてのプラットフォーム用のアセットバンドルを作成しようとすると
Switch Platformに長時間かかってしまいます
今回開発したアプリではSwitch Platformに1時間半以上かかりました
そこで、Switch Platformの時間を短縮するために下記の2つの方法を試しました
- Fast Platform Switchを使用する
- 複数のプラットフォーム用にプロジェクトをチェックアウトする
Fast Platform Switchを使用する
Fast Platform Switchを使用すると2回目以降のプラットフォームの切り替えが高速になります
とても便利なアセットで、最初こちらを使用していたのですが
プラットフォームの切り替え中にUnityがクラッシュする不具合にときどき遭遇したので
途中からは複数のプラットフォーム用にプロジェクトをチェックアウトする方法をとりました
複数のプラットフォーム用にプロジェクトをチェックアウトする
SVNからプロジェクトをチェックアウトしてきた後に
一度だけSwitch Platformしておくだけなのでオススメです
シーンのアセットバンドル化
今回開発したアプリではUIの修正もサーバーのリソース更新のみで完結できるように
UIのプレハブもアセットバンドルに含めるようにしました
ただし、シーンファイルをそのままアセットバンドル化できなかったため
アセットバンドルを作る前に次のような準備を行うようにしました
- シーンファイルのルートのオブジェクトをプレハブに変換する
- プレハブをアセットバンドル化する
- アセットバンドルからプレハブを読み込んで生成するためのシーンを用意する
アセットバンドルの読み込み
DL中はターゲットフレームレートを60に設定する
Application.targetFrameRate = 60;
今回開発したアプリのターゲットフレームレートは30だったので、アセットバンドルのDLも少し遅くなってしまいました
なので、アセットバンドルのDL中のみターゲットフレームレートを60に設定することでDL時間を短縮するようにしました
WWW.LoadFromCacheOrDownload
を複数同時に実行する
最初はWWW.LoadFromCacheOrDownload
を1つしか実行しておらず、DLに時間がかかってしまっていたので
WWW.LoadFromCacheOrDownload
を複数同時に実行することでDL時間を短縮しました
アセットバンドルがキャッシュに存在するかどうか
アセットバンドルがキャッシュに存在するかどうかはCaching.IsVersionCached
で確認できます
今回開発したアプリではCaching.IsVersionCached
を使用して
不要なアセットバンドルがキャッシュに残っていないかどうかを確認するようにしました
アセットバンドルの個別削除
アセットバンドルを一括で削除する時はCaching.CleanCache
を使用したのですが
個別で削除する時はWWW.LoadFromCacheOrDownload
を使用しました
WWW.LoadFromCacheOrDownload
の第3引数のcrc
に0以外の適当な値を渡すことで
アセットバンドルを個別で削除することが可能です
WWW.LoadFromCacheOrDownload( url, version, 【適当な値】);
Caching
クラスに個別削除できそうな関数がいくつかあったのですが
これらを使用してもアセットバンドルを個別削除することはできませんでした
(使用を推奨しないことを表すObsolete
属性も適用されていました)
[Obsolete("this API is not for public use.")]
[WrapperlessIcall]
public static bool CleanNamedCache(string name);
[Obsolete("This function is obsolete and has no effect.")]
[WrapperlessIcall]
public static bool DeleteFromCache(string url);
なので、少し怖いやり方ですが今回はWWW.LoadFromCacheOrDownload
の第3引数のcrc
に
0以外の適当な値を渡す方法で、アセットバンドルの個別削除を実現しました
参考サイト様
キャッシュを削除するボタンを用意する
最近では「白猫プロジェクト」や「フルボッコヒーローズ」、「リトルテイルストーリー」などのゲームで
不要なキャッシュを削除するためのボタンがタイトル画面に配置されているのを見かけます
今回開発したアプリでもキャッシュを削除するためのボタンをゲーム内に用意することで
万が一、不要なアセットバンドルが端末に溜まってしまっても削除できるようにしました
アセットバンドルのプラットフォーム間の互換性
アセットバンドルはプラットフォーム間で互換性があります
例えばAndroid用のアセットバンドルやiOS用のアセットバンドルをUnityエディタ上で使用することが可能です
そのため、Android、iOS向けのアプリを開発している場合は
Unityエディタ用のアセットバンドルを作成する必要はありません
参考サイト様
遭遇した問題
古いバージョンのアセットバンドルがキャッシュに溜まっていく
WWW.LoadFromCacheOrDownload( url, version )
のversion
に新しい値を入れてアセットバンドルをDLすると
古いバージョンのアセットバンドルがキャッシュに残ったままになります(Unityの仕様のようです)
同じアセットバンドルの差分更新を行いたい場合は
アセットバンドルを作成する時にBuildPipeline.BuildAssetBundle
でcrc
を受け取っておき
WWW.LoadFromCacheOrDownload( url, 1, crc )
というような記述方法で
アセットバンドルをDLすることで実現可能のようです
この時、version
に新しい値を入れてしまうと古いバージョンのアセットバンドルが
キャッシュに残ってしまうため、version
には常に固定の値を指定します
int crc = 0;
BuildPipeline.BuildAssetBundle( mainAsset, assets, pathName, out crc );
var www = WWW.LoadFromCacheOrDownload( url, 1, crc );
iOSの同時ファイルオープン可能数によるエラー
開発中、iOSにおいて256個以上のアセットバンドルをDLして展開したままにしてしまったことで
それ以上リソースを読み込めなくなり、シーン遷移できなくなる問題に遭遇しました
使用メモリの削減のためにもオンメモリにする必要がないアセットバンドルは
WWW.LoadFromCacheOrDownload
でDLした後にAssetBundle.Unload
で解放する必要があります
フォルダのロックによるエラー
UnauthorizedAccessException: Access to the path "XXXX" is denied.
IOException: Lock violation on path XXXX
Couldn't move cache data into place.
アセットバンドル検証中にアセットバンドルのDL先のフォルダにロックがかかってしまうことがありました
フォルダにロックがかかった状態でWWW.LoadFromCacheOrDownload
を実行したところ
端末によって上記のようなエラーが発生することを確認したので書き残しておきます
スクリプトの変更によるエラー
AssetBundle loading failed because the AAAA script serialization hash does not match.
Supported: BBBB, loading: CCCC
The asset bundle 'DDDD' could not be loaded because it references scripts that are not compatible with the currently loaded ones.
Rebuild the AssetBundle to fix this error.
スクリプトを関連付けているプレハブをアセットバンドル化した場合は
それ以降、そのスクリプトにpublic
変数やSerializeField
属性が適用されたprivate
変数を追加すると
上記のエラーが発生してアセットバンドルの読み込みに失敗するようになります
public class Player : MonoBehaviour
{
}
例えば、上記のスクリプトをアセットバンドル化するプレハブに関連付けていた場合
public class Player : MonoBehaviour
{
public int Level;
[SerializeField]
private string Name;
}
アセットバンドルを作成した後にスクリプトをこのように変更してからアセットバンドルをDLすると
スクリプトの関連付けに失敗して前述のエラーが出力されます
このエラーを回避するためには下記のような対応を行う必要があります
- スクリプトを変更した段階でアセットバンドルを作りなおす
- アセットバンドル作成後にスクリプトに
public
変数やSerializeField
属性が適用されたprivate
変数を追加しない
参考サイト様
原因不明のエラー
WWWCached data can only be accessed using the assetBundle property!
You are trying to load data from a www stream which had the following error when downloading.
一度だけUnityエディタ上で発生したエラーです
その他
Windows7におけるアセットバンドルのDL先
C:\Users\【ユーザー名】\AppData\LocalLow\Unity\WebPlayer\Cache\【Company Name】