If I creat some entities sequentially and then use an EntityQuery.ToComponentDataArray to create a native array of some component, is there a guaratee that the components in the native array will have the same sequence that the entities were created in? This seems to be the case based on some tests, but is it something that I can rely on?
Depending on the other structural changes that happen in your game, I doubt the order will be maintained. For example :
- Create entities A, B, C and D
- Change the archetype of B by adding a new component to it
- ToComponentDataArray will probably give you ACDB or BACD, not ABCD as you expect.
Even if you do not make archetype changes, I wouldn’t be surprised if the order can vary if your entities exist across multiple chunks. Unity generally prioritizes memory order, not creation order.
My recommendation: If the documentation does not state that the order is consistent with creation order, assume it isn’t.
Thank you! Makes sense not use rely on something not explicitly documented.
But I do need to get an ordered list of a component. One way I thought was to add an Index component that will contain the sequence number:
public struct Index : IComponentData {public int Value;}
Assume I also have LocalTransform component on these entities… Now, how can I get a native array of these LocalTransforms ordered by the Index component value?
I did something like this. which works, but not ideal
Put both LocalTransform and Index in a single component. And create a comparer using Index.
public struct IndexedLocalTransform : IComponentData
{
public LocalTransform LocalTransform;
public int Index;
}
public struct IndexComparer : IComparer<IndexedLocalTransform>
{
public int Compare(IndexedLocalTransform x, IndexedLocalTransform y) {
return x.Index.CompareTo(y.Index);
}
}
Then build a native array using ToComponentDataArray. And then use SortJob to sort by the Index
var query = new EntityQueryBuilder(Allocator.TempJob)
.WithAll<IndexedLocalTransform>()
.Build(ref state);
var data = query.ToComponentDataArray<IndexedLocalTransform>(Allocator.TempJob);
data.SortJob(new IndexComparer());
That works. If you don’t want the IndexedLocalTransform component, you could instead do this:
public struct IndexedLocalTransform : IComparable<IndexedLocalTransform>
{
public LocalTransform LocalTransform;
public int Index;
public int CompareTo(IndexedLocalTransform other) => Index.CompareTo(other.Index);
}
var query = new EntityQueryBuilder(Allocator.TempJob)
.WithAll<LocalTransform, Index>()
.Build(ref state);
var transforms = query.ToComponentDataArray<LocalTransform>(Allocator.TempJob);
var indices = query.ToComponentDataArray<Index>(Allocator.TempJob);
var indexedTransforms = new NativeArray<IndexedLocalTransform>(transforms.Length, Allocator.TempJob);
for (int i = 0; i < indexedTransforms.Length; i++)
{
indexedTransforms[i] = new() { Index = indices[i].Value, LocalTransform = transforms[i] };
}
indexedTransforms.SortJob();