Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Question When EntityManager.Instantiate all existing Entities get reset to the original Position

Discussion in 'Entity Component System' started by DerDerErIst, Jul 28, 2023.

  1. DerDerErIst

    DerDerErIst

    Joined:
    Nov 26, 2016
    Posts:
    22
    Hey Guys,

    im not sure what my problem is exactly or if i understand it fully, maybe someone can tell me more about.

    I try to create a Pickup System so when an Enemy is dying it leaves certain Pickups behind.

    Here is how im doing it: I have a Singleton MonoBehaviour which keep a reference to the EntityManager i call now from my Enemy Health Script


    PickupManager.SpawnPickup(this.transform.position,1);


    Or also from other sources it could be called.

    to execute the following Code:
    Code (CSharp):
    1.     public static void SpawnPickup(Vector3 pos, int id)
    2.     {
    3.         //Debug.Log("Spawn Pickup");
    4.         instance.entityManager.SetComponentData(
    5.             instance.entityManager.CreateEntity(typeof(PickupSpawnComponent)),
    6.             new PickupSpawnComponent
    7.             {
    8.                PickupSpawnID = id,
    9.                SpawnPosition = new float3(pos.x,0,pos.z),
    10.                CollectionRadius = 10,
    11.             });
    12.     }
    I Create a PickupSpawnComponent : IComponentData which basicially holds the information to spawn the pickup in Unity Dots.

    Now ive Created a PickupSpawnSystem : SystemBase i've tried to write that System on multiple ways but whatever i try i get the same Behaviour, after attracting the Pickups when i generate new ones the old ones reset their transform to their spawnposition.

    Version 1:
    Code (CSharp):
    1.         var configEntity = SystemAPI.GetSingletonEntity<PickupConfig>();
    2.         var pickupConfig = SystemAPI.GetComponent<PickupConfig>(configEntity);
    3.  
    4.  
    5.         Entities.WithAll<PickupSpawnComponent>().WithStructuralChanges().ForEach((ref PickupSpawnComponent pickupSpawnComponent) =>
    6.         {
    7.             if (!pickupSpawnComponent.IsInstantiated)
    8.             {
    9.                 pickupSpawnComponent.IsInstantiated = true;
    10.  
    11.                 Entity pickupObject;
    12.  
    13.                 switch (pickupSpawnComponent.PickupSpawnID)
    14.                 {
    15.                     case 1:
    16.                         pickupObject = EntityManager.Instantiate(pickupConfig.Prefab_ExperienceStone);
    17.                         break;
    18.                     case 2:
    19.                         pickupObject = EntityManager.Instantiate(pickupConfig.Prefab_KaijuBounty);
    20.                         break;
    21.                     case 3:
    22.                         pickupObject = EntityManager.Instantiate(pickupConfig.Prefab_Health);
    23.                         break;
    24.                     case 4:
    25.                         pickupObject = EntityManager.Instantiate(pickupConfig.Prefab_Battery);
    26.                         break;
    27.                     case 5:
    28.                         pickupObject = EntityManager.Instantiate(pickupConfig.Prefab_Magnet);
    29.                         break;
    30.                     case 6:
    31.                         pickupObject = EntityManager.Instantiate(pickupConfig.Prefab_SpeedBoost);
    32.                         break;
    33.                     case 7:
    34.                         pickupObject = EntityManager.Instantiate(pickupConfig.Prefab_EXPBoost);
    35.                         break;
    36.                     case 0:
    37.                     default:
    38.                         pickupObject = EntityManager.Instantiate(pickupConfig.Prefab_ExperienceStone);
    39.                         break;
    40.                 }
    41.  
    42.                 EntityManager.SetComponentData(pickupObject, new PickupComponent
    43.                 {
    44.                     PickupID = pickupSpawnComponent.PickupSpawnID,
    45.                     CollectionRadius = 2,
    46.                     AttractRadius = 10,
    47.                     IsCollected = false,
    48.                     IsTriggered = false,
    49.                 });
    50.  
    51.  
    52.                 EntityManager.SetComponentData(pickupObject, new LocalTransform
    53.                 {
    54.                     Position = pickupSpawnComponent.SpawnPosition,
    55.                     Rotation = quaternion.identity,
    56.                     Scale = 1
    57.                 });
    58.             }
    59.         }).Run();
    Version 2:
    Code (CSharp):
    1.         foreach (var pickup in
    2.               SystemAPI.Query<RefRW<PickupSpawnComponent>>()
    3.                   .WithAll<PickupSpawnComponent>())
    4.         {
    5.             if (pickup.ValueRO.IsInstantiated)
    6.                 return;
    7.  
    8.             pickup.ValueRW.IsInstantiated = true;
    9.  
    10.             Entity pickupEntity;
    11.             var pickupConfig = SystemAPI.GetSingleton<PickupConfig>();
    12.  
    13.             switch (pickup.ValueRO.PickupSpawnID)
    14.             {
    15.                 case 1:
    16.                     pickupEntity = EntityManager.Instantiate(pickupConfig.Prefab_ExperienceStone);
    17.                     break;
    18.                 case 2:
    19.                     pickupEntity = EntityManager.Instantiate(pickupConfig.Prefab_KaijuBounty);
    20.                     break;
    21.                 case 3:
    22.                     pickupEntity = EntityManager.Instantiate(pickupConfig.Prefab_Health);
    23.                     break;
    24.                 case 4:
    25.                     pickupEntity = EntityManager.Instantiate(pickupConfig.Prefab_Battery);
    26.                     break;
    27.                 case 5:
    28.                     pickupEntity = EntityManager.Instantiate(pickupConfig.Prefab_Magnet);
    29.                     break;
    30.                 case 6:
    31.                     pickupEntity = EntityManager.Instantiate(pickupConfig.Prefab_SpeedBoost);
    32.                     break;
    33.                 case 7:
    34.                     pickupEntity = EntityManager.Instantiate(pickupConfig.Prefab_EXPBoost);
    35.                     break;
    36.                 case 0:
    37.                 default:
    38.                     pickupEntity = EntityManager.Instantiate(pickupConfig.Prefab_ExperienceStone);
    39.                     break;
    40.             }
    41.  
    42.             EntityManager.SetComponentData(pickupEntity, new PickupComponent
    43.             {
    44.                 PickupID = pickup.ValueRO.PickupSpawnID,
    45.                 CollectionRadius = 2,
    46.                 AttractRadius = 10,
    47.                 IsCollected = false,
    48.                 IsTriggered = false,
    49.             });
    50.  
    51.  
    52.             EntityManager.SetComponentData(pickupEntity, new LocalTransform
    53.             {
    54.                 Position = pickup.ValueRO.SpawnPosition,
    55.                 Rotation = quaternion.identity,
    56.                 Scale = 1
    57.             });
    58.         }
    Once the PickupSpawnComponent is Instantiated i have a Job Running that Destroys the Entity
    ISystem to Create the Job
    Code (CSharp):
    1. [BurstCompile]
    2. public partial struct PickupSpawnIDestroySystem : ISystem
    3. {
    4.     [BurstCompile]
    5.     public void OnCreate(ref SystemState state)
    6.     {
    7.         state.RequireForUpdate<PickupSpawnComponent>();
    8.     }
    9.  
    10.     [BurstCompile]
    11.     public void OnUpdate(ref SystemState state)
    12.     {
    13.         var commandBuffer = SystemAPI.GetSingleton<EndSimulationEntityCommandBufferSystem.Singleton>();
    14.  
    15.         var pickupSpawnDestroyJob = new PickupSpawnIDestroyJob
    16.         {
    17.             CommandBuffer = commandBuffer.CreateCommandBuffer(state.WorldUnmanaged),
    18.         };
    19.  
    20.         pickupSpawnDestroyJob.Schedule();
    21.     }
    22. }
    The Job:

    Code (CSharp):
    1. [BurstCompile]
    2. public partial struct PickupSpawnIDestroyJob : IJobEntity
    3. {
    4.     public EntityCommandBuffer CommandBuffer;
    5.  
    6.     [BurstCompile]
    7.     void Execute(Entity entity, ref PickupSpawnComponent pickup)
    8.     {
    9.         if (pickup.IsInstantiated)
    10.         {
    11.             CommandBuffer.RemoveComponent<PickupSpawnComponent>(entity);
    12.             CommandBuffer.DestroyEntity(entity);
    13.         }
    14.     }
    15. }
    If the pickup.IsInstantiated id like to remove the PickSpawnComponent from the System so it won't get used anymore as it served it purpose.

    Now meanwhile my Player roams around and comes in Range of those Pickups, I have a System that constantly writes the PlayerPosition to PlayerPositionComponent so i can check with Unity Dots where the Player is even the Player is a regular MonoBehaviour GameObject.

    My PickupAttractSystem handles this now:
    Code (CSharp):
    1. [BurstCompile]
    2. public partial class PickupAttractSystem : SystemBase
    3. {
    4.     [BurstCompile]
    5.     protected override void OnCreate()
    6.     {
    7.         RequireForUpdate<PlayerPositionComponent>();
    8.         RequireForUpdate<PickupComponent>();
    9.     }
    10.  
    11.     [BurstCompile]
    12.     protected override void OnUpdate()
    13.     {
    14.         var player = SystemAPI.GetSingletonEntity<PlayerPositionComponent>();
    15.         var playerPos = SystemAPI.GetComponent<PlayerPositionComponent>(player);
    16.         var deltaTime = SystemAPI.Time.DeltaTime;
    17.  
    18.         //Attract Pickup
    19.         Entities.ForEach((ref LocalToWorld transform, ref PickupComponent pickupComponent) =>
    20.         {
    21.             if (pickupComponent.IsCollected)
    22.             {
    23.                 return;
    24.             }
    25.  
    26.             float distanceToPlayer = math.length(playerPos.PositionValue - transform.Position);
    27.  
    28.             if (!pickupComponent.IsTriggered)
    29.             {
    30.                 if (distanceToPlayer <= pickupComponent.AttractRadius)
    31.                     pickupComponent.IsTriggered = true;
    32.  
    33.                 return;
    34.             }
    35.  
    36.             float3 directionToPlayer = math.normalize(playerPos.PositionValue - transform.Position);
    37.             float3 movement = deltaTime * directionToPlayer * 15;
    38.  
    39.             transform = new LocalToWorld
    40.             {
    41.                 Value = float4x4.TRS(
    42.                     transform.Position + movement,
    43.                     transform.Rotation,
    44.                     1)
    45.             };
    46.         }).ScheduleParallel();
    47.     }
    48. }
    It works fine, besides whenever i kill an Enemy and Generate new Pickups, all existing Pickups get transfered back to their origin Position. As you can see here in the Video.




    What im doing wrong? I have no Clue why this happens, i've got another project where i almost use the identical System, the only difference is that in this System there is only 1 Pickup instead of 7 but i instantiate them on the same way.



    As you can see in this Project the Pickup Objects not get transfered back to their origin position and keeps flying towards the player.

    i hope i could show what im doing and trying to achieve. If someone could maybe explain me whats happening?

    Thanks for help