Search Unity

Should I always use entities as ids or should I have my own sub-ids?

Discussion in 'Entity Component System' started by frankfringe, Apr 17, 2019.

  1. frankfringe

    frankfringe

    Joined:
    Feb 9, 2019
    Posts:
    105
    Hi,

    I am writing a simulation-like game and I often have problems similar to this:

    I have Humans and Ressources. Each human has a composition of which Ressources he needs, e.g.

    Human 1 needs 30% of Ressource 1, 50% of Ressource 2 and 20% of Ressource 3 (the shares always sum up to 100%).

    Now there are two ways I could do this. Human has a dynamic buffer component ressource share

    Code (CSharp):
    1. sturct RessourceShare : IComponentData {
    2.    public float share;
    3. }
    and RessourceShareBuffer[n] is the share of the nth ressource, i.e. I use the buffer index as ressource id. I then of course need to have some way to map the index to a ressource data in some other way. (Maybe just a static public object or an Entity)

    Or I have
    Code (CSharp):
    1. struct RessourceShare : IComponentData {
    2.     public Entity Ressource;
    3.     public float share;
    4. }
    i.e. I explicitely save the Ressource Entity.

    Are there any considerations I should make when deciding if I use the buffer index as ressource id or explicitely save the Entities?

    Many thanks
     
    Last edited: Apr 17, 2019
  2. NoDumbQuestion

    NoDumbQuestion

    Joined:
    Nov 10, 2017
    Posts:
    186
    Dynamic buffer is kind of like list. You dont have to use dynamic buffer index as index(ID) of your resources. Just add ResourceId to your ComponentData.
    Code (CSharp):
    1.     struct RessourceShare : IComponentData {
    2.         public int RessourceId;
    3.         public float share;
    4.     }
    5.  
    when iterate through dynamic buffer. Check if total share > 100 then you know your other system is not working correcty
     
  3. frankfringe

    frankfringe

    Joined:
    Feb 9, 2019
    Posts:
    105
    My question was more if I should do

    (A)
    Code (CSharp):
    1. struct RessourceShare : IComponentData {
    2.    public float share;
    3. }
    4.  
    5.  
    and have another entity or public array which gives me index -> Ressource Entity

    or

    (B)
    Code (CSharp):
    1. public struct RessourceShare : IComponentData {
    2.     public Entity Ressource;
    3.     public float share;
    4. }
    which means saving the ressource Entities in every Humans (allthough they are all the same) and not using the array order.


    Your approach seems not to improve on these two versions from my perspective. Is there anything I am overlooking?
     
  4. NoDumbQuestion

    NoDumbQuestion

    Joined:
    Nov 10, 2017
    Posts:
    186
    You mean resource as real entity? not from static dictionary list ID resource type.
    Then B is better.
    Other option would be resource entity have SharedComponent that point to HumanEntity. That way all resources always belong to someone or something. it would much easier to query. Not Human EntityComponentBuffer contain resources
     
    frankfringe likes this.
  5. frankfringe

    frankfringe

    Joined:
    Feb 9, 2019
    Posts:
    105
    Thank you for your answers. I now overthought the whole thing and I am not sure anymore. I have many Humans (a few thousand) and probably a few hundred different Ressources. The Ressources are things like "Gold", "Wood", "Chairs", etc. and are basically read-only.

    Which is better:
    (1) Put this kind of information in a static class
    Code (CSharp):
    1. public static class Ressources {
    2.     public Goods[] ressourceInformation;
    3.     or
    4.     public NativeArray<Goods> ressourceInformation;
    5.     .....
    6. }
    and then have my own `GoodId` which is just the index of the good in the `goodInformation`.

    (2) Let the `ressourceInformation` be Entities instead.

    The public static class seems in some sense easier to me, as I can order the ids (I can test `good_id1 < good_id2`) which makes some things like inventory much faster. On the other side I maybe lose some ECS performance (?)
     
  6. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Enums are good for this kind of thing. So an Item/Resource struct for example with a Sku enum.

    Enums play nice with unity editor scripts also as you can make dropdowns from them.

    constant/static readonly integers are another option but IMO not as flexible or as easy to reason about in some context's.

    Once you get into thousands of things you might consider code generation. Ie taking a bunch of string names and generating enums from them. Values should be stable over time, so whether you use enums or say constants, hundreds to thousands becomes difficult to manage manually. But conversion of string to int values can easily have logic that keeps the values the same.

    This is what our item database looks like in a scriptable object with a custom editor, all of the dropdowns are enums we use them extensively. Our items in the base form are classes because we have multiple concerns with reasons for that so we actually have to maintain proxy structs for DOTS, but structs work just as well.

    upload_2019-4-17_12-49-9.png
     
    frankfringe likes this.
  7. frankfringe

    frankfringe

    Joined:
    Feb 9, 2019
    Posts:
    105
    Hi Snacktime, thank you very much for the answer. How do you save the items ingame? And how do you keep track of which player has which items?

    Basically I need to maintain a many-to-many relationship in the ECS - Which player has how much of which ressource (Gold, Stone, Wood but also Chairs, Houses, Cars, ....).

    I am thinking about if I should
    (1) have a RessourceId which is an integer and a "Data class" that gives me ressource id -> ressource information or
    (2) if I should just save the ressources as entities and and use the Entity id.
    The first approach makes some things easier (I can sort the items with their id and make queries faster). The second one is more "in the ECS".
     
  8. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    How you handle a lot of this is going to be very game specific. There is no general best way it's going to depend on all the details of what you are doing with items exactly.

    The most important thing is that DOTS doesn't change the fundamentals. How we handle DOTS is really no different then how I handled creating optimized views of data in other industries. The basics are the same. For multiplayer you are going to be storing data in a database. That is your authoritative, normalized view of the data. You then 'denormalize' it for other uses like DOTS.

    There are variations on that like using a specialized database to start with, but you get the idea.

    So all of our data in DOTS that can persist, is feature specific views of the larger data structured for what works best in DOTS.
     
    frankfringe likes this.