Addressables に関するよくある質問
最適な圧縮設定は何ですか?
[AssetBundle の圧縮] を参照してください。
多数の小さいバンドルと少数の大きいバンドルでは、どちらが効率的ですか?
[AssetBundle へのグループのパッキング] を参照してください。
カタログサイズを最小にする方法はありますか?
[カタログ設定] を参照してください。
addressables_content_state とは何ですか?
[コンテンツ状態ファイル] を参照してください。
規模により、どのような影響が考えられますか?
[プロジェクトの拡大時の規模による影響] を参照してください。
どのアセットロードモードを使用すべきですか?
[アセットロードモード] を参照してください。
内部命名モードには、どのような影響がありますか?
[グループの詳細設定] を参照してください。
ロードしたアセットを編集しても安全ですか?
プレイヤーで、または "Use Existing Build (requires built groups)" 再生モード設定の使用時にバンドルからロードされたアセットを編集する場合、 アセットはバンドルからロードされ、メモリ内にのみ存在します。ディスク上のバンドルに変更を再び書き込むことはできません。メモリ内のオブジェクトへの変更は、セッションが変わると失われます。
これは、"Use Asset Database (fastest)" または "Simulate Groups (advanced)" 再生モード設定の使用時とは異なります。これらのモードでは、アセットがプロジェクトファイルからロードされます。ロードされたアセットに加えられた変更によってプロジェクトアセットが変更され、変更はファイルに保存されます。
これを防ぐには、ランタイムに変更を行う場合、変更するオブジェクトを Instantiate メソッドでインスタンスの作成元として使用して、オブジェクトの新しいインスタンスを作成します。以下にコード例を示します。
var op = Addressables.LoadAssetAsync<GameObject>("myKey");
yield return op;
if (op.Result != null)
{
GameObject inst = UnityEngine.Object.Instantiate(op.Result);
// これで、ソースプロジェクトアセットが変更されることなく、安全に inst を使用して編集できます。
}
オブジェクトをインスタンス化するときは、以下に 注意してください。
- アセットを解放するときは、インスタンスではなく、AsyncOperationHandle または元のアセットを使用する必要があります。
- 他のアセットへの参照を含むアセットをインスタンス化しても、その参照先アセットの新しいインスタンスは作成されません。参照の対象はプロジェクトアセットのままです。
- Start、OnEnable、OnDisable などの Unity のメソッドは新しいインスタンスで呼び出されます。
アセットのアドレスまたは参照をランタイムに取得することはできますか?
最も一般的なケースでは、ロードされたアセットには、そのアドレスと IResourceLocation
のどちらとの結び付きもなくなっています。ただし、適切に関連付けられた IResourceLocation
を取得し、それを使用して PrimaryKey フィールドを読み取る方法はあります。PrimaryKey フィールドは、オブジェクトの元のグループで "Include Address In Catalog" が無効になっていない限り、アセットのアドレスに設定されます。無効になっている場合、PrimaryKey は、キーのリスト内の次の項目になります (多くの場合は GUID ですが、ラベルまたは空の文字列であることもあります)。
例
AssetReference のアドレスを取得します。これを行うには、その参照に関連付けられた場所を探し、PrimaryKey を取得します。
var op = Addressables.LoadResourceLocationsAsync(MyRef1);
yield return op;
if (op.Status == AsyncOperationStatus.Succeeded &&
op.Result != null &&
op.Result.Count > 0)
{
Debug.Log("address is: " + op.Result[0].PrimaryKey);
}
ラベルを指定して複数のアセットをロードし、それぞれにアドレスを関連付けます。ここでも、LoadResourceLocationsAsync が必要です。
Dictionary<string, GameObject> _preloadedObjects = new Dictionary<string, GameObject>();
private IEnumerator PreloadHazards()
{
//ラベルが "SpaceHazards" の場所をすべて見つける
var loadResourceLocationsHandle = Addressables.LoadResourceLocationsAsync("SpaceHazards", typeof(GameObject));
if( !loadResourceLocationsHandle.IsDone )
yield return loadResourceLocationsHandle;
//それぞれの場所のロードを開始する
List<AsyncOperationHandle> opList = new List<AsyncOperationHandle>();
foreach (IResourceLocation location in loadResourceLocationsHandle.Result)
{
AsyncOperationHandle<GameObject> loadAssetHandle = Addressables.LoadAssetAsync<GameObject>(location);
loadAssetHandle.Completed += obj => { _preloadedObjects.Add(location.PrimaryKey, obj.Result); };
opList.Add(loadAssetHandle);
}
//GroupOperation を作成して、上記のロードすべてを同時に待機する。
var groupOp = Addressables.ResourceManager.CreateGenericGroupOperation(opList);
if( !groupOp.IsDone )
yield return groupOp;
Addressables.Release(loadResourceLocationsHandle);
//結果を確認する。
foreach (var item in _preloadedObjects)
{
Debug.Log(item.Key + " - " + item.Value.name);
}
}
スクリプトの再コンパイル時に Addressables をビルドすることはできますか?
ドメインの再ロードをトリガーするビルド前ステップがある場合は、ドメインの再ロードの完了後まで Addressables ビルド自体が開始されないように、特に注意する必要があります。
スクリプティング定義シンボルを設定するメソッド (PlayerSettings.SetScriptingDefineSymbolsForGroup) や、アクティブなビルドターゲットを切り替えるメソッド (EditorUserBuildSettings.SwitchActiveBuildTarget) などを使用すると、スクリプトの再コンパイルと再ロードがトリガーされます。エディターコードの実行は、ドメインが再ロードされ、実行が停止するまで、現在ロードされているドメインで続行されます。プラットフォームに依存するコンパイル やカスタム定義はいずれも、ドメインが再ロードされるまでは設定されません。コードを正しくビルドするためにこれらの定義が必要な場合は、想定外の問題が発生する可能性があります。これは見逃されやすいため注意が必要です。
ベストプラクティス
コマンドライン引数または CI を介してビルドする場合、Unity では、コマンドライン引数 を使用して、目的のプラットフォームごとにエディターを再起動することを推奨しています。これにより、-executeMethod が呼び出される前に、スクリプトが確実にプラットフォーム用にコンパイルされます。
ビルド前にスクリプトを変更する安全な方法はありますか?
プラットフォームを切り替える場合、または、コードでエディタースクリプトを変更してから、設定された定義で続行する場合は、ドメインの再ロードを実行する必要があります。ただし、この場合は -quit 引数を使用できないことに注意してください。使用すると、呼び出されたメソッドの実行後すぐにエディターが終了します。
ドメインが再ロードされると、InitialiseOnLoad が呼び出されます。以下のコードは、スクリプティング定義シンボルを設定し、エディターコードでそれらに対応して、ドメインの再ロードの完了後に Addressables をビルドする方法を示しています。プラットフォームの切り替えと、プラットフォームに依存するコンパイル でも、同じプロセスを実行できます。
[InitializeOnLoad]
public class BuildWithScriptingDefinesExample
{
static BuildWithScriptingDefinesExample()
{
bool toBuild = SessionState.GetBool("BuildAddressables", false);
SessionState.EraseBool("BuildAddressables");
if (toBuild)
{
Debug.Log("Domain reload complete, building Addressables as requested");
BuildAddressablesAndRevertDefines();
}
}
[MenuItem("Build/Addressables with script define")]
public static void BuildTest()
{
# if !MYDEFINEHERE
Debug.Log("Setting up SessionState to inform an Addressables build is requested on next Domain Reload");
SessionState.SetBool("BuildAddressables", true);
string originalDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup);
string newDefines = string.IsNullOrEmpty(originalDefines) ? "MYDEFINEHERE" : originalDefines + ";MYDEFINEHERE";
Debug.Log("Setting Scripting Defines, this will then start compiling and begin a domain reload of the Editor Scripts.");
PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, newDefines);
# endif
}
static void BuildAddressablesAndRevertDefines()
{
# if MYDEFINEHERE
Debug.Log("Correct scripting defines set for desired build");
AddressableAssetSettings.BuildPlayerContent();
string originalDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup);
if (originalDefines.Contains(";MYDEFINEHERE"))
originalDefines = originalDefines.Replace(";MYDEFINEHERE", "");
else
originalDefines = originalDefines.Replace("MYDEFINEHERE", "");
PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, originalDefines);
AssetDatabase.SaveAssets();
# endif
EditorApplication.Exit(0);
}
}
Addressables の再ビルドが必要になるのは、スクリプトにどんな変更を加えた場合ですか?
Addressables コンテンツのクラスは、MonoScript オブジェクトを使用して参照されます。このオブジェクトは、アセンブリ名、[名前空間]、およびクラス名または参照先クラスを使用してクラスを定義します。
コンテンツをランタイムにロードするときは、MonoScript を使用して、ランタイムクラスのインスタンスがプレイヤーアセンブリからロードされ、作成されます。 MonoScript への変更は、プレイヤーと、ビルドされた Addressables コンテンツとの間で一貫している必要があります。クラスを正しくロードするには、プレイヤーと Addressables コンテンツの両方の再ビルドが必要です。
以下を行うと、MonoScript データの変更が必要になる可能性があります。
- 別の [アセンブリ定義ファイル] の影響を受ける場所にスクリプトファイルを移動する
- クラスを含む [アセンブリ定義ファイル] の名前を変更する
- クラスの [名前空間] を追加または変更する
- クラス名を変更する
バンドルへの変更を最小限にする方法
コンテンツバンドルのサイズは大きくなる可能性があるため、小さい変更のためにバンドル全体を更新すると、MonoScript を少し変更しただけで大量のデータが更新されることになる場合があります。 [Addressables 設定] で "MonoScript Bundle Naming Prefix" オプションを有効にすると、MonoScript オブジェクトを含むアセットバンドルが、シリアル化されたデータとは別にビルドされるようになります。 シリアル化されたクラスデータに変更がない場合は、MonoScript バンドルのみが変更され、その他のバンドルを更新する必要がなくなります。
サブオブジェクトへの参照
コンテンツビルドに何が含まれるかは、アセットとスクリプトがどのように相互に参照するかに大きく左右されます。 サブオブジェクトが関係していると、これが複雑になる可能性があります。
AssetReference
が Addressable アセットのサブオブジェクトを指している場合は、ビルド時にオブジェクト全体が AssetBundle
に組み込まれます。AssetReference
が GameObject
、ScriptableObject
、Scene
などの Addressable (アドレス指定可能) オブジェクトを指している場合は、サブオブジェクトが直接参照され、サブオブジェクトのみが暗黙の依存関係として AssetBundle
に含まれます。