Search Unity

basic Datastructure question

Discussion in 'Entity Component System' started by MaskedMouse, Oct 1, 2019.

  1. MaskedMouse

    MaskedMouse

    Joined:
    Jul 8, 2014
    Posts:
    1,092
    When creating data components I'm kind of uncertain whether to split data into multiple pieces or combine them together as they're closely related to each other.

    i.e. a
    Health
    component. Should it contain 2 fields "Current" and "Maximum" or would you split the
    Health
    component up into two separate components
    CurrentHealth
    and
    MaximumHealth


    For instance entities that have health and age data. As they age their maximum health capacity goes down.
    When they reach their randomized maximum age, they die. When they take damage and reach 0 health they die.

    Hypothetically systems have to process 100.000's of entities (maybe more).
    A system that increases the current age over time.
    A system that decreases maximum health as they age.
    A system that tags entities with death that have reached their maximum age.
    A system that tags entities with death that have 0 health left.
    A system that decreases health when they're damaged.

    This is only a portion of the data that could be processed. I could add more data movement speed, hunger etc.

    I'm just wondering what a good approach is for these kinds of problems. Combine data or separate data.

    Logically to me from a MonoBehaviour perspective, I would combine data so that systems have to iterate less over the same entities. As counting the amount of systems required to process data it would mean they're iterating 5x over the same entities but doing different things with them.
    But combining data would mean that systems get packed data which could contain properties they actually don't care about. Like the system that increases the current age doesn't care about the maximum age.
    Is this a tradeoff to make?

    The same thing could be said about systems.
    A system that is increasing the current age and when they reach the maximum age tag them with a death component or 2 separate systems processing the same entities, where a system is increasing their age and the other system tags entities where current age >= maximum age.
    Separating logic or combining logic?

    What would be logical to pursue?
     
  2. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,267
    This is the typical thin vs fat component argument. Splitting components into thinner components can be more performant, but that's not worth it if it drastically slows down your development time. Especially if you are jumping into your first DOTS project, focus on making the game work however is comfortable to you. By default, if you are using Jobs and Burst, it should be outperforming Game Objects by a long shot, even if it is not the most optimal.
     
    MaskedMouse likes this.
  3. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,776
    Combine them. Will give you less boiler plates. If you will find ever need to split, then do it.
     
    MaskedMouse likes this.
  4. LazyGameDevZA

    LazyGameDevZA

    Joined:
    Nov 10, 2016
    Posts:
    143
    I'd echo what was posted above, but I'll take a gander at explaining why you'd want to perhaps split something like MaxHealth and CurrentHealth. If you have a HealthRegenSystem you could potentially have thousands of entities currently at max health, which would mean the system would have to consume that data even if an entity is at full health. If I know that say at any time only about 30% of my current entities aren't either dead or at max health I'd use the approach below.

    Components:
    • MaxHealth
    • CurrentHealth
    • Dead (tag)
    Systems:
    • HealthRegenSystem
    • DamageSystem
    The HealthRegenSystem would be responsible for, you guessed it, health regen. If an entity's current health reaches MaxHealth I'd simply remove the CurrentHealth component from the entity. If I want to know what an entity's current health is I simply have to retrieve the CurrentHealth component or look at the MaxHealth component if the entity doesn't have the Dead tag attached to it.

    The DamageSystem would when applying damage check if an entity has a CurrentHealth attached, if it doesn't it'll create it and apply the damage accordingly. If it has one attached it'll apply the damage to it and if the health drops below 0 add the dead tag.

    This way you're keeping the HealthRegenSystem from processing every single alive entity for every frame and only process the ones that aren't at max health. On a large number of entities that could be quite a performance gain, however this is a specific use-case where the design is specific to the current situation. If for instance you know that 95% of entity's won't be at max health or dead it might not be worth it to go through all the effort of removing CurrentHealth. It's going to be very specific to what you're trying to do and what the characteristics of your data is.
     
    MaskedMouse likes this.
  5. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,776
    As far I am concerned adding and removing component with data, causes moving to different chunks. So doing that, wouldn't be something to recommend. On other hand, adding and removing component tag, which has no data, is much more perform an option.

    However, I would only add max health to entity, if entities can have different max healths. But if I have all entities having same max health, or maybe just few, I would incorporate such check into a system, which calculates health. I.e. Resting system, which regenerates health, and use switch, to define type of entity, if more than one max health is involved. For example dog and human type entity, which have different max health values.

    If anyhow information about healthy entities is required, which needs only 100% health entities to be filtered, then you can use MaxHealthTagComponent or similar, with no data. Is much cheaper to add/remove than component with data.
     
  6. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    I agree with @DreamingImLatios that for your first dive into DOTS you shouldn't split them to make it easy for you.
    Down the line when you fully understand how DOTS works and know your data well enough you can choose whether or not if your use case makes sense to split the data.