Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

ECS Component Best Practices

Discussion in 'Entity Component System' started by nicolasgramlich, Feb 7, 2020.

  1. nicolasgramlich

    nicolasgramlich

    Joined:
    Sep 21, 2017
    Posts:
    231
    Hey everyone,

    I was wondering what general best practices or rule(s) of thumb(s) for designing ECS Components are.

    One fundamental I keep wondering about is how fine granular to make things, say should I have:
    Code (CSharp):
    1. public struct Unit : IComponentData {
    2.     public float moveSpeed;
    3.     public float rotateSpeed;
    4.     public float attackSpeed;
    5.     public float attackTime;
    6.     public Entity targetEntity;
    7. }
    or is it more common/efficient to have something like this:

    Code (CSharp):
    1. public struct Unit : IComponentData {}
    2. public struct MoveSpeed: IComponentData
    3.     public float value;
    4. }
    5. public struct RotateSpeed: IComponentData
    6.     public float value;
    7. }
    8. public struct AttackSpeed: IComponentData
    9.     public float value;
    10.     public float time;
    11. }
    12. public struct Target: IComponentData
    13.     public Entity targetEntity;
    14. }
    Does it all depend on how it's being used in the Systems? Say I have a MoveSystem, that operates on MoveSpeed and RotateSpeed, and an AttackSystem that operates on AttackSpeed, does it make more sense to keep the components separate, for memory layout efficiency?

    Thanks in advance!
     
  2. Radu392

    Radu392

    Joined:
    Jan 6, 2016
    Posts:
    210
    I have found that the second option is the best. The only time when the first option would be better is if you’re 100% sure that you won’t have a job that requires only a certain number of those fields instead of all. You can look around these forums, there’s a few threads around talking about this
     
    nicolasgramlich likes this.
  3. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    The 2nd way is more efficient since you get a contiguous memory of only the field you are interested in, therefore it is faster to iterate through. Note that when using Entities.ForEach, the number of components that you can use is upto 8. It can be a trouble if you need to bring in 7-8 `in` components each time if you are too granular. Also when you need to use ComponentDataFromEntity you may need to prepare more instance of them for more types, when you travel to other entity and need multiple things.

    In a 2D side scrolling game would you store float2 as position or float and float? Looks like float and float would be too much, but if you imagine you have a lot of use case of just X (cheap collision check with walls/stage boundary, or if it is a game about bouncing horizontally) or Y (if things in your game fall out a hole and something must happen a lot) then you may justify doing float and float.
     
  4. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,222
    If your job requires all those fields, it is actually better to keep them together as the memory prefetcher can get on a better rhythm. But that's typically not the case which is why most people suggest splitting the data up.
     
    BitPax, 5argon and nicolasgramlich like this.