LoginSignup
159

More than 5 years have passed since last update.

【Unity】ゲーム会社でスマホ向けゲームを開発して得た知識 アセットバンドル編

Last updated at Posted at 2015-03-06

2年目のゲームプログラマがゲーム会社で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のプレハブもアセットバンドルに含めるようにしました

ただし、シーンファイルをそのままアセットバンドル化できなかったため
アセットバンドルを作る前に次のような準備を行うようにしました

  1. シーンファイルのルートのオブジェクトをプレハブに変換する
  2. プレハブをアセットバンドル化する
  3. アセットバンドルからプレハブを読み込んで生成するためのシーンを用意する

アセットバンドルの読み込み

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.BuildAssetBundlecrcを受け取っておき
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

参考サイト様

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
159