Search Unity

Question Scenes and Prefab as Entity, weird behaviour

Discussion in 'Entity Component System' started by Vari-Mods, Apr 18, 2021.

  1. Vari-Mods

    Vari-Mods

    Joined:
    Jan 21, 2021
    Posts:
    7
    Hi,

    I am totally new to ECS and Unity. I am trying to keep my entities following the ECS approach. Get rid of GameObjects etc.
    I currently have 3 different scenes (some Starting scene "MANAGER", a server connection scene "LOGIN" and a scene for the first ingame view "WORLD").

    TheWorldScene just creates an Entity using a prefab. This ist just for an experimental purpose to get the very basics of entity creation and manipulation.
    As I am using GooglePlayServices for Android in the LOGIN-Scene. I startet to skip this one and jump instead to the WORLD-Scene .. Everything was fine. I saw my prefab (loaded as Entity) displayed in the editor. There was no GameObject attached to the scene.
    Code (CSharp):
    1. public class GameManager : MonoBehaviour
    2. {
    3.     public static GameManager instance;
    4.     private SceneIndexes currentScene;
    5.  
    6.     private void Awake()
    7.     {
    8.         instance = this;
    9.         DontDestroyOnLoad(instance);
    10.         currentScene = SceneIndexes.MANAGER;
    11.  
    12. #if UNITY_EDITOR
    13.         this.LoadScene(SceneIndexes.WORLD);
    14. #else
    15.         this.LoadScene(SceneIndexes.LOGIN);
    16. #endif
    17.  
    18.     }
    19.  
    20.     public void LoadScene(SceneIndexes sIndex) {
    21.         StartCoroutine(LoadAsyncScene(sIndex));
    22.     }
    23.  
    24.     private IEnumerator LoadAsyncScene(SceneIndexes sIndex) {
    25.         AsyncOperation asyncLoad = SceneManager.LoadSceneAsync((int)sIndex, LoadSceneMode.Additive);
    26.  
    27.         while (!asyncLoad.isDone)
    28.         {
    29.             yield return null;
    30.         }
    31.  
    32.         SceneManager.UnloadSceneAsync((int)currentScene);
    33.         currentScene = sIndex;
    34.     }
    35. }
    Code (CSharp):
    1. public class WorldScene : MonoBehaviour
    2. {
    3.     void Start()
    4.     {
    5.         EntityManager entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
    6.         Entity sw = entityManager.CreateEntityQuery(typeof(SampleWorld)).GetSingleton<SampleWorld>().Value;
    7.         entityManager.Instantiate(sw);
    8.     }
    9. }

    But now I thought, ok let's use the login scene, to connect to the server still, but skip the google stuff.
    So the idea ist to jump first to LOGIN-Scene and if login to the game server succeeded jump from LOGIN to the WORLD-Scene. Just 1 step in between. I can confirm that the server connects successfully, I got a token and continue to the WORLD scene.

    But now, I can see in the Entity Debugger, that all the entities where loaded, but I can't see any in the editor.
    Instead I get this error:
    I tried a bit around and got this working, which I dont prefer, because it was working the other way already. I thought it might be an timing issue, for whatever reason. But I was able to reduce the yield to 0s, which is almost like removing it.
    Code (CSharp):
    1. public class WorldScene : MonoBehaviour
    2. {
    3.     void Start()
    4.     {
    5.         //it won't work if I put the Entity-Code up here
    6.         StartCoroutine(this.Waiting());
    7.     }
    8.  
    9.     public IEnumerator Waiting()
    10.     {
    11.         yield return new WaitForSeconds(0);
    12.         EntityManager entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
    13.         Entity sw = entityManager.CreateEntityQuery(typeof(SampleWorld)).GetSingleton<SampleWorld>().Value;
    14.         entityManager.Instantiate(sw);
    15.     }
    16. }
    Does anyone has an idea why this happens? This Coroutine in my workaround is nothing I would like to keep :eek:
    I don't get why it is working if I skip the LOGIN-Scene. Even if I reduce the LOGIN-Scene to just load the WORLD-Scene, it won't work. :(

    Additionally, I think I didn't quite get if using Editor-Scenes and ECS/DOTS is good or bad. But as I have just beginner understanding of unity, the scenes helped me alot to set up some basics. Especially for UI stuff

    Thanks for reading that far :D
     
  2. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    This doesn't have anything to do with entities though. Its just how Unity callback ordering works.

    So when you're using StartCoroutine - it only runs next frame, no matter what yield instructions are in.
    And since you're using load async - it may not load required objects / scripts at all at the point WorldScene Start executes.

    Hence why GetSingleton will return 0 entities.

    As a suggestion, create / load your required entities before anything runs.
    Or specify prefabs directly via conversion or serialize via inspector field without fetching queries.

    Alternatively, use an event to notify WorldScene script that you've loaded the scene.
    Only then try to fetch singleton.


    Also, semi-unrelated - to "wait" for one frame - yield return null is enough. new WaitForSeconds(0) creates GC.