【Unity ECS】BakeはStartよりも遅い(場合がある)

はじめに

気付いたきっかけ。

UnityEditor上では問題なく動くのに、Buildすると意図通りに動かない。そんな現象にあたりました。

MonoBehaviour(A)にBakerクラスを追加して、SpawnerComponentを作成。

別のMonoBehaviour(B)のStart()内で、SpawnerComponentにオブジェクトの生成数を設定。

SpawnerのSystemで設定された生成数分のオブジェクトをInstantiateということをやろうとしました。

しかし、これがUnityEditor上では動くのにビルドすると動かない状態になりました。

原因

最初原因がさっぱりわからなかったのですが、処理を追っていった結果、MonoBehaviour(B)のStart()内で、SpawnerComponentの取得に失敗しているようでした。

つまるところ、EditorとExeでのメソッドの実行順が変わってしまっていて、ExeではMonoBehaviour(A)のBakeメソッドが呼ばれる前にMonoBehaviour(B)のStartが呼ばれる挙動になっているようです。

対応

Bakeメソッドが呼ばれていること自体は確認できていて、順番だけの問題なので、Startメソッドでやりたかった処理内容をCoroutine化して、SpawnerComponentが生成されるまで繰り返すのが一番簡単そうな解決策でした。

実装例

MonoBehaviour(B)の初期化処理

    void Start()
    {
        StartCoroutine(InitializeWithDelay());
    }

    private IEnumerator InitializeWithDelay()
    {
        while (World.DefaultGameObjectInjectionWorld == null)
        {
            Debug.Log("Waiting for World...");
            yield return null;
        }

        _entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
        _cubeQuery = _entityManager.CreateEntityQuery(ComponentType.ReadWrite<CubeControlInfo>());

        while (true)
        {
            using var spawnerQuery = _entityManager.CreateEntityQuery(ComponentType.ReadWrite<EntitySpawnerComponent>());

            if (!spawnerQuery.IsEmpty)
            {
                var entity = spawnerQuery.GetSingletonEntity();
                var spawnerComponent = _entityManager.GetComponentData<EntitySpawnerComponent>(entity);

                //spawnerComponentになんか設定する
                spawnerComponent.settingA = A;

                _entityManager.SetComponentData(entity, spawnerComponent);
                Debug.Log("Successfully updated EntitySpawnerComponent");
                break;
            }

            yield return null;
        }
    }

さいごに

Editor上とExeの挙動が異なると困りますよね。

WinFormsのReleaseビルドとDebugビルドで動きが違うとかも追うのが大変なので、めっちゃ困ります。

でも、しばしばあたる問題なので、ノウハウを蓄積していきたいと思う今日このごろ。

どなたかのお役に立てば幸いです。

コメント

タイトルとURLをコピーしました