Search Unity

Update systems at FixedUpdate frequency (with new APIs)?

Discussion in 'Data Oriented Technology Stack' started by Mr-Mechanical, Apr 7, 2019.

  1. Mr-Mechanical

    Mr-Mechanical

    Joined:
    May 31, 2015
    Posts:
    191
    Before I created a systemgroup and manually updated it...
    How would I do this now? (Edit: this still works just some small API changes)

    Thanks, input is appreciated.
     
    Last edited: Apr 10, 2019
    GliderGuy likes this.
  2. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    521
    In an older versions you could use the [UpdateBefore(typeof(FixedUpdate))]

    Code (CSharp):
    1.  [UpdateBefore(typeof(FixedUpdate))]
    2.     public class Test : ComponentSystem {
    3.         protected override void OnUpdate() {
    4.         }
    5.     }
    unfortunately this doesn't work at the moment :(
     
  3. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,265
    Right now `ScriptBehaviourUpdateOrder.UpdatePlayerLoop(World world)` is locked to put the specific 3 top system groups to a specific step, the way maybe you have to modify the ScriptBehaviourUpdateOrder.CurrentPlayerLoop that comes out of that, then use ScriptBehaviourUpdateOrder.SetPlayerLoop back again. By "modify" you would have to put your system group's update delegate in the correct subsystem like what ScriptBehaviourUpdateOrder.cs is doing (a pain, but at least now you just need to put 1 update of the whole group instead of every updates in the group's system. Great when you have to add more systems to the group too so sorting update order in the group again does not affect what the player loop is running)
     
  4. jooleanlogic

    jooleanlogic

    Joined:
    Mar 1, 2018
    Posts:
    332
    There's probably a better way but this is working for me atm.

    Code (CSharp):
    1. void Awake() {
    2.     World.Active.GetExistingSystem<FixedUpdateGroup>().Enabled = false;
    3. }
    4.  
    5. void FixedUpdate() {
    6.     var fixedUpdateGroup = World.Active.GetExistingSystem<FixedUpdateGroup>();
    7.     fixedUpdateGroup.Enabled = true;
    8.     fixedUpdateGroup.Update();
    9.     fixedUpdateGroup.Enabled = false;
    10. }
    All my fixed update systems are in FixedUpdateGroup which is in Simulation group.
     
    StefanaUnity, Abbrew and 5argon like this.
  5. StefanaUnity

    StefanaUnity

    Joined:
    Apr 9, 2019
    Posts:
    18
    So no one actually know the proper way to do it? I'm not kidding when i say this, its crossed my mind that the ECS dev doesnt even know how to write fixedupdate in ecs :D
     
  6. Roycon

    Roycon

    Joined:
    Jul 10, 2012
    Posts:
    19
    I don't think there is a proper way yet, just use one of these and then replace it in a few ECS versions when there is a proper way

    Unity will add fixed update support at some point :) we just need to wait or do one of these work arounds
     
    StefanaUnity likes this.
  7. jooleanlogic

    jooleanlogic

    Joined:
    Mar 1, 2018
    Posts:
    332
    To my knowledge, there currently is no proper way.
    Hybrid FixedUpdate is literally not part of ecs at the moment. They're working on it but you need your own temp solution in the meantime.

    - Edit - Roycon beat me. :)
     
    StefanaUnity likes this.
  8. StefanaUnity

    StefanaUnity

    Joined:
    Apr 9, 2019
    Posts:
    18
    Hey thanks guys I liked your post, can i get a example? I have this but still get this warning:
    Code (CSharp):
    1. Ignoring invalid [UpdateBefore] dependency for SystemFixedUpdate_: UnityEngine.Experimental.PlayerLoop.FixedUpdate must be a member of the same ComponentSystemGroup.
    2.  
    This is my attempt

    Code (CSharp):
    1. [UpdateBefore(typeof(FixedUpdate))]
    2. public class SystemFixedUpdate_ : ComponentSystem
    3. {
    4.  
    5. }
    6.  
    7.  
    8. private void FixedUpdate ()
    9. {
    10.         var updategroup = World.Active.GetExistingSystem<SystemFixedUpdate_>();
    11.         updategroup.Enabled = true;
    12.         updategroup.Update();
    13.         updategroup.Enabled = false;
    14. }
    15.  
     
  9. jooleanlogic

    jooleanlogic

    Joined:
    Mar 1, 2018
    Posts:
    332
    So atm, I don't think FixedUpdate is utilised and there's just these three parent groups in which your systems have to be. At least for the default scenario:
    InitializationSystemGroup
    SimulationSystemGroup
    PresentationSystemGroup

    I just made my own sub group 'FixedUpdateGroup' and put it in the SimulationSystemGroup.
    Code (CSharp):
    1. // FixedUpdateGroup.cs
    2. [UpdateInGroup(typeof(SimulationSystemGroup))]
    3. public class FixedUpdateGroup : ComponentSystemGroup {}
    Then I add my systems to that FixedUpdateGroup
    Code (CSharp):
    1. // MyFixedUpdateSystem.cs
    2. [UpdateInGroup(typeof(FixedUpdateGroup))]
    3. public class MyFixedUpdateSystem : BaseComponentSystem {}
    Then I add that code from post #4 above to a MonoBehaviour in the scene.
     
    StefanaUnity likes this.
  10. psuong

    psuong

    Joined:
    Jun 11, 2014
    Posts:
    55
    Hey so they actually reverted the change for SimulationGroup to run in Update (not FixedUpdate) until they've got more infrastructure in place.

    https://github.com/Unity-Technologi...Samples/blob/master/ReleaseNotes.md#changes-3

     
  11. james_unity988

    james_unity988

    Joined:
    Aug 10, 2018
    Posts:
    71
    This is a better solution:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using Unity.Entities;
    4. using Unity.Physics.Systems;
    5. using UnityEngine;
    6. public class PhysicsRunner : MonoBehaviour
    7. {
    8.     private IEnumerable<ComponentSystemBase> simSystems;
    9.     void Start()
    10.     {
    11.         World.Active.GetOrCreateManager<SimulationSystemGroup>().Enabled = false;
    12.         simSystems = World.Active.GetOrCreateManager<SimulationSystemGroup>().Systems;
    13.     }
    14.     void FixedUpdate()
    15.     {
    16.         foreach(var sys in simSystems)
    17.         {
    18.             sys.Update();
    19.         }
    20.     }
    21. }
    Found here: Unity Physics Discussion
     
  12. StefanaUnity

    StefanaUnity

    Joined:
    Apr 9, 2019
    Posts:
    18
    Is it just me? I wouldn't notice it if it wasn't for my camera following the character's head in LateUpdate. Basically the camera doesn't follow the head properly, it's as if its not in LateUpdate because only LateUpdate gets animation bones transform.
     
    Last edited: Apr 11, 2019
  13. james_unity988

    james_unity988

    Joined:
    Aug 10, 2018
    Posts:
    71
    Oh, I thought you were asking about FixedUpdate not LateUpdate. If you need something to run in LateUpdate you could use a very similar approach to what I mentioned above, but I would recommend creating your own system group instead of using SimulationSystemGroup.
     
  14. cort_of_unity

    cort_of_unity

    Unity Technologies

    Joined:
    Aug 15, 2018
    Posts:
    23
    Earlier this week I added a sample demonstrating the current FixedUpdate workaround; it is basically what's described in this thread though (#11 pretty much nails it). The sample should be included in the next Entities package release.

    Re: @StefanaUnity's question about the camera lagging behind the object it's tracking -- unfortunately this is a known issue. As a workaround, the PresentationSystemGroup runs (for now) after the legacy LateUpdate player loop phase, for systems running in that group can access the most up-to-date, post-animation object locations. Some caveats:
    1. Make sure your systems are ordered before the actual built-in presentation systems, or the work will be done too late to be rendered.
    2. Note that the transformation system currently only runs in the SimulationSystemGroup, so if you modify any the transformation components of any Entities beyond that point, you'll have to manually generate an up-to-date LocalToWorld matrix for the presentation systems to consume.
     
    GilCat and james_unity988 like this.
  15. StefanaUnity

    StefanaUnity

    Joined:
    Apr 9, 2019
    Posts:
    18
    You are correct I needed FixedUpdate and I also was doing LateUpdate with the examples you guys provided
     
  16. OndrejP

    OndrejP

    Joined:
    Jul 19, 2017
    Posts:
    27
    Another variant of running SimulationUpdateGroup in fixed update.
    It finds SimulationUpdateGroup in PlayerLoop and moves it from Update to FixedUpdate.
    No need for MonoBehaviour, just place this script anywhere into project.

    Code (CSharp):
    1. using System;
    2. using Unity.Entities;
    3. using UnityEngine;
    4. using UnityEngine.Experimental.LowLevel;
    5. using UnityEngine.Experimental.PlayerLoop;
    6.  
    7. public static class FixedUpdateRunner
    8. {
    9.     [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
    10.     static void MoveSimulationGroup()
    11.     {
    12.         // This must be called AFTER DefaultWorldInitialization, otherwise DefaultWorldInitialization overwrites PlayerLoop
    13.         var playerLoop = ScriptBehaviourUpdateOrder.CurrentPlayerLoop;
    14.         var func = RemoveCallback<SimulationSystemGroup>(playerLoop);
    15.         if (func != null)
    16.         {
    17.             InstallCallback<SimulationSystemGroup>(playerLoop, typeof(FixedUpdate), func);
    18.             ScriptBehaviourUpdateOrder.SetPlayerLoop(playerLoop);
    19.         }
    20.     }
    21.  
    22.     static void InstallCallback<T>(PlayerLoopSystem playerLoop, Type subsystem, PlayerLoopSystem.UpdateFunction callback)
    23.     {
    24.         for (var i = 0; i < playerLoop.subSystemList.Length; ++i)
    25.         {
    26.             int subsystemListLength = playerLoop.subSystemList[i].subSystemList.Length;
    27.             if (playerLoop.subSystemList[i].type == subsystem)
    28.             {
    29.                 // Create new subsystem list and add callback
    30.                 var newSubsystemList = new PlayerLoopSystem[subsystemListLength + 1];
    31.                 for (var j = 0; j < subsystemListLength; j++)
    32.                 {
    33.                     newSubsystemList[j] = playerLoop.subSystemList[i].subSystemList[j];
    34.                 }
    35.                 newSubsystemList[subsystemListLength].type = typeof(FixedUpdateRunner);
    36.                 newSubsystemList[subsystemListLength].updateDelegate = callback;
    37.                 playerLoop.subSystemList[i].subSystemList = newSubsystemList;
    38.             }
    39.         }
    40.     }
    41.  
    42.     static PlayerLoopSystem.UpdateFunction RemoveCallback<T>(PlayerLoopSystem playerLoop)
    43.     {
    44.         for (var i = 0; i < playerLoop.subSystemList.Length; ++i)
    45.         {
    46.             int subsystemListLength = playerLoop.subSystemList[i].subSystemList.Length;
    47.             for (var j = 0; j < subsystemListLength; j++)
    48.             {
    49.                 var item = playerLoop.subSystemList[i].subSystemList[j];
    50.                 if (item.type == typeof(T))
    51.                 {
    52.                     playerLoop.subSystemList[i].subSystemList = ExceptIndex(playerLoop.subSystemList[i].subSystemList, j);
    53.                     return item.updateDelegate;
    54.                 }
    55.             }
    56.         }
    57.         return null;
    58.     }
    59.  
    60.     static T[] ExceptIndex<T>(T[] array, int exceptIndex)
    61.     {
    62.         T[] result = new T[array.Length - 1];
    63.         if (exceptIndex > 0)
    64.         {
    65.             Array.Copy(array, result, exceptIndex);
    66.         }
    67.         if (exceptIndex < array.Length - 1)
    68.         {
    69.             Array.Copy(array, exceptIndex + 1, result, exceptIndex, array.Length - exceptIndex - 1);
    70.         }
    71.         return result;
    72.     }
    73. }
     
    psuong likes this.