General purpose components
ComponentData in Unity (also known as a component in standard ECS terms) is a struct that contains only the instance data for an entity. ComponentData should not contain methods beyond utility functions for accessing the data in the struct. All game logic and behaviour should be implemented in systems. To put this in terms of the old Unity system, this is somewhat similar to an old Component class, but one that only contains variables.
The Unity ECS API provides an interface called IComponentData that you can implement in your code to declare a general-purpose component type.
Traditional Unity components (including
MonoBehaviour) are object-oriented classes which contain data and methods for behavior.
IComponentData is a pure ECS-style component, meaning that it defines no behavior, only data.
IComponentData should be implemented as struct rather than a class, meaning that it is copied by value instead of by reference by default. You will usually need to use the following pattern to modify data:
var transform = group.transform[index]; // Read transform.heading = playerInput.move; // Modify transform.position += deltaTime * playerInput.move * settings.playerMoveSpeed; group.transform[index] = transform; // Write
IComponentData structs may not contain references to managed objects. Since
ComponentData lives in simple non-garbage-collected tracked chunk memory allowing for many performance advantages.
To help porting existing code over to ECS in a piecemeal fashion, interoperating with managed data not suitable in
ISharedComponentData or when first prototyping what your data layout will look like, it may be helpful to use a managed
IComponentData (that is,
IComponentData declared using a
class rather than
struct). These components are used the same way as value type
IComponentData however internally are handled in a much different (and slower) way. Users who do not need managed component support should define
UNITY_DISABLE_MANAGED_COMPONENTS in their Project Settings -> Player -> Scripting Define Symbols to prevent accidental usage.
By nature of being a managed type, managed
IComponentData have the following performance drawbacks compared to valuetype
- Cannot be used with the Burst Compiler
- Cannot be used in Job structs
- Cannot use chunk memory
- Require garbage collection
Users should try to limit the number of managed components, preferring blittable types as much as possible.
IComponentData must implement the
IEquatable<T> interface and override for
Object.GetHashCode(). As well, for serialization purposes, managed components must be default constructible.
Since managed components are by their nature not blittable, these components are stored in a managed C# array known indirectly by each
ArchetypeChunk and are indexed to by
You must set the value of the component on the main thread using either the
EntityCommandBuffer. Being a reference type, you may change value of the component without moving entities across chunks
unlike ISharedComponentData and thus does not create a sync-point. However while logically stored separate from value-type components,
managed components still contribute to an entity's
EntityArchetype definition. As such, adding a new managed component to an entity will still cause a new archetype to be created (if a matching archetype doesn't exist already) and the entity to be moved to a new chunk.
See file: /Packages/com.unity.entities/Unity.Entities/IComponentData.cs.