この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
Unityではモデルやテクスチャなどコード以外のデータをAssetBundlesという仕組みで管理できます。ユーザーが最新のデータをダウンロードすることでアプリのアップデートなしでモデルや素材の変更ができます。
概要
今回の記事でやること
前回作成した平面検出UnityアプリをAssetBundleに対応します。ボールのプレハブをサーバーからダウンロードするように変更して、アプリの更新なしでデータが変更されるか確認します。サーバーはPythonでローカル環境に構築します。
開発環境
- OS: macOS Monterey
- Unity Version:2020.3.20f1
- C#エディター: Visual Studio 2019 for Mac
- Python: 3.9.7
AssetBundle対応
AssetBundleを有効にする
AssetBundleを有効にするためにはコードを記述する必要があります。
- ProjectからAssetsを選択 > [Create] > [Folder] > Editorフォルダを作成
- Editorフォルダ内から [Create] > [C# Script] > ファイル名をCreateAssetBundleに変更
- 作成したCreateAssetBundleをダブルクリックして以下のように変更して保存
CreateAssetBundle.cs
using System.IO;
using UnityEditor;
using UnityEngine;
public class CreateAssetBundles : MonoBehaviour
{
[MenuItem("Assets/Build AssetBundles")]
static void BuildAllAssetBundles()
{
string assetBundleDirectory = "Assets/StreamingAssets";
if (!Directory.Exists(Application.streamingAssetsPath))
{
Directory.CreateDirectory(assetBundleDirectory);
}
BuildPipeline.BuildAssetBundles(assetBundleDirectory,
BuildAssetBundleOptions.None, EditorUserBuildSettings.activeBuildTarget);
}
}
ボールのプレハブをAssetBundleで管理するように変更する
- Shpereを選択 > Inspector最下部のAssetBundleドロップダウンを選択 > [New]を選択 > [testbundle]を入力
これでこのプレハブはAssetBundleでの管理対象になります。AssetBundleをビルドするとAssets/StreamingAssetsフォルダが生成されます。
- メニューから [Assets] > [Build AssetBundles]
データをサーバーからダウンロードするプログラムを作成する
今回はローカル環境にサーバーを立てるのでPCのIPを調べておきます。
データをダウンロードしてきてGameObjectをロードするプログラムを作成して保存します。
BundleWebLoader.cs
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
public class BundleWebLoader : MonoBehaviour
{
private string bundleUrl = "http://192.168.50.68:8000/assetbundles/testbundle";
private string assetName = "Sphere";
public IEnumerator GetBundle(Action<GameObject> callback)
{
UnityWebRequest www = UnityWebRequestAssetBundle.GetAssetBundle(bundleUrl);
yield return www.SendWebRequest();
if (www.result != UnityWebRequest.Result.Success)
{
Debug.LogError("Failed to download AssetBundle");
yield break;
}
else
{
AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(www);
callback(bundle.LoadAsset(assetName) as GameObject);
bundle.Unload(false);
}
}
}
アプリ起動時にオブジェクトをダウンロードするようにプログラム変更
アプリ起動時にAssetBundleをサーバーからダウンロードするようにプログラムを変更します。
PlaneDetection.cs
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;
public class PlaneDetection : MonoBehaviour
{
ARRaycastManager raycastManager;
BundleWebLoader loader;
// ダウンロードしてきたSphere
GameObject instantiate;
public delegate void Callback(Action<GameObject> gameObject);
private void Awake()
{
raycastManager = GetComponent<ARRaycastManager>();
}
void Start()
{
loader = new BundleWebLoader();
// ダウンロード開始
StartCoroutine(loader.GetBundle((GameObject obj) => {
// ダウンロードしたGameObject
instantiate = obj;
}));
}
void Update()
{
if (Input.touchCount == 0 || Input.GetTouch(0).phase != TouchPhase.Ended)
{
return;
}
var hits = new List<ARRaycastHit>();
if (raycastManager.Raycast(Input.GetTouch(0).position, hits, TrackableType.PlaneWithinPolygon))
{
var hitPose = hits[0].pose;
// ダウンロードに成功していればインスタンス化
if(instantiate != null)
{
Instantiate(instantiate, hitPose.position, hitPose.rotation);
}
}
}
}
ローカルサーバーを準備する
AssetBundle内のファイルを配置する
サーバーを起動したいフォルダ内にStreamingAssetsフォルダをコピーして、フォルダ名をassetbundlesに変更します。
今回はPythonでローカル環境にサーバーを立てます。Terminalで任意フォルダに移動してから以下コマンドでサーバーを立ち上げます。ポートを指定しない場合、設定は8000になります。
python3 -m http.server
※事前にウェブブラウザでプログラム内で設定したURLにアクセスしてファイルがダウンロードできることを確認してください。
アプリの実行
アプリをビルドし実行します。スクリーンショットは平面にボールを置いた結果です。
プレハブを変更して、再度アップロードする
ここからは、プレハブのマテリアル変更がアプリの再インストールなしで適用されるのかを確認します。
- メニューから [Assets] > [Create] > [Material] ファイル名をSphereMaterialに変更
- Sphereを選択から Main MapsのAlbedo横の色を選択し任意の色に変更
- SphereMaterialをSphereプレハブにドラッグ&ドロップするとマテリアルが適用されます
再度AssetBundleをビルドします。
- メニューから [Assets] > [Build AssetBundles]
ビルドが終わったらサーバーを起動しているフォルダ内のファイルを入れ替えます。
色が変わるのを確認
アプリを再起動して平面にボールを置くと色が変わっているのが確認できました。
まとめ
AssetBundleを使えばアプリを更新せずにデータ変更できることが確認できました。アプリ配信後にデータを変更したい場面はありそうなので何かと使えそうです。