Again, the nature of DOTS changing so much leads me to have to ask, so if I’m being stupid, my apologies.
I’m making a traffic system for a VR game
There are hover cars at multiple levels.
Waypoints are provided by the road system (Easy Roads 3D, HIGHLY recommend) which are baked into a series of entity Lanes. (Lane’s waypoints, dynamic array of connected other Lanes) The lane waypoint data is ONLY at the street level. (no need to have an entity for each series of waypoints at each Height)
Autos are a collection of GameObject prefabs, where the actual Auto is a child object. This is important, so there doesn’t have to be waypoints at each Height, only the Auto’s height is changed.
Each BASE of the Auto’s has a Speed entity and that is used, along with it’s Local Transform, in a System to move the Autos to the next waypoint. All fine and good.
Thing is, I need to adjust the child entity (the actual mesh) My thought was it too would have a Speed entity and the same Movement system would affect that component’s height/y But finding a way to access the child entity is not working out.
Entity spawnedEntity = EntityManager.Instantiate(trafficSpawnerComponent.ElementAt(index).prefab); //the prefab is the Game Object, converted via a Bake
if (SystemAPI.HasBuffer<Child>(spawnedEntity))
{
Debug.Log("found child");
}
This doesn’t work as there is no “Child” entity, so obviously I am missing something. There are several other methods that are supposed to get the child, like: var childFromEntity = GetBufferFromEntity(true); But that’s depreciated and the new method; GetBufferLookup is also not getting me there.
So in an effort to make my day easier, I thought I’d ask you, how do I access a child entity? Should I “just” have a different Tag on the child and access them that way?
Hi there! First off. Don’t apologize for trying to learn.
May I ask if you’ve already checked the Entities Hierarchy if there’s actually Parent component in your root entity? You can also use the Components inspector and see if there are children. Just to make sure the Parent-Child relationships/components has been set up properly.
If not, you’d have to manually add the Parent component and wait for the ParentsSystem to run to resolve the children. Last I checked that’s still the way to do it.
From there, you should be able to get the Child buffer from the Parent entity.
I only apologize in case I’m being overly stupid, which does happen. Ive been a dev for decades and I know when i don’t know something, that it may be MY fault.
This shows the same layout as the Game Object. In that image the Parent object, “HBC Auto (1)” is highlighted, no “Parent” tag. The child object, “LightCorvetteHullGray” does not have a “Child” tag. This is why I am asking if I need to author a tag “Child” to said child Game Object. Is it that simple? Is there a better method?
Thanks very much for the response, have a wonderful weekend
I was looking at the bottom of the Inspector AND I was expecting the Child tag to be on the child, (see told you it could be my fault)
So, that said, the following code returns nothing
Entity spawnedEntity = EntityManager.Instantiate(trafficSpawnerComponent.ElementAt(index).prefab);
if (EntityManager.HasComponent<Child>(spawnedEntity))
{
Debug.Log("found a child");
}
Which, as you can see from the new image linked above the Parent does have the “Child” tag, and it is correctly referencing the object/entity. So why doesn’t the above code run? What dumbass thing am I missing?
Ah, there you go. In that case, use EntityManager.GetBuffer(parentEntity) because Child component is an IBufferElementData. That’ll return a DynamicBuffer that you can then use to access the children entities.
[EDIT]
If you want to check for existence, use the HasBuffer() method.
[/EDIT]
if (EntityManager.HasBuffer<Child>(spawnedEntity))
{
Debug.Log("found it");
}
But nope, nothing found. Within the Entities Hierarchy the are show then with the correct info.
So my next thought is the way I am creating these, is this the problem? I am creating this in a SystemBase and the values are being set via an Entity Command Buffer. JUST IN CASE this is causing the issue on the “delay” between when Entity Manager is told to create an entity and when all the values, children are available to access? Or… I don’t know.
private bool spawnAutos = true;
private const int MIN_LANE_INDEX = 8;
private const int MAX_LANE_INDEX = 16;
private const float speedBase = 24.0f;
private const float rotationSpeedOffset = 0.4f;
protected override void OnUpdate()
{
if (spawnAutos)
{
SpawnAutos();
}
else
{
StopSystem();
}
}
private void SpawnAutos()
{
RefRW<RandomComponent> randomComponent = SystemAPI.GetSingletonRW<RandomComponent>();
DynamicBuffer<TrafficSpawnerComponent> trafficSpawnerComponent = SystemAPI.GetSingletonBuffer<TrafficSpawnerComponent>();
EntityCommandBuffer entityCommandBuffer = SystemAPI.GetSingleton<BeginSimulationEntityCommandBufferSystem.Singleton>().CreateCommandBuffer(World.Unmanaged);
foreach (var (lanePoints, entity) in SystemAPI.Query<DynamicBuffer<LanePoints>>().WithEntityAccess())
{
//To give a little variance for where the autos start and end on each lane, more attempts to a random enviroment
int start = randomComponent.ValueRW.random.NextInt(MIN_LANE_INDEX, MAX_LANE_INDEX);
int end = randomComponent.ValueRW.random.NextInt(MIN_LANE_INDEX, MAX_LANE_INDEX);
for (int lanePointIndex = start; lanePointIndex < (lanePoints.Length - end); lanePointIndex++)
{
float speed = SpeedCalculation(10.0f);
int index = randomComponent.ValueRW.random.NextInt(0, trafficSpawnerComponent.Length);
Entity spawnedEntity = EntityManager.Instantiate(trafficSpawnerComponent.ElementAt(index).prefab);
if (EntityManager.HasBuffer<Child>(spawnedEntity))
{
Debug.Log("one more time");
}
entityCommandBuffer.SetComponent(spawnedEntity, LocalTransform.FromPosition(lanePoints[lanePointIndex].point));
entityCommandBuffer.SetComponent(spawnedEntity, new Speed { value = speed });
entityCommandBuffer.SetComponent(spawnedEntity, new RotationSpeed { value = (speed * rotationSpeedOffset) });
entityCommandBuffer.SetComponent(spawnedEntity, new WaypointIndex { value = lanePointIndex });
entityCommandBuffer.SetComponent(spawnedEntity, new LaneEntity { value = entity });
lanePointIndex += randomComponent.ValueRW.random.NextInt(MIN_LANE_INDEX, MAX_LANE_INDEX);
}
}
spawnAutos = false;
}
EDIT: Found GetBufferLookup: var childrenFromEntity = GetBufferLookup();
Added it and it is returning values, but at the moment I am trying to research more about this method. Notice how it has no ref to the specific spawnedEntity? How does it know?
Entity spawnedEntity = EntityManager.Instantiate(trafficSpawnerComponent.ElementAt(index).prefab);
var buffer = EntityManager.GetBuffer<Child>(spawnedEntity); //This fails
ArgumentException: A component with type:Unity.Transforms.Child [Buffer] has not been added to the entity. Entities Journaling may be able to help determine more information. Please enable Entities Journaling for a more helpful error message.
This SEEMS to say that the entity isn’t completed when the “spawnedEntity” is created… or, more likely, I’m still doing something wrong.
The GetBufferLookup, while it returns some values, a BufferLookup, which I am currently attempting to understand… and this might be the wrong path too…
Child is a cleanup component [buffer]. Some system in TransformSystemGroup is responsible for setting up the buffer, it will not be immediately available after instantiation because of that. Besides that, the LinkedEntityGroup buffer on the instantiated entity will already be present at instantiation time and references all entities in the hierarchy. You could equivalently determine if the entity has any children by iterating over the entity references in LinkedEntityGroup elements and checking if they have a Parent component that then points to the root entity.