🕌
Addressablesでクラウドに保存したデータを表示する
はじめに
イワケンラボ(代表: イワケンさん)のメンバーとして、開発合宿に参加してきました!
まず、支援者としてたくさんの方々から金銭面中心に支援をいただきました。本当にありがとうございました!!!
今回の合宿では、Addressablesをテーマに取り組みました。今後アプリケーションを開発していく上で必須な技術だと感じ選定しました。この記事では、XR好き開発合宿ブログリレーの4日目担当として自分の発表内容をまとめます。
この記事で触れていること
- Addressablesとは
- Addressablesでできること
- Addressablesの基本的な使い方
- 工夫点
- ダウンロードサイズの事前表示
- ダウンロードの進捗状況の表示
- 今後の課題
- 新規C#スクリプトは配布できない
- ダウンロード進捗状況のユーザー向け表示
- (なお、この記事ではAssetBundleをクラウドにあげて利用することを前提としています)
環境
- Unity 2021.3.9f1
- Addressables 1.19.19
できたもの
- ビルドファイルには含めていないsceneやprefabをサーバー(AWS)から持ってきています。
- ダウンロードを開始する前に、ダウンロードサイズを表示しています。
- ダウンロードの進行中に、その進捗状況を表示しています。
Addressablesとは
- 一言で感覚値を言語化すると「AssetBundleのこと(依存関係や読み込みなど)を深く理解せずに、よしなにAssetBundleのビルド、読み込みをしてくれるもの」となります。
- Unityブログでは以下のように解説されています。参照の管理やメモリの管理を担ってくれます。
アセットバンドルの使用体験について開発者の方々とお話した所、うまく使用できている方々は皆、ほぼ同じ高水準システムを、少しずつ異なる様々な方法で記述されていることが分かりました。Addressables は、アセットのアドレス・ビルド・読み込みにまつわる一般的な問題各種を解決するフレームワークへの明白なニーズに対応すべく誕生しました。
Addressables 経由で読み込む場合、読み込まれるアセットとその依存の高水準な参照カウントが自動的に提供され、使用されなくなったバンドルとその関連アセットを自動的にアンロードすることができます。
Addressablesでできること
- Addressablesによってbuildされた.bundleファイルや.json等をクラウドに上げることで、ビルドファイルに含まれていないアセットをクライアントで表示することができます。
- ビルドファイルの軽量化ができます。(App Store等で配布するファイルは小さく。後から本データをダウンロードする)
- クライアントを更新せずに、コンテンツを更新することができます(※後述しますがC#スクリプトは不可)
- AssetBundleには、prefabまたはsceneを含めることができます。
Addressablesの基本的な使い方
-
Addressablesの基本的な手続きは以下のドキュメントがわかりやすくまとまっているので、そちらをご覧ください。この記事では、補足として数点追加します。
https://note.com/graffity/n/n8620f244894a
https://youtu.be/KJbNsaj1c1o -
補足1: Build & Load Pathの設定は2箇所(以上)で必要です。そうでないと自分の環境では、addressablesでbuildしても、.bundleファイルが生成されませんでした。
- Assets/AddressableAssetsData/AddressableAssetSettingsの設定。これはwindow > Asset Management > Addressables > Profilesで変更。
- 各Addressable Groupの設定(インスペクターで、Content Update > Build Remote Catalogをtrueに)
- Assets/AddressableAssetsData/AddressableAssetSettingsの設定。これはwindow > Asset Management > Addressables > Profilesで変更。
-
補足2: 設計の概要
- クラウドサービスはAWS S3を利用。GCPなどでも可。
- publicアクセスにしている(のでセキュリティに問題あり)
-
補足3: AWS S3の設定
- バケットを作成した時点では、パブリックなアクセスは認められていない
- (セキュリティの問題は後で回収するとして)以下の設定でパブリックなReadアクセスを許容することができる。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicRead",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::BUCKET-NAME/*"
}
]
}
工夫点
ダウンロードサイズの事前表示
- 事前に容量がわからないとユーザーはダウンロードするかどうか判断しにくくなるので欲しい情報。
- 以下のスクリプトを、適当なGameObjectにアタッチ
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using TMPro;
public class StartSceneManager : MonoBehaviour
{
[SerializeField]
TextMeshProUGUI loadSceneButtonText;
private void Start()
{
// キャッシュを削除しない場合は0と表示される(キャッシュがあったほうがよい場合が多いのであくまで開発用)
// 非同期メソッドはこの他も含めてAddressablesが用意してくれています。
Addressables.ClearDependencyCacheAsync("LoadedScene");
// ここでは文字列でアドレスを指定している
var handle = Addressables.GetDownloadSizeAsync("LoadedScene");
handle.Completed += _ => loadSceneButtonText.text = $"Load Scene {String.Format("{0:F2}", handle.Result / 1000000f)}MB" ;
}
}
- Addressables.GetDownloadSizeAsync()メソッドによって、ダウンロードをせずに、対象となっているファイルのサイズを取得することができる。
ダウンロードの進捗状況の表示
- 現在何%ダウンロードが完了したかを表示する
- (UniTask使いたくなったので使ってます)
(上記に加えて)
using System.Threading;
using Cysharp.Threading.Tasks;
public class StartSceneManager : MonoBehaviour
{
// ダウンロードサイズの事前表示コードは省略
// ボタンのイベントに設定
public void LoadAsset()
{
OnLoad(assetReference.InstantiateAsync());
}
async private void OnLoad(AsyncOperationHandle obj)
{
while (obj.IsDone == false)
{
await UniTask.Delay(100);
(// ここ同じif文通してるの汚い...)
if (obj.IsDone == false)
{
downloadPercent.text = String.Format("{0:F1}", obj.PercentComplete * 100f) + "%";
}
}
}
}
今後の課題
- 新規のC#スクリプトを配布することはできません。AssetBundleに含まれるのは、C#スクリプトの参照情報のみとなります。
- AssetBundleの中のとあるGameObjectが参照しているスクリプトが、buildの中に含まれていなければスクリプトの内容は動かない
- 逆に、buildの中に含まれればスクリプトが動く
- AssetBundle作成時から、スクリプトの内容を変更してbuildし直すと、AssetBundleを変更しなくても変更後のスクリプトの挙動となる
- ダウンロード状況の数字が飛び飛びになる(いきなり72%まで進んだら、急にゆっくりになり、最後急に99%まで飛ぶなど)。これはUnityの内部の挙動で仕方ないとのこと。ユーザーがダウンロード状況を見たときに飛び飛びに見えないように、表示する側でまた別のロジックを作り、バックエンド側の数字を包み隠すことで解決していきたい。
Discussion