Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

Is there a way to have a System disabled by default?

Discussion in 'Project Tiny' started by Ferran_SP, May 13, 2019.

  1. Ferran_SP

    Ferran_SP

    Joined:
    Jul 9, 2018
    Posts:
    27
    Hi,

    I'm giving some thought how to structure my game update loops and game states.
    I've seen the MatchThree sample project uses a UpdateGameState System, and then uses static methods to update the active game state.

    I was wondering if I could avoid using these static update methods (because, conceptually, I don't like them very much).
    I thought of creating a system for each of these update methods (such that, for instance, the UpdateWorldMap static method would become a WorldMapSystem that would be updated by Unity Tiny's scheduler).
    Then, I would enable or disable the Systems depending on the current game state in some other System or helper function.
    But the problem is that if I do this, all the systems OnUpdate method is at least called once. Even if I disable them (via the this.world.scheduler().disableName method) as early as I can, they are at least updated once.

    Is there a way to have Systems disabled by default?

    Thanks!
     
  2. reallyhexln

    reallyhexln

    Joined:
    Jun 18, 2018
    Posts:
    69
    I'm not sure about performance but you can try to use Configuration component with some flag that will be checked in OnUpdate method.
     
  3. ben4d85

    ben4d85

    Joined:
    Dec 26, 2018
    Posts:
    9
    How about this?

    Code (JavaScript):
    1. export class MySystem extends ut.ComponentSystem {
    2.  
    3.     // switch this system's update method on/off
    4.     private runSystem: boolean = true;
    5.  
    6.     OnUpdate():void {
    7.  
    8.         // if this system's update method is switched off
    9.         if( !this.runSystem ) {
    10.             console.log( "Skipping MySystem" );
    11.             return;
    12.         }
    13.         else {
    14.             console.log( "Running MySystem" );
    15.         }
    16.     }
    17. }
    18.  
     
    Ferran_SP likes this.
  4. Zionisias

    Zionisias

    Joined:
    Apr 23, 2019
    Posts:
    40
    In the project I'm currently working on we use a similar approach as to what reallyhexln and ben4d85 mentioned. I have created an abstract class, which extends from ut.ComponentSystem. This class has an abstract field with an array of gamestates (I think it's best to make GameState an enum). The class then has a method, which can be used to check if the current gamestate is part of the list of gamestates provided. I can best explain with some code.
    Code (CSharp):
    1.  
    2. export abstract class GameStateComponentSystem extends ut.ComponentSystem {
    3.     //Fill it with the GameStates in which your sub-class's OnUpdate() should execute.
    4.     protected abstract statesToExecuteIn: GameState[];
    5.  
    6.     //Default is false, you can override this value in your sub-class.
    7.     protected executesInAllStates = false;
    8.  
    9.     //Call this function in the first line of your OnUpdate() in your sub-class.
    10.     IsAllowedToExecute(): boolean {
    11.         //If it is allowed to execute in all states,
    12.         //or if the current state is within the list of statesToExecuteIn, return true.
    13.         if (this.executesInAllStates || this.statesToExecuteIn.indexOf(GameStateManager.CurrentState) !== -1) return true;
    14.         //Return false if it isn't.
    15.         return false;
    16.     }
    17. }
    18.  
    You can then extend this class within your other classes, fill in the list of GameStates, set executesInAllStates to true to ignore the list of states if you want, and add the IsAllowedToExecute() check within your class's OnUpdate(). Code:
    Code (CSharp):
    1. export class ExampleSystem extends GameStateComponentSystem {
    2.     //Fill in your list of states like this.
    3.     protected statesToExecuteIn: GameState[] = [GameState.MAINMENU, GameState.GAME];
    4.  
    5.     //This can be true or false, but if it's false you can just remove this line
    6.     //because we already provided the baseclass with a default of false.
    7.     protected executesInAllStates = false;
    8.  
    9.     OnUpdate(): void {
    10.         //You will need to call the IsAllowedToExecute() like this.
    11.         if (!super.IsAllowedToExecute()) return;
    12.         //Place code here!
    13.     }
    14. }
    The disadvantage of this code is that all systems will still execute and do these checks, even when they are 'not running'. So it is slightly less performant than disabling the entire system.
     
    Last edited: May 14, 2019
    Ferran_SP and reallyhexln like this.
  5. Ferran_SP

    Ferran_SP

    Joined:
    Jul 9, 2018
    Posts:
    27
    Thanks for the feedback, I'll keep it in mind!.
    Cheers!
     
    ben4d85 and Zionisias like this.
  6. Ferran_SP

    Ferran_SP

    Joined:
    Jul 9, 2018
    Posts:
    27
    @Zionisias I'm exploring the suggestion you made, but I'm running into this compilation error

    TypeScriptError: Class 'GameStateComponentSystem' used before its declaration.
    Scripting error (at Assets/MyGame/Scripts/BootSystem.ts:4)


    BootSystem looks like this:

    namespace game
    {
    export class BootSystem extends game.GameStateComponentSystem
    {
    protected statesToExecuteIn: GameStateTypes[] = [GameStateTypes.Boot];

    OnUpdate(): void
    {

    }
    }
    }


    Did you encounter anything similar?
    The weirdest thing is that I'm only getting this error in some files. In some others, it works fine. :/
     
  7. reallyhexln

    reallyhexln

    Joined:
    Jun 18, 2018
    Posts:
    69
    You need to add
    Code (JavaScript):
    1. /// <reference path="./GameStateComponentSystem.ts" />
    at the beginning line of each your file that uses classes from different file in [static] context.
    Inheritance in the Typescript is the thing that executes while your script is loading and requires the base class is already available and loaded before using it in inheritance relationship.
    In your case, BoostSystem is loaded before the GameStateComponentSystem, so Typescript don't know about it and thinks it's undefined.
    When you use <reference> directive you point the interpreter that GameStateComponentSystem must be loaded before BoostSystem.
    Sorry for my bad english.

    Upd:
    > The weirdest thing is that I'm only getting this error in some files. In some others, it works fine. :/

    It's because the tiny system that combining all your code into single .ts file arranging your classes in undetermined order, so some classes may be already defined when you trying to use them in inheritance, and some files is not defined yet, so you get an error when attempting to inherits from them.
     
    Last edited: May 14, 2019
    Ferran_SP and Zionisias like this.
  8. Ferran_SP

    Ferran_SP

    Joined:
    Jul 9, 2018
    Posts:
    27
    Damn, I had already tried this approach, but I missed the slash / at the end, before the closing angular bracket >.
    Thanks a lot! :)