アドレッサブルシーン
Addressables カタログから加算シーンをロード/アンロードする。キーごとの参照カウント付き。
現在のレベルの上に追加のシーンをストリーミングして出し入れ — 参照カウント付きなので、共有コンテンツが早すぎるタイミングでアンロードされることはありません。
| インターフェース | IAddressableSceneService |
| オフスイッチ | NullAddressableSceneService |
| アセンブリ | CommonGameSystem.AddressableScene(オプション — Addressables パッケージを削除するとコンパイルから外れる) |
| 起動 | 起動時に自動登録(23 サービスの 1 つ)— セットアップ不要 |
概要
このサービスは、すでに開いているシーンの上に Addressables カタログからシーンをロードし(加算ロード — 新しいシーンは現在のシーンを置き換えるのではなく、そこに加わります)、用が済んだらアンロードします。Addressables は Unity のアセット配信システムです:コンテンツはカタログにパブリッシュされ、実行時に文字列キーでロードされます。
各シーンキーは参照カウントされます:すでにライブなキーをロードすると既存のシーンを共有してカウントが上がり、シーンが本当にアンロードされるのはカウントが 0 に戻ったときだけです。実行中のロードも共有されます — 同じキーの重なった 2 つのロードは、1 つの操作を await します。
ランタイム障害は例外を投げません。キーが見つからない、またはロードが失敗した場合は、警告をログして Succeeded = false の結果を返すので、ゲームは動き続けます。
このサービスは一度に 1 操作だけ実行し、その IsLoading ゲートはシーンフローサービス(ISceneService)から独立しています — 両者が互いをブロックすることはありません。
オプションの CommonGameSystem.AddressableScene アセンブリで出荷されます。Addressables パッケージを削除すると、このアセンブリは自分自身をオフにし、フレームワークの残りはコンパイルされ続けます。
クイックスタート
using CommonGameSystem.Core;
using UnityEngine;
public class MySceneStreamer : MonoBehaviour
{
private IAddressableSceneService _scenes;
private void Awake() => _scenes = ServiceLocator.Resolve<IAddressableSceneService>();
public async void EnterArea()
{
SceneLoadResult result = await _scenes.LoadAdditiveAsync("DlcArea_01");
if (result.Succeeded) { /* scene is live */ }
}
// later, when you're done with it:
public async void LeaveArea()
{
await _scenes.UnloadAdditiveAsync("DlcArea_01"); // count goes down; unloads at 0
}
}
Bootstrap は起動時にこのサービスを自動登録します。上のように、Awake() で一度解決してキャッシュしてください。
API リファレンス
IAddressableSceneService
| メンバー | 説明 |
|---|---|
Task<SceneLoadResult> LoadAdditiveAsync(string key, CancellationToken ct = default) | カタログのシーンを加算ロードします。すでにライブなキーをロードすると既存のシーンを共有します:カウントが上がり、共有された結果を受け取ります。別の操作の実行中にロードを開始すると、メッセージが [AddrScene] で始まる InvalidOperationException を投げます。キーが見つからない、またはロードが失敗した場合は決して例外を投げません — 警告をログして Succeeded = false を返します。例外を投げるのはプログラミングエラーだけです:null や空白のキー、破棄済みのサービス、ワーカースレッドからの呼び出し。 |
Task UnloadAdditiveAsync(string key, CancellationToken ct = default) | ロード済みキーの参照カウントを下げます。シーンがアンロードされるのはカウントが 0 に達したときだけで、自動追い出しはありません。ロードされていないキーのアンロードは決して例外を投げません — 警告をログして完了済みタスクを返します。 |
IReadOnlyList<string> ActiveSceneList { get; } | 現在ロードされている異なるシーンキーを、ロード順で。読み取り専用のスナップショットで、参照カウントは公開されません。サービスがオフのときは空です。 |
bool IsLoading { get; } | このサービスに実行中の操作があるかどうか。ISceneService.IsLoading とは別物です — 「何かシーン処理が走っているか?」を知りたければ両方を確認してください。 |
SceneLoadResult
シーンフローサービスが使うものと同じ結果型です:
| メンバー | 説明 |
|---|---|
string SceneName | この結果が属するシーンキー。 |
bool Succeeded | 成功とログ済みの失敗を見分けるには、これで分岐します。 |
bool Canceled | ここでは未使用 — 常に false。 |
Exception Error | あれば、根底にある失敗。 |
TimeSpan TotalDuration | 操作にかかった時間。 |
イベント
イベントバス上でパブリッシュされます — ペアリング保証については下の落とし穴を参照:
| イベント | 発火タイミング |
|---|---|
AddrSceneLoadStarted(string Key) | 実際のロードが始まった(キーが未ロードからロード中になった)。 |
AddrSceneLoadCompleted(string Key, SceneLoadResult Result) | ロードがキャンセルされずに終わった(成功またはログ済みの失敗)。 |
AddrSceneLoadCanceled(string Key, Exception Cause) | 実行中のロードが、その CancellationToken によりキャンセルされた。 |
AddressableSceneOptions — コンストラクタ設定
| メンバー | 説明 |
|---|---|
bool WarnOnMissingKey / bool WarnOnUnloadOfUnloaded | 警告の饒舌さ。Default プリセットは警告し(診断しやすい)、Release プリセットは沈黙します。 |
int InitialKeyCapacity | 内部シーンテーブルの初期容量。0–1024 にクランプ。 |
使用例
using CommonGameSystem.Core;
using UnityEngine;
public class DlcLoader : MonoBehaviour
{
private IAddressableSceneService _scenes;
private const string DlcKey = "DlcArea_01";
private void Awake() => _scenes = ServiceLocator.Resolve<IAddressableSceneService>();
public async void EnterDlc()
{
// Loading twice is safe: a second call while live just raises the count.
SceneLoadResult result = await _scenes.LoadAdditiveAsync(DlcKey);
if (!result.Succeeded)
{
Debug.LogWarning($"DLC scene didn't load: {result.Error}");
return;
}
Debug.Log($"Loaded in {result.TotalDuration.TotalMilliseconds:F0} ms. " +
$"Active: {string.Join(", ", _scenes.ActiveSceneList)}");
}
public async void LeaveDlc() => await _scenes.UnloadAdditiveAsync(DlcKey); // unloads at count 0
}
無効化する
ServiceLocator.Replace<IAddressableSceneService>(new NullAddressableSceneService());
これですべての加算ロードが抑止されます。LoadAdditiveAsync は呼び出し側が動き続けるよう Succeeded = true の完了済み結果を返し、UnloadAdditiveAsync は何もせず、ActiveSceneList は空で、イベントは発火しません。ヘッドレステストや、カタログコンテンツなしで出荷するビルドに便利です。置き換えの構築時に 1 回警告がログされるので、差し替えが無音で起きることはありません。プログラミングエラーは引き続き例外を投げ — null キーはやはり ArgumentNullException を投げます — 要求されたキャンセルも引き続き尊重されます。
よくある落とし穴
- 参照カウントは呼び出しの対を意味します。 2 回の
LoadAdditiveAsync("X")はカウントを 2 にします。シーンは最初のUnloadAdditiveAsync("X")を生き延び、2 回目でようやくアンロードされます。すべてのロードにちょうど 1 回のアンロードを対にしないと、シーンを生かしたまま残すことになります。 - ゲートはシーンフローから独立しています。 ここでの
IsLoadingはこのサービス自身のロックです。シーンフローの操作をブロックすることも、ブロックされることもありません。[AddrScene]のInvalidOperationExceptionを投げるのは、このサービス上の 2 つの操作が重なったときだけです。 - すべての開始は、ちょうど 1 回クローズされます。 共有されたロードと拒否された呼び出しはイベントをパブリッシュしません。したがって各
AddrSceneLoadStartedには、ちょうど 1 つのAddrSceneLoadCompletedまたはちょうど 1 つのAddrSceneLoadCanceledが対応します — 両方でも、どちらもなしでもありません。 - 通常のシーン遷移は加算シーンを破壊します。 ゲームがフル(非加算)のシーン切り替えを行うと、Unity はすべての加算シーンをアンロードします — このサービスがまだ追跡しているものも含めてです。そうした遷移の後は、必要なものをロードし直してください。
関連ページ
- シーンフロー — ベースのシーンローダー(
ISceneService)。Unity のビルドリストからの独自の加算ロードも含む - アセットプロバイダー — 兄弟サービス:同じ参照カウント方式による Addressables のアセットロード
- イベントバス —
AddrSceneLoad*イベントの購読