DOTS Layer Data¶
Component¶
For all component, these should NOT be used as field: - Native Container: it has separated life span, not supporting query. And there are better alternatives. - Fixed Array: Dynamic Buffer is a better alternative. - Fixed Size String: string is not processed in any way in DOTS Layer. This field is often passed along to the Managed Layer. It should just stay in the Managed Layer instead.
Data Component¶
- Data that changes frequently
- Data with large value range
Tag Component¶
- Classification that changes seldomly.
- Low storage cost in chunk.
Classification that are processed differently
[WithAll(typeof(SoldierTag))]
internal partial struct SoldierVelocityJob : IJobEntity {
public float deltaTime;
private void Execute(in Velocity velocity, ref Position position) {
position = SoldierUtils.Move(position, velocity);
}
}
[WithAll(typeof(AirplaneTag))]
internal partial struct AirplaneVelocityJob : IJobEntity {
public float deltaTime;
private void Execute(in Velocity velocity, ref Position position) {
position = AirplaneUtils.Move(position, velocity);
}
}
Entity count is high enough to warrant a tag. If not, use a Data Component instead, so that these entities stay in the same chunk and benefit from batch processing.
[WithAll(typeof(SoldierTag))]
internal partial struct SoldierVelocityJob : IJobEntity {
public float deltaTime;
private void Execute(in Velocity velocity, ref Position position) {
if (velocity.Value > 10f) {
position = VeryFastSoldierUtils.Move(position, velocity);
} else {
position = SoldierUtils.Move(position, velocity);
}
}
}
Shared Component¶
- Low storage cost.
- Data that changes seldomly.
- Data with small value range. Each value should ideally bring in a proportionally large amount of entities.
Possible to query by value and process them differently
public enum Diplomacy { Ally, Neutral, Enemy } public struct DiplomacyStatus: ISharedComponentData { public enum Diplomacy Value; }
var neutrals = SystemAPI.QueryBuilder() .WithAll<Diplomacy>() .Build(); neutrals.SetSharedComponentFilter(new Diplomacy{Value = Diplomacy.Neutral}); // declare war on all neutral provinces EntityManager.SetSharedComponent(neutrals, new Diplomacy{Value = Diplomacy.Enemy}); // process all allies and enemies differently new AllyJob().ScheduleParallel(allies); new EnemyJob().ScheduleParallel(enemies);
Enableable Component¶
- Classification that changes frequently
- Enableable Component works by adding a bit-wise flags into the chunk. This flag is used to iterate a query inside a job. Changes happen during job execution is collected and write to this flag at the end of the job.
Classification that bound to a component value
public struct WillBeInvisibleTag: IEnableableComponent, IComponentData { } internal partial struct CullEntityJob : IJobEntity { public CameraInfo Camera; private void Execute(EnabledRefRW<WillBeInvisibleTag> invisible, in Bound2D bound) { invisible.ValueRW = CameraUtils.IsInsideBound(bound, Camera); } }
If we have too many classifications, using Enableable Component instead of Tag will avoid chunk fragmentation.public struct Health: IEnableableComponent, IComponentData { public int Value; } [WithChangeFilter(typeof(Health))] internal partial struct SetDeadJob : IJobEntity { private void Execute(EnabledRefRW<Health> isAlive, in Health health) { isAlive.ValueRW = health.Value > 0; } } var deadArmies = SystemAPI.QueryBuilder() .WithDisabled<Health>() .Build();