For this system I used the states design pattern (see pattern). I already had a finite state machine to switch between the different screens. But the more screens I made, the less clear and organized it became. So I refactored it in about a week with the design pattern.
public interface IState
{
public void OnEnter(Data data = null);
public void Update();
public void OnExit();
}
public enum EState
{
Idle,
Init,
MainMenu,
Database,
SearchResults,
ChosenRouteChain,
Route,
}
private readonly Dictionary<EState, IState> AllStates = new();
public void Init()
{
RegisterStates();
SwitchState(defaultState);
}
private void RegisterStates()
{
AllStates.Add(EState.Idle, new IdleState());
AllStates.Add(EState.Init, new InitState());
AllStates.Add(EState.MainMenu, new MainMenuState());
AllStates.Add(EState.Database, new DatabaseState());
AllStates.Add(EState.SearchResults, new SearchResultsState());
AllStates.Add(EState.ChosenRouteChain, new ChosenRouteChainState());
AllStates.Add(EState.Route, new RouteState());
}
public EState CurrentState { get; private set; }
public EState PreviousState { get; private set; }
private readonly EState defaultState = EState.Init;
public void SwitchState(EState state, Data data = null)
{
if (ValidSwitch(state))
{
PreviousState = CurrentState;
AllStates[CurrentState]?.OnExit();
CurrentState = state;
string previousState = AllStates[PreviousState] != null ? $"{AllStates[PreviousState]}" : "null";
Debug.LogWarning($"Switching from {previousState} to {AllStates[CurrentState]}");
AllStates[CurrentState].OnEnter(data);
}
}
private bool ValidSwitch(EState state)
{
if (!AllStates.ContainsKey(state))
{
Debug.LogError($"State {state} is not registered.");
return false;
}
if (CurrentState == state)
{
Debug.LogWarning($"Already in state {state}. No switch needed.");
return false;
}
return true;
}
public class IdleState : IState
{
public void OnEnter(Data data = null)
{
ScreenManager.Instance.Open(EScreen.Idle, data);
}
public void OnExit()
{
ScreenManager.Instance.Close(EScreen.Idle);
}
public void Update()
{
}
}
using System.Collections.Generic;
using UnityEngine;
public enum EState
{
Idle,
Init,
MainMenu,
Database,
SearchResults,
ChosenRouteChain,
Route,
}
public class StateManager
{
private static StateManager instance;
public static StateManager Instance
{
get
{
if (instance == null)
{
instance = new();
}
return instance;
}
}
public EState CurrentState { get; private set; }
public EState PreviousState { get; private set; }
private readonly EState defaultState = EState.Init;
private readonly Dictionary<EState, IState> AllStates = new();
public void Init()
{
RegisterStates();
SwitchState(defaultState);
}
private void RegisterStates()
{
AllStates.Add(EState.Idle, new IdleState());
AllStates.Add(EState.Init, new InitState());
AllStates.Add(EState.MainMenu, new MainMenuState());
AllStates.Add(EState.Database, new DatabaseState());
AllStates.Add(EState.SearchResults, new SearchResultsState());
AllStates.Add(EState.ChosenRouteChain, new ChosenRouteChainState());
AllStates.Add(EState.Route, new RouteState());
}
public void SwitchState(EState state, Data data = null)
{
if (ValidSwitch(state))
{
PreviousState = CurrentState;
AllStates[CurrentState]?.OnExit();
CurrentState = state;
string previousState = AllStates[PreviousState] != null ? $"{AllStates[PreviousState]}" : "null";
Debug.LogWarning($"Switching from {previousState} to {AllStates[CurrentState]}");
AllStates[CurrentState].OnEnter(data);
}
}
private bool ValidSwitch(EState state)
{
if (!AllStates.ContainsKey(state))
{
Debug.LogError($"State {state} is not registered.");
return false;
}
if (CurrentState == state)
{
Debug.LogWarning($"Already in state {state}. No switch needed.");
return false;
}
return true;
}
}