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. Dismiss Notice

Question Novice question:my events scripts seem cumbersome, what's the cleaner way to do this?

Discussion in 'Scripting' started by bullettea, Mar 24, 2023.

  1. bullettea

    bullettea

    Joined:
    Oct 24, 2019
    Posts:
    29
    For the sake of brevity, I have three game states. Every time the state changes, a changeState event fires off, and different game objects will be active or inactive depending on the state.

    Code (CSharp):
    1. //GameManager.cs
    2.  
    3.     public static GameManager Instance { get; private set; }
    4.  
    5.     private GameState currentGameState;
    6.  
    7.     public event Action<GameState> OnGameStateChanged;
    8.  
    9.     public void UpdateGameState(GameState newState)
    10.     {
    11.         currentGameState = newState;
    12.  
    13.         switch (newState)
    14.         {
    15.             case GameState.Tutorial:
    16.                 break;
    17.             case GameState.Combat:
    18.                 break;
    19.             case GameState.GameOver:
    20.                 break;
    21.             default:
    22.                 throw new ArgumentOutOfRangeException(nameof(newState), newState, null);
    23.         }
    24.  
    25.         OnGameStateChanged?.Invoke(newState);
    26.     }
    27.  
    28. //Let's say each of these objects (a tutorial enemy, a combat fighter, and a gameover screen), will
    29. //each be active or inactive depending on the game state. Enemy.cs,
    30. //Fighter.cs, and GameOverScreen.cs will be attached to their respective
    31. //objects and include this code:
    32.  
    33.  private void Start()
    34.     {
    35.  
    36.         GameManager.Instance.OnGameStateChanged += GameManager_OnGameStateChanged;
    37.     }
    38.  
    39.     private void GameManager_OnGameStateChanged(GameState currentState)
    40.     {
    41.         if (GameManager.Instance.GetGameState() == GameState.Tutorial) //or GameState.Combat or GameState.GameOver, depending on the object
    42.         {
    43.             this.gameObject.SetActive(true);
    44.         }
    45.         else
    46.         {
    47.             this.gameObject.SetActive(false);
    48.         }
    49.     }
    50.  
    51.  
    52.  
    It seems like a lot of code is being replicated here, since each of these objects have a snippet of almost the same code. Is this the best way to set these objects active and inactive depending on the Game State while using events? What's a better way of doing this? Thank you so much!
     
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    Generalize it as a simple script:

    Code (csharp):
    1. public class GameManagerStatusStateMachine : MonoBehaviour
    2. {
    3.  
    4.     #region Fields
    5.  
    6.     public GameObject TutorialState;
    7.     public GameObject CombatState;
    8.     public GameObject GameOverState;
    9.  
    10.     #endregion
    11.  
    12.     #region CONSTRUCTOR
    13.  
    14.     void Start()
    15.     {
    16.         this.SyncState(GameManager.Instance.CurrentGameState);
    17.         GameManager.Instance.OnGameStateChanged += GameManager_OnGameStateChanged;
    18.     }
    19.  
    20.     void OnDestroy()
    21.     {
    22.         GameManager.Instance.OnGameStateChanged -= GameManager_OnGameStateChanged;
    23.     }
    24.    
    25.     #endregion
    26.  
    27.     #region Methods
    28.  
    29.     public void SyncState(GameState state)
    30.     {
    31.         if (TutorialState) TutorialState.SetActive(state == GameState.Tutorial);
    32.         if (CombatState) CombatState.SetActive(state == GameState.Combat);
    33.         if (GameOverState) GameOverState.SetActive(state == GameState.GameOver);
    34.     }
    35.  
    36.     private void GameManager_OnGameStateChanged(GameState currentState)
    37.     {
    38.         this.SyncState(currentState);
    39.     }
    40.  
    41.     #endregion
    42.  
    43. }
    We do this very exact thing all the time in our games.

    upload_2023-3-23_21-30-40.png

    Here you can see how I have our multiplayer UI is configured. There's an object in the scene that when you walk up to it and press A, the UI opens, and it enables the appropriate UI screen in itself based on what the status of the game is:

    upload_2023-3-23_21-31-46.png

    And because it's generalized... it can be used for anything. It just HAPPENS to be for UI here. But note that like in the script I showed you... nothing about it conveys UI. It's just enabling/disabling gameobjects.
     
    Last edited: Mar 24, 2023
    Bunny83 and spiney199 like this.
  3. bullettea

    bullettea

    Joined:
    Oct 24, 2019
    Posts:
    29
    Hey, thanks so much for showing a cleaner way to do this! Very much appreciated.

    I'm trying to understand it fully....
    Code (CSharp):
    1.         if (TutorialState) TutorialState.SetActive(state == GameState.Tutorial);
    What will cause TutorialState to be true or false in the first place? Is this another script that controls this?

    And to be clear, the game states (e.g. Tutorial State) are objects? Like Host/Client/Offline in your game? Aren't they always true then, if they simply exist in the game scene?
     
  4. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    What if they don't exist? Maybe you destroyed it, or you never dragged an entry onto it (maybe you don't need a tutorial state in one of your use cases), then the GameObject reference will be null.

    And Unity implicitly converts null/destroyed gameobjects to false. And alive/non-null gameobjects to true. (not just gameobjects, but all UnityEngine.Objects)

    This can give you more freedom of use.

    Some places you use it you're tracking all possible game states.

    But maybe you have another where the ONLY thing you need to know is if you're in Tutorial or not. So you only configure the TutorialState and leave the others null.
     
    bullettea likes this.
  5. bullettea

    bullettea

    Joined:
    Oct 24, 2019
    Posts:
    29
    Ahhhhh thank you for the explanation...I think I understand now! :D