- AssetBundleとは
- 1:Editorフォルダを作成する。
- 2:アセットバンドルをエクスポートするためのスクリプトを書く。
- 3:第一引数で書いた通りにフォルダを作成する。
- 4:アセットバンドルにしたいprefabにアセットバンドル名をつける。
- 5:メニューのAssets > Build AssetBundlesを実行する。
- 6:アセットバンドルをサーバーにアップする
- 7:アセットバンドルを読み込むスクリプトを書く。
AssetBundleとは
シーン・スプライト・プレハブなどをサーバーからアプリに読み込むもの。
メリットは、Appの容量を抑えられる。
デメリットは、ダウンロードに時間がかかる場合がある。
以前、最初のスプラッシュ画面で一括読み込みを試みたんですが、ダウンロードに時間がかかり過ぎたみたいで散々でした。
ということで、今回は移動ごとにゲームシーンを読み込む作戦にきりかえてみます。
一度読み込んだシーンは、保持できるので、初めての場面では表示が遅くなりますが、ゲームができないよりはマシかと。
1:Editorフォルダを作成する。
Editorフォルダに入れないとエラーでたので、念のため。
2:アセットバンドルをエクスポートするためのスクリプトを書く。
手順1で作ったEditorフォルダにCreateAssetBundles.csを作る。
using UnityEditor; public class CreateAssetBundles { [MenuItem ("Assets/Build AssetBundles")] static void BuildAllAssetBundles () { // Android用 BuildPipeline.BuildAssetBundles ("Assets/AssetBundles/Build/Android", BuildAssetBundleOptions.ChunkBasedCompression, BuildTarget.Android); // iOS用 BuildPipeline.BuildAssetBundles ("Assets/AssetBundles/Build/iOS", BuildAssetBundleOptions.ChunkBasedCompression, BuildTarget.iOS); } }
[MenuItem ("Assets/Build AssetBundles")]
これを書くと、Unityのメニューに" "の項目が追加される。
BuildPipeline.BuildAssetBundles();
エディターで指定されたすべてのアセットバンドルを作成する。
第一引数 "Assets/AssetBundles/Build/Android"
生成されるアセットバンドルファイルを保管する場所
第二引数 BuildAssetBundleOptions.ChunkBasedCompression
アセットバンドルのビルドオプション
圧縮してくれるほうが良さそうだったので、なんとなくそれを選んで見た。
詳細は公式にて:
docs.unity3d.com
第三引数 BuildTarget.Android
プラットフォームの設定
3:第一引数で書いた通りにフォルダを作成する。
4:アセットバンドルにしたいprefabにアセットバンドル名をつける。
prefabを選択すると、インスペクターの下側に表示されるassetBundleのところでNoneになっているから、Newで新しい名前をつける。
名前はすべて小文字になるので注意。
5:メニューのAssets > Build AssetBundlesを実行する。
ファイル数が多いとかなり時間がかかるので、気長に待つ。
こんな感じで生成される。
6:アセットバンドルをサーバーにアップする
作成されたファイルをサーバーにアップして置く。
7:アセットバンドルを読み込むスクリプトを書く。
いつもは、ゲームシーン移動専用のMoveクラスを作成し、そこでResouceに配置したゲームシーンプレハブをstage(空のGameObject)にInstantiate()で配置している。
ということで、Moveクラスをカスタマイズして使うことにした。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Move : MonoBehaviour { //シングルトン用 static public Move instance; //すでに配置されているプレハブ GameObject now; //バージョン int version = 1; //AssetBundle URL string bundleURL; //対象のバンドル名 string bundleName; //キャッシュ AssetBundle chach; //キャッシュからバンドル名で呼び出すためのdictionary Dictionary<string, GameObject> bundleList = new Dictionary<string, GameObject> (); void Awake () { //シングルトン処理 if (instance == null) { instance = this; DontDestroyOnLoad (this.gameObject); } else { Destroy (this.gameObject); } } public void OnMove (string sceneName) { bundleName = sceneName; if (!bundleList.ContainsKey (sceneName)) { //URL設定 #if UNITY_EDITOR bundleURL = "file://" + Application.dataPath + "/AssetBundles/Build/Android/" + bundleName; #elif UNITY_ANDROID bundleURL = "http://hogehoge/android/"+bundleName; #elif UNITY_IOS bundleURL = "http://hogehoge/ios/"+bundleName; #endif //バージョンチェック if (PlayerPrefs.GetInt ("bundleVersion", -1) != version) { Caching.CleanCache (); PlayerPrefs.SetInt ("bundleVersion", version); } StartCoroutine ("Import"); } else { OnComplete (); } } IEnumerator Import () { //キャッシュの読み込み準備待ち while (!Caching.ready) { yield return null; } //ダウンロード WWW www = WWW.LoadFromCacheOrDownload (bundleURL, version); while (!www.isDone) { yield return null; } //アセットバンドルをキャッシュ chach = www.assetBundle; //dictionaryに保管 string[] names = chach.GetAllAssetNames (); for (int i = 0; i < names.Length; i++) { bundleList.Add(chach.LoadAsset<GameObject>(names[i]).name, chach.LoadAsset<GameObject>(names[i])); } foreach (var keyValuePair in bundleList) { Debug.Log(keyValuePair.Key); } //リクエストの解放 www.Dispose (); OnComplete (); } void OnComplete () { prefab = bundleList [bundleName]; if (prefab != null) { if (now != null) { Destroy (now); } now = Instantiate (prefab); GameObject stage = GameObject.Find ("stage"); now.transform.SetParent (stage.transform); now.transform.localPosition = Vector3.zero; now.transform.localScale = Vector3.one; //保存 PlayerPrefs.SetString ("presentScene", bundleName); } } }
シングルトンにした理由
・エンディングでシーンが切り替わる→ゲーム本編のシーンに戻るとbundleListが空っぽになっちゃうので、シングルトンにして保持することにした。
処理の流れ
1:OnMove()で実行される。 引数はアセットバンドル名になる。
2:バージョンチェックをして、新しいバージョンがあればキャッシュをクリアする。
なので、アセットバンドルを変更したときは、このバージョンも変更すること。
3:キャッシュがあればキャッシュから、キャッシュがなければサーバーから読み込む。
この部分→ WWW www = WWW.LoadFromCacheOrDownload (bundleURL, version);
4:読込先のファイルURLはbundleURLに設定する。
Unityで再生した場合はローカルファイルから読み込むようにしてある。
サーバーにアップしたURLをそれぞれ設定すること。
5:読み込み後は、bundleListに順に代入していく。
key=バンドル名 , value=ゲームシーンのprefab
6:bundleListが作成されたら、OnComplete()でstageに配置する。
stageがゲーム本編にしか配置していないので、ゲームシーン移動時に毎回Findすることにした。
※2度目以降は、キャッシュから読み込む必要がないので、bundleListのkeyがあるかどうかを調べて、あるなら配置のみ。
以上。
[ 2019/09/12 修正 ] 項目4と5が逆になってたのを修正。