Execution order between MonoBehaviour Start() and Subscene converted entity

Hi

I’m trying to understand the best way to communicate transforms to a GameObject in my main Scene from my Entity. This is my current setup.

I have a GameObject in a Subscene that is converted to an Entity with the the following Authoring script to tag it.

public struct FollowTag : IComponentData { }

[DisallowMultipleComponent]
public class FollowTagAuthoring : MonoBehaviour
{
    class Baker : Baker<FollowTagAuthoring>
    {
        public override void Bake(FollowTagAuthoring authoring)
        {
            Entity entity = GetEntity(TransformUsageFlags.None);
            AddComponent(entity, new FollowTag {});
        }
    }
}

I then have a GameObject in my MainScene which I want to follow the Entity, with the following MonoBehaviour.

using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;

public class EntityFollow : MonoBehaviour
{
    private EntityManager entityManager;
    private Entity targetEntity;

    private void Start()
    {
        entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
    }

    private void Update()
    {
        if (entityManager != null) {
            if (entityManager.Exists(targetEntity))
            {
                var entityTransform = entityManager.GetComponentData<LocalToWorld>(targetEntity);

                var deltaTime = Time.deltaTime;
                var smoothTime = 8.0f;

                float t = 1 - Mathf.Exp(-smoothTime * deltaTime);
                transform.position = math.lerp(transform.position, entityTransform.Position, t);
            } else {
                FindTaggedEntity();
            }
        }
    }

    private void FindTaggedEntity()
    {
        // Find the entity with the FollowTag
        entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
        EntityQuery query = entityManager.CreateEntityQuery(typeof(FollowTag), typeof(LocalToWorld));
       
        if (!query.IsEmpty) {
            var entities = query.ToEntityArray(Allocator.TempJob);

            if (entities.Length > 0)
            {
                targetEntity = entities[0]; // only follow first
                Debug.Log("following entity: " + targetEntity.Index);
            }
            entities.Dispose();
        } else {
            Debug.Log("no entity found to follow yet.");
        }
    }
}

This works, however I initially just had the Start() method call FindTaggedEntity() but this only worked in the Editor Player. When I created a build and ran it, I realized of course that the Entity did not exist yet when the MonoBehaviour Start() method is executed. I adapted my script to what is above, which works OK, however I see in the Player.log that it takes about 13 frames before the entity is “found”.

I would much rather get some direction on how to do this properly for when it gets detrimental to performance to blindly keep querying until an entity is found. (besides some rudimentary delay/polling methods)

I’ve seen some solutions in the forum, but nothing that made exactly sense for my use case. (I’m very new to ECS, so excuse the question if it is completely basic.)

A side question - I know the Editor Player is quite different than a build, but in this specific case, is it because the Editor already has the Entity created that a EntityQuery in the MonoBehaviour’s Start() method would pick it up?

Any feedback or direction would be very much appreciated.

The issue here is that subscenes stream in asynchronously, so your subscene isn’t loaded at runtime until after your GameObject is created. There’s a few different solutions for this. Simpler solutions involve changing your Start method to be an IEnumerator or forcing subscenes to load synchronously.

A more advanced solution would be to inject the GameObject into the ECS world and then use a linking system to connect things up on the ECS side. This is what I do with my GameObjectEntity feature. Relevant code is here: Latios-Framework/Transforms/Shared/GameObjectEntities at master · Dreaming381/Latios-Framework · GitHub

Many thanks for the information. That now makes perfect sense that the actual subscene is not loaded yet. I’ll take a look at your solution. Thank you!