I’m trying to build a spawn system. I have an authoring component that inherits from MonoBehaviour and implements IDeclareReferencedPrefabs, IConvertGameObjectToEntity. So far, so good. In my convert, I’m looping through the GameObject[ ] prefabs and creating and calling manager.AddComponentData on the new entities. The ComponentData I’m adding is fixed per-entity (i.e. prefab1 has e.g. data.acceleration = 1 and prefab2 has e.g. data.acceleration = 1.5 and those values are fixed/read only for every instance of an entity instantiated from that prefab):
public void Convert(Entity entity, EntityManager manager, GameObjectConversionSystem conversionSystem)
{
_vehiclePrefabCount = vehiclePrefabs.Length;
vehicleEntityPrefab = new Entity[vehiclePrefabs.Length];
for (int i = 0; i < _vehiclePrefabCount; i++)
{
var vehicleEntity = GameObjectConversionUtility.ConvertGameObjectHierarchy(vehiclePrefabs[i], World.Active);
manager.AddComponent(vehicleEntity, typeof(Prefab));
var data = vehiclePrefabs[i].GetComponent<VehicleDataAuthoring>();
if (data != null)
{
manager.AddComponentData(vehicleEntity, new VehicleDataComponent
{
acceleration = data.acceleration,
deceleration = data.deceleration
});
}
vehicleEntityPrefab[i] = vehicleEntity;
}
SpawnLocationComponent location = new SpawnLocationComponent
{
location = Location,
chance = spawnChance,
timeBetween = timeBetweenSpawns,
direction = SpawnDirection,
};
var entitiesBuffer = manager.AddBuffer<SpawnEntityComponent>(entity);
foreach (var vehicle in vehiclePrefabs)
{
entitiesBuffer.Add(new SpawnEntityComponent
{
entityPrefab = conversionSystem.GetPrimaryEntity(vehicle)
});
}
LaneIdentityComponent id = new LaneIdentityComponent
{
roadId = RoadId,
laneIndex = LaneIndex,
laneSubIndex = LaneSubIndex,
isLeft = IsLeft
};
var lanePoints = LanePointsComponentConverter(points);
var buffer = manager.AddBuffer<LanePointsComponent>(entity);
foreach (var point in lanePoints)
{
buffer.Add(point);
}
manager.AddComponentData(entity, new TimeSinceLastSpawnComponent { TimeSince = 0f });
manager.AddComponentData(entity, location);
manager.AddComponentData(entity, id);
manager.AddComponentData(entity, new LaneSpeedComponent { value = speed });
Debug.Log($"Converted spawner {gameObject.name}");
}
My job looks like this:
public class VehicleSpawnSystem : JobComponentSystem
{
BeginInitializationEntityCommandBufferSystem _entityCommandBufferSystem;
float deltaTime;
Unity.Mathematics.Random randomSource;
protected override void OnCreate()
{
// Cache in a field, so we don't have to create every frame
_entityCommandBufferSystem = World.GetOrCreateSystem<BeginInitializationEntityCommandBufferSystem>();
randomSource = new Unity.Mathematics.Random((uint)DateTime.Now.Millisecond);
}
private struct VehicleSpawnJob : IJobForEachWithEntity_EBCCCC<
SpawnEntityComponent,
TimeSinceLastSpawnComponent,
SpawnLocationComponent,
LaneIdentityComponent,
LaneSpeedComponent>
{
public EntityCommandBuffer.Concurrent CommandBuffer;
public Unity.Mathematics.Random RandomSource;
public float DeltaTime;
public void Execute(Entity entity,int index,DynamicBuffer<SpawnEntityComponent>spawnEntityComponentBuffer,refTimeSinceLastSpawnComponent timeSinceLastSpawnComponent, [ReadOnly] ref SpawnLocationComponent locationData,[ReadOnly] ref LaneIdentityComponent laneIdentityComponent,[ReadOnly] ref LaneSpeedComponent laneSpeedComponent)
{
timeSinceLastSpawnComponent.TimeSince += DeltaTime;
if (timeSinceLastSpawnComponent.TimeSince > locationData.timeBetween)
{
timeSinceLastSpawnComponent.TimeSince = 0f;
if (RandomSource.NextInt(0, 100) <= locationData.chance)
{
// select the prefab to spawn
var entityToSpawn = spawnEntityComponentBuffer[RandomSource.NextInt(0, spawnEntityComponentBuffer.Length - 1)];
// set location and orientation of spawned entity
var instance = CommandBuffer.Instantiate(index, entityToSpawn.entityPrefab);
CommandBuffer.SetComponent(index, instance, new Translation { Value = locationData.location });
Quaternion spawnDirection = Quaternion.identity;
spawnDirection.SetLookRotation(locationData.direction);
CommandBuffer.SetComponent(index, instance, new Rotation { Value = spawnDirection });
// add data to entity
CommandBuffer.AddComponent(index, instance, typeof(ERAutoTag));
CommandBuffer.AddComponent(index, instance, new LaneIdentityComponent
{
isLeft = laneIdentityComponent.isLeft,
laneIndex = laneIdentityComponent.laneIndex,
laneSubIndex = laneIdentityComponent.laneSubIndex,
roadId = laneIdentityComponent.roadId
});
CommandBuffer.AddComponent(index, instance, new LaneSpeedComponent { value = laneSpeedComponent.value });
CommandBuffer.AddComponent(index, instance, new CurrentPositionIndexComponent { value = 0 });
// CommandBuffer.AddComponent(index, instance, new VehicleDataComponent
// {
// acceleration = VehicleData[instance].acceleration,
// deceleration = VehicleData[instance].deceleration
// });
}
}
}
}
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
var job = new VehicleSpawnJob()
{
DeltaTime = Time.deltaTime,
RandomSource = randomSource,
CommandBuffer = _entityCommandBufferSystem.CreateCommandBuffer().ToConcurrent()
}.Schedule(this, inputDeps);
_entityCommandBufferSystem.AddJobHandleForProducer(job);
return job;
}
}
When I’ve attempted to use var x = GetComponentDataFromEntity<VehicleDataComponent>(true), when I attempt to add it to the entity in Execute, I get an error saying it is still deferred.
It doesn’t seem to me that it should be all that difficult to make a copy of an entity prefab and the data associated with it, but I have no clue where to start.