Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

【Unity】ZenjectSceneLoaderをAddressables.LoadSceneAsync()に対応させる【Extenject】

はじめに

最近やっとAddressable Asset System(Addressables?正式名称わからず)を使い始め、シーンのロードにも対応していることに驚きました。

自分は Extenject 使いなので今後シーンのロードは Addressables + ZenjectSceneLoader でやろうと思ったのですが、ZenjectSceneLoaderAssetReference によるシーン読み込みに対応してなかったので、検証したり対応してみたりしました。

Extenject with Addressablesの状況

Unity Addressable Assets #8(Extenjectリポジトリのissue)

In terms of addressable assets, I'm not really sure. I haven't played with it yet. But we could certainly add it as an alternative to prefabs when it's ready

Addressablesからのプレハブのバインドに関するissueはあるっぽいのですが、シーンのロードに関してはなさそうでした。

そもそも対応しないとどうなる?

API ProjectContext Bindings Parent Bindings Self Bindings
Addressables.LoadSceneAsync(.. Single) -
Addressables.LoadSceneAsync(.. Additive)
Addressables.LoadSceneAsync(.. Additive) + Contract Names
ZenjectSceneLoader#LoadSceneAsync(.. Single) -
ZenjectSceneLoader#LoadSceneAsync(.. Additive, .. Child)
ZenjectSceneLoader#LoadSceneAsync(.. Additive) + Contract Names
  • ⭕,❌:そのままの状態のときの挙動
  • ✅:APIを足したことにより実現した挙動

検証してみたら Addressables.LoadSceneAsync(.. Additive) + Contract Names は普通に動いたので驚きましたが、 ZenjectSceneLoader を用いて動的にペアレンティングしたい場合は対応する必要がありそうでした。

対応させてみる

環境

  • macOS Catalina 10.15.5
  • Unity 2018.4.21f1
  • Extenject 8.0.1
  • Addressables 1.10.0
  • エディター上・スタンドアロンビルドで簡単な動作検証済み

動作検証用に簡単なプロジェクトを作ったので興味ある人はこちらのリポジトリをクローンして触ってみてください。

ExtenjectからAddressablesを参照できるようにする

それぞれAssembly DefinitionでDLLが区切られているので zenject.asmdef にAddressables関連の asmdef への参照を追加します。

zenject_asmdef.png

AssetReferenceSceneAssetを実装する

AssetReference をそのまま使ってもいいのですが、 SceneAsset 以外の参照を渡したときにコンパイルエラーにしたいので SceneAsset 専用の参照クラスを実装します。

参考:something like AssetReferenceT(Unityフォーラム)

AssetReferenceSceneAsset.cs
using System;
using UnityEngine.AddressableAssets;

[Serializable]
public class AssetReferenceSceneAsset : AssetReferenceT<
#if UNITY_EDITOR
    UnityEditor.SceneAsset
#else
    UnityEngine.Object
#endif
>
{
    public AssetReferenceSceneAsset(string guid) : base(guid)
    {
    }
}

このクラスをExtenjectから参照できるようにします。

  • Assets/Plugins/Zenject/Source とかの zenject.asmdef配下に置く
  • 自前の asmdef の配下に置いて先の手順のように zenject.asmdef に参照を足す

などプロジェクトに応じてよしなに設定します。

ZenjectSceneLoader にメソッドを追加する

以下を追加します。

ZenjectSceneLoader.cs
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceProviders;

...

public AsyncOperationHandle<SceneInstance> LoadSceneAsync(AssetReferenceSceneAsset sceneReference)
{
    return LoadSceneAsync(sceneReference, LoadSceneMode.Single);
}

public AsyncOperationHandle<SceneInstance> LoadSceneAsync(AssetReferenceSceneAsset sceneReference, LoadSceneMode loadMode)
{
    return LoadSceneAsync(sceneReference, loadMode, null);
}

public AsyncOperationHandle<SceneInstance> LoadSceneAsync(
    AssetReferenceSceneAsset sceneReference, LoadSceneMode loadMode, Action<DiContainer> extraBindings)
{
    return LoadSceneAsync(sceneReference, loadMode, extraBindings, LoadSceneRelationship.None);
}

public AsyncOperationHandle<SceneInstance> LoadSceneAsync(
    AssetReferenceSceneAsset sceneReference,
    LoadSceneMode loadMode,
    Action<DiContainer> extraBindings,
    LoadSceneRelationship containerMode)
{
    return LoadSceneAsync(
        sceneReference, loadMode, extraBindings, containerMode, null);
}

public AsyncOperationHandle<SceneInstance> LoadSceneAsync(
    AssetReferenceSceneAsset sceneReference,
    LoadSceneMode loadMode,
    Action<DiContainer> extraBindings,
    LoadSceneRelationship containerMode,
    Action<DiContainer> extraBindingsLate)
{
    PrepareForLoadScene(loadMode, extraBindings, extraBindingsLate, containerMode);

    return Addressables.LoadSceneAsync(sceneReference, loadMode);
}

ちなみにこれらはZenjectSceneLoader の既存の LoadSceneAsync() をコピペして

  • 返り値
  • 引数
  • SceneManager

をAddressables対応仕様に書き換えただけのものです。

これで ZenjectSceneLoader にシーンの参照を渡してロードしつつ、シーン内の [Inject] に適切にInjectされるようにできました。

Extenject_with_Addressables.gif
↑スタンドアロンビルドでの検証(gif)

感想

Addressablesを使ったバインディングのベストプラクティスが知りたい。

su10
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away