Animator and CharacterController with ECS?

Hi,

I am trying to make the Animator and CharacterController work with ECS but unfortunately I was not able to do so. I am following the Prefab workflow which means my CharacterController component and Animator component are in the prefab that I am instantiating with a spawning system. I tried to use the AddComponentObject() to add the components to the entity but this does not work. Also PostUpdateCommands does not have a SetComponentObject method and since we are have to use ForEach I am stuck.

What should I do?

[RequiresEntityConversion]
public class PlayerProxy : MonoBehaviour, IDeclareReferencedPrefabs, IConvertGameObjectToEntity
{
    public GameObject Prefab;

    public void DeclareReferencedPrefabs(List<GameObject> gameObjects)
    {
        gameObjects.Add(Prefab);
    }

    public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    {
        var spawnerData = new PlayerSpawner
        {
            Prefab = conversionSystem.GetPrimaryEntity(Prefab)
        };
        dstManager.AddComponentData(entity, spawnerData);
        dstManager.AddComponentObject(entity, Prefab.GetComponent<CharacterController>());
    }
}
public class PlayerSpawnerSystem : ComponentSystem
{
    protected override void OnUpdate()
    {
        Entities.ForEach((Entity entity, ref PlayerSpawner spawner) => {
            Entity instance = PostUpdateCommands.Instantiate(spawner.Prefab);

            // ??? :(
            //CharacterController characterController = World.Active.EntityManager.GetComponentObject<CharacterController>(entity);
            //PostUpdateCommands.SetComponent(instance, characterController);

            PostUpdateCommands.DestroyEntity(entity);
        });
    }
}

Thank you

Here’s how I was able to tie hybrid components to entities:

  1. Add a GameObject to the scene with a SpawnableAnchoredPrefabs script and a ConvertToEntity in ConvertAndInjectGameObject mode. Add the prefab with the CharacterController to the array in SpawnableAnchoredPrefabs.

  2. Add a GameObject to the scene with a CreateAnchoredPrefabProxy and a ConvertToEntity in ConvertAndDestroy mode. Make sure PrefabIndex is 0 and CopyFromTransfrom is set to True.

  3. Enter play mode. You should have an entity with SpawnableAnchoredPrefabs and an entity with a CharacterController.

Here are my scripts:
My Implementation

[DisallowMultipleComponent, RequiresEntityConversion]
public class SpawnableAnchoredPrefabs : MonoBehaviour
{
    public GameObject[] Prefabs;
}

[DisallowMultipleComponent, RequiresEntityConversion]
public class CreateAnchoredPrefabProxy : MonoBehaviour, IConvertGameObjectToEntity
{
    public int PrefabIndex = 0;
    public bool CopyFromTransform = false;
    public bool CopyToTransform = false;
   
    public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    {
        dstManager.AddComponentData(entity, new CreateAnchoredPrefabIndex { Value = PrefabIndex });
        if (CopyFromTransform)
            dstManager.AddComponentData<CopyTransformFromGameObject>(entity, default);
        if (CopyToTransform)
            dstManager.AddComponentData<CopyTransformToGameObject>(entity, default);
    }
}

public struct CreateAnchoredPrefabIndex : IComponentData
{
    public int Value;
}

[UpdateInGroup(typeof(InitializationSystemGroup))]
public class AnchorPairingSystem : ComponentSystem
{
    private NativeList<Entity> anchorEntities;
    private NativeList<CreateAnchoredPrefabIndex> createAnchoredPrefabIndicies;

    protected override void OnCreate()
    {
        anchorEntities = new NativeList<Entity>(Allocator.Persistent);
        createAnchoredPrefabIndicies = new NativeList<CreateAnchoredPrefabIndex>(Allocator.Persistent);
        RequireForUpdate(GetEntityQuery(ComponentType.ReadWrite<SpawnableAnchoredPrefabs>()));
        RequireForUpdate(GetEntityQuery(ComponentType.ReadWrite<CreateAnchoredPrefabIndex>()));
    }

    protected override void OnDestroy()
    {
        anchorEntities.Dispose();
        createAnchoredPrefabIndicies.Dispose();
    }

    protected override void OnUpdate()
    {
        SpawnableAnchoredPrefabs singleton = null;
        Entities.ForEach((SpawnableAnchoredPrefabs spawnableAnchoredPrefabs) =>
        {
            singleton = spawnableAnchoredPrefabs;
        });
        Entities.ForEach((Entity entity, ref CreateAnchoredPrefabIndex createAnchoredPrefab) =>
        {
            anchorEntities.Add(entity);
            createAnchoredPrefabIndicies.Add(createAnchoredPrefab);
            PostUpdateCommands.RemoveComponent<CreateAnchoredPrefabIndex>(entity);
        });
        for (int i = 0; i < anchorEntities.Length; i++)
        {
            GameObject prefab = singleton.Prefabs[createAnchoredPrefabIndicies[i].Value];
            Component[] components = Object.Instantiate(prefab).GetComponents<Component>();
            foreach (var component in components)
            {
                EntityManager.AddComponentObject(anchorEntities[i], component);
            }
        }
        anchorEntities.Clear();
        createAnchoredPrefabIndicies.Clear();
    }
}
1 Like