Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

Controling execution of systems

Discussion in 'Entity Component System' started by fholm, Nov 10, 2018.

  1. fholm

    fholm

    Joined:
    Aug 20, 2011
    Posts:
    2,052
    I have the need to execute some systems on a fixed time step based interval, i.e. not in sync with the regular update/render rate.

    The basic idea is that I have some systems which are responsible for the simulation/logic of the game, these need to run on a fixed time step, i.e. 1/60 or something like that. I have another set of systems which are responsible for the rendering of the world, which should run at whatever the current fps is of the game.

    A naive 'fixed step' loop looks something like this in regular Unity code (note this is not what I'm doing, just trying to illustrate my point):

    Code (csharp):
    1.  
    2.             float acc;
    3.             void Update() {
    4.                 acc += Time.deltaTime;
    5.                 while(acc >= (1f/60f)) {
    6.                     FixedStep();
    7.                     acc -= 1f / 60f;
    8.                 }
    9.                 RenderStep();
    10.             }
    11.  
    FixedStep() will be all of the simulation and RenderStep() would be all of the rendering (things are never this clean in real world scenarios). Basically I need to be able to fully control when and how the systems update.... how would I go about this?

    There's some additional considerations for things such as rollbacks and predictions also, but that's easily solved once I know how to step everything by hand.
     
  2. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,554
    I remembered some discussions about [UpdateBefore/After(typeof(FixedUpdate))] which works, it put your system in a similar timing to FixedUpdate() (if the device lags, then you get multiple calls)

    Or https://forum.unity.com/threads/update-interval.523628/#post-3625324

     
    rigidbuddy likes this.
  3. fholm

    fholm

    Joined:
    Aug 20, 2011
    Posts:
    2,052
    So I looked at the FPS Sample that was released recently, and they seem to be manually controlling execution of the systems. The code in the FPS Sample is massively complex, but from scanning it looks like they are creating a custom world via new World() and then adding managers to it, creating entities, etc. and manually calling Update on all the systems in the exact order that they want.

    the FPS Sample is obviously using Hybrid, and some of the solutions seem a bit... hacky (good sample overall though, for sure).

    But for an example of what i'm talking about, this is the ClientGameLoop.cs class which basically does exactly what I'm talking about: https://github.com/Unity-Technologi...er/Assets/Scripts/Game/Main/ClientGameLoop.cs

    Edit 1: Here's also the GameWorld.cs file https://github.com/Unity-Technologies/FPSSample/blob/master/Assets/Scripts/Game/Entity/GameWorld.cs which contains the creation of the new ecs world, etc.

    Edit 2: Trying to decode exactly what Joachim Ante said in the post you quoted:

    * Turn off auto injection of systems into the player loop. Add relevant entry point into playerloop callback manually.
    Basically means we just disable the auto creation of systems right? How is this done?

    * Call ComponentSystem.Update at the right time for all systems you want to run explicitly
    Which means iterating through all of the systems on the world, and calling update by hand?

    * Implement your own IComponentData storing time & input and update that in the first
    system that runs

    This i'm not following what he means? Why would this be required?

    Edit 3: Looking further into the FPS Sample, can see that they also set the compiler symbol
    UNITY_DISABLE_AUTOMATIC_SYSTEM_BOOTSTRAP
     
    Last edited: Nov 12, 2018
  4. Enzi

    Enzi

    Joined:
    Jan 28, 2013
    Posts:
    908
    In the FPSSample there's ECS/BaseComponentSystem.
    I'm using the BaseComponentSystem now instead of ComponentSystem. The difference is that you have to call the constructor with the GameWorld. The GameWorld.worldTime has a tick, I think that's what Joachim means with own timing and is one of the first things that happen in HandleTime in the Update loop. Basicially just a counter that gets incremented.

    Anyway, the world is created in GameClient/ServerLoop and is pretty easy to setup.
    Those systems' update is then called in the GameLoop Update, which is pretty handy.
    AutoCreation is nice but control over the sequence is even better.

    Word of advice, the other helper systems are not good or have quirks. Don't use InitializeComponentSystem even though it reads fine. I think the problem with it, is that it's only using one state. So if your entity has more than 1 uninitialized comp it screws itself. No idea really, I had errors and then wrote the added/remove pattern that Joachim presented at Unite Berlin 2018 and it worked as expected.
     
  5. fholm

    fholm

    Joined:
    Aug 20, 2011
    Posts:
    2,052
    Yeah I've dug into the FPS sample pretty heavily, I don't plan on replicating or copying it - but it's a good resource to see how to do manual world setup and update. They are also using Hybrid ECS, which I'm not really interested in (if you're doing hybrid, you might aswel just stick to the old GO/MB system imho)
     
  6. Enzi

    Enzi

    Joined:
    Jan 28, 2013
    Posts:
    908
    Yeah, some systems they use run on Monobehaviour comps which is less than optimal. Hybrid is still a big increase when the expensive systems run on IComponentData, it's just the presentation layer that gets slowed down but that can be phased out once we can really go pure ECS which is still a while off I think.
     
  7. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,554
    In FPS example, each systems are given a reference to `m_GameWorld` which is a class type at start through OnCreateManager's "constructor injection". (where what's there in OnCreateManager argument is magically reflected to the manager's constructor method) Then on each update a time is given to m_GameWorld, letting the time known to everyone via the reference type property of a class type variable.

    That works but the more "pure" ECS way would be not using class type but instead a struct. Just putting the time, input, and other shared/bus-like information to ECS database by attaching them to some entities. Then any system down the line can ask for that entity and get the data out. System that aims to process that time and input then can use jobs + mathematics + burst, because struct works in a job.