Spawning Entities in job, but how to set position without creating a component?

Hi,
I’m spawning a number of entities in a CommandBuffer. I can add a component to set the position but is there a way to “Set Values” on components when an entity is spawned this way? For example, I want to set a Owner ID on a Projectile component to track who “Shot” created me. From what I can tell you can’t “SetComponent” when using a ParallelWritter though.

public class SpawnProjectileSystem : SystemBase
    {
        private EndSimulationEntityCommandBufferSystem barrier;
        protected override void OnCreate()
        {
            barrier = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
        }
    
        protected override void OnUpdate()
        {
            float deltaTime = Time.DeltaTime;
            float elapseTime = (float)Time.ElapsedTime;
            var cmdBuffer = barrier.CreateCommandBuffer().AsParallelWriter();
            Entities.ForEach((Entity entity, int entityInQueryIndex, ref ProjectileSpawner spawner, ref Rotation rotation, ref Translation translation) =>
            {
                if (spawner.Trigger)
                {
                    spawner.CooldownCurrent = elapseTime + spawner.m_Cooldown;
                
                    var projectile = cmdBuffer.Instantiate(entityInQueryIndex, spawner.m_ProjectilePrefab);
                    cmdBuffer.AddComponent(entityInQueryIndex, projectile, new Rotation { Value = rotation.Value });
//rather set position to the exisiting transform
                    cmdBuffer.AddComponent(entityInQueryIndex, projectile, new Translation { Value = translation.Value });
//Really want to "Set" values on the created entities "projectile" component here. e.g.
 // cmdBuffer.SetComponent(entityInQueryIndex, projectile, Projectile{ Owner = entity});  How can I do this?
                    spawner.Trigger = false;
                }
            }).WithName("SpawnProjectile").ScheduleParallel();
            barrier.AddJobHandleForProducer(Dependency);
        }
    }

Few things here.

Try to avoid adding components at runtime, as much as possible. Especially when comes to large number of entities.

For that, you either use archetype, or if you use authoring GO to Entity conversion, you can add required components at conversion time. Or create new additional utility entities prefabs.

Secondly, since you are using ECB inside job, you can use either add, or set component inside that job.

Other options are, to spawn primaryly number of entities, using either playback, or wait a frame until entities are created, then you can use setComponent withouth ECB.

You could also use EM, to spaw number of entities in advance.

Thanks for the reply!

Two follow up questions

  1. if I want to set the “Translation” components position value to be the same as the “gun that shot the projectile” with ECB would I do this?
Entities.ForEach((Entity entity, int entityInQueryIndex, ref ProjectileSpawner spawner, ref Rotation rotation, ref Translation translation) =>
  {
cmdBuffer.SetComponent(entityInQueryIndex, projectile, translation);
  1. When using the command buffer, How can I set values on exiting components on the entity I created? The entities I’m created are converted gameobjects (projectiles) Each has a “Projectile” component. Let’s say I want to set the “Entity IShotProjectile” to “Foo” like this:
Entities.ForEach((Entity entity, int entityInQueryIndex, ref ProjectileSpawner spawner, ref Rotation rotation, ref Translation translation) =>
            {
                if (spawner.Trigger)
                {
                    spawner.CooldownCurrent = elapseTime + spawner.m_Cooldown;
                    var projectile = cmdBuffer.Instantiate(entityInQueryIndex, spawner.m_ProjectilePrefab);

//unworking code.  how would I do this?
cmdBuffer.SetComponentValue(projectile, Projectile{IShotProjectile = entity}

Am I approching this wrong? Should I not be spawning my projectiles like this at all?
Thanks again.

Do exactly the same way, as in your first code example, line 3.

Then when you instantiate your projectile, you should set straight away set position and rotation, based on gun. Also you may need other properties, like velocity and dmg.

Thanks.

For those interested working code:

public class SpawnProjectileSystem : SystemBase
    {
        private EndSimulationEntityCommandBufferSystem barrier;
        protected override void OnCreate()
        {
            barrier = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
        }
       
        protected override void OnUpdate()
        {
            float deltaTime = Time.DeltaTime;
            float elapseTime = (float)Time.ElapsedTime;
            var cmdBuffer = barrier.CreateCommandBuffer().AsParallelWriter();
            Entities.ForEach((Entity entity, int entityInQueryIndex, ref ProjectileSpawner spawner, ref ProjectileSpawnerParams spawnParams) =>
            {
                if (spawner.Trigger)
                {
                    spawner.CooldownCurrent = elapseTime + spawner.m_Cooldown;
                    var projectile = cmdBuffer.Instantiate(entityInQueryIndex, spawner.m_ProjectilePrefab);

                    cmdBuffer.SetComponent(entityInQueryIndex, projectile, new Translation { Value = spawnParams.SpawnTranslation.Value });
                    cmdBuffer.SetComponent(entityInQueryIndex, projectile, new Rotation { Value = spawnParams.SpawnRotation.Value });
                    cmdBuffer.SetComponent(entityInQueryIndex, projectile, new ProjectileSpawnParams
                    { ProjectileOwner = spawnParams.ProjectileOwner,
                      SpawnTranslation = spawnParams.SpawnTranslation,
                      SpawnRotation = spawnParams.SpawnRotation,
                    });
                    spawner.Trigger = false;
                }
            }).WithName("SpawnProjectile").ScheduleParallel();
            barrier.AddJobHandleForProducer(Dependency);
        }
    }