Search Unity

  1. Unity 2018.3 is now released.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. We've updated our Terms of Service. Please read our blog post from Unity CTO and Co-Founder Joachim Ante here
    Dismiss Notice
  4. Want to provide direct feedback to the Unity team? Join the Unity Advisory Panel.
    Dismiss Notice
  5. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice

Temporary Working Variables

Discussion in 'Entity Component System and C# Job system' started by jooleanlogic, May 16, 2018.

  1. jooleanlogic


    Mar 1, 2018
    Picture the following scenario. You have a bunch of ships (entities) each with a number of stacked fuel containers (entities) on board. Each ship has one fuel container that is the active one. When that container is empty, we need to select the next highest (spatial) container on the ship. In OO, the update loop looks like this.

    Code (CSharp):
    1. for each Ship
    2.     // Initialisation - These are the temporary working variables
    3.     FuelContainer highestContainer = null;
    4.     float maxY = 0;
    6.     // Processing
    7.     for each container on ship
    8.         if(container.hasFuel() && container.position.y > maxY){
    9.             maxY = container.position.y;
    10.             highestContainer = container;
    11.         }
    12.     }
    14.     // Post processing
    15.     if(highestContainer != null)
    16.         ship.activeContainer = highestContainer
    17. }
    In this scenario, highestContainer and maxY are temporary working variables. This works because we can iterate containers grouped by ship.
    In ECS where you're iterating on unsorted containers, where would you store such temporary variables that need to hold state related to individual ships?
    In a component on the parent Ship Entity like code below? Or perhaps in a HashMap where the Ship Entity would be the key and TempVars as the value? Is there another kind of ecs pattern for this?

    Code (CSharp):
    1. // Initialise Temp Vars
    2. for each Ship Entity
    3.     ship.TempVarsComponent.maxY = 0;
    4.     ship.TempVarsComponent.highestContainerEntity = Entity.Null;
    5. }
    7. //Processing
    8. ComponentDataFromEntity<TempVarsComponent> shipTempVars;
    9. for each FuelContainer Entity
    10.     tempVars = shipTempVars[fuelContainer.parentEntity]; // Get temp vars from parent ship
    12.     if(container.hasFuel() && container.position.y > tempVars.maxY){
    13.         tempVars.maxY = container.position.y;
    14.         tempVars.highestContainerEntity = container;
    15.     }
    16.     shipTempVars[fuelContainer.parentEntity] = tempVars;
    17. }
    19. // Post processing
    20. for each Ship Entity
    21.     if(ship.tempVarsComponent.highestContainerEntity != Entity.Null)
    22.         ship.addComponent<ActiveContainerCompnent>(ship, ship.tempVarsComponent.highestContainerEntity);
    23. }
    This works well but it doesn't feel right storing such data in Components.
  2. Joachim_Ante


    Unity Technologies

    Mar 16, 2005
    That seems perfectly fine.

    We will add support for containers on ComponentData but organizing it the other way around like you are doing is more efficient, it avoids lots of small memory allocations for each array.
  3. avvie


    Jan 26, 2014
    Any possibility of the full cs file for this or a github project? I still get majorly confused with ecs. You love to read the complete file.
  4. starikcetin


    Dec 7, 2017
    Takes some time to get used to but as far as I see up to now, you can store everything as components, or even their own entities. I believe it is what makes ECS beautiful, that we get to treat all of the data the same way.
  5. jooleanlogic


    Mar 1, 2018
    Thanks for the feedback.
    Most of my confusion comes from not understanding how ecs works under the hood. I was completely wrong on how I thought filtering worked. I didn't even realise it applied to shared components and not data components. :(.

    You can but I'm not sure it works well in practice. Data components are generally pretty fixed whereas working variables change all the time as you refactor code. My understanding is that component data should store the state of your game, not the local variables you use to get to that state. Local variables ideally should just exist in the Systems and between Systems.

    The crux of the problem is that I have a single logical process (engines consume fuel from the active fuel tank) split across multiple systems so I need to pass the working variables across multiple systems.

    Having said that, this was my first attempt and likely just poor design. I'm sure with a bit more thought, it could be done within a single system. Overall, I think Unity's pure implementation of ecs is going to prove to be awesome. It's just my skills that have to catch up. :)

    No you wouldn't. lol. I struggle to reason about my own code. The seemingly simple pseudo code above is very hard to follow in the actual implementation.
    My advice is to create a project with the smallest working shell of an ecs you can, and then build on it. All you need at a minimum is a ComponentData, a GameObject with that ComponentData attached, and then a ComponentSystem. That's it. Then go from there.
  6. PhilSA


    Jul 11, 2013
    I am facing a situation that is somewhat similar to this... in the sense that there needs to be data that needs to be passed from one system to another, and it just doesn't "feel right" to make that data into a component. I am making a physics engine and I have my own "rigidbody" and "collider" components. I have a system that handles detecting contacts between colliders, and a different one that handles resolving contacts for the rigidbodies associated to those colliders

    My ContactsGenerationSystem needs to store contacts per collider entity, and my ContactsResolutionSystem needs to use those contacts later

    My plan for now (not tested yet) is that I will keep a persistent NativeMultiHashMap<Entity, Contact> somewhere publicly-accessible in my physics world, and store all contacts per collider entity in there. Later, all the systems that need to access contacts of a certain collider entity can get them from here

    But in my case, since this is an extremely performance-critical part of the system, I may end up doing something similar, but without hashmaps. Instead, I will do everything directly with conservatively pre-allocated NativeArrays, and every collider component will store the index of where their data is in those arrays
    Last edited: May 18, 2018
  7. recursive


    Jul 12, 2012
    I have a similar issue. It's one thing to have the source data be components on entities, but some best practices for passing around shared temporary processing buffers between related systems so it's easy for them to read/write to them without blowing up job read/write safety would be helpful. @Joachim_Ante - is this something in the works for Unite Berlin (or possibly before)?
  8. sngdan


    Feb 7, 2014

    Would be great if you could share progress here. Not too long ago I did a pixel collision in response to a forum discussion. ECS, burst, etc where not out then. When I have some time, I plan to convert this to pure ECS. Things I need to figure out:
    - best practice for managing collision matrices - (ie Box collision -> pixel collision pairs) and accessing the from different systems - I also thought of multihashmap
    - (best) way to stop a parallel for job (ie pixel collision can stop when first hit is found)
    - parallelforbatch - any info on how this works and if it can be stopped early