231 lines
7.7 KiB
C#
231 lines
7.7 KiB
C#
/*
|
|
* author: mark joshwel
|
|
* date: 29/5/2024
|
|
* description: game manager singleton for single source of truth state management
|
|
*/
|
|
|
|
using UnityEngine;
|
|
|
|
/// <summary>
|
|
/// singleton class for managing the game state as a single source of truth
|
|
/// </summary>
|
|
public class GameManager : MonoBehaviour
|
|
{
|
|
/// <summary>
|
|
/// enum for available menus in the game, for use with <c>ShowMenu()</c>
|
|
/// </summary>
|
|
public enum DisplayState
|
|
{
|
|
Game,
|
|
ScreenMainMenu,
|
|
ScreenOptionsMenu,
|
|
ScreenCreditsMenu,
|
|
ScreenPauseMenu,
|
|
ScreenCaughtPause,
|
|
ScreenEscapedMenu,
|
|
UnassociatedState
|
|
}
|
|
|
|
/// <summary>
|
|
/// singleton pattern: define instance field for accessing the singleton elsewhere
|
|
/// </summary>
|
|
public static GameManager Instance;
|
|
|
|
/// <summary>
|
|
/// the current state of the game
|
|
/// </summary>
|
|
private DisplayState _state = DisplayState.UnassociatedState;
|
|
|
|
/// <summary>
|
|
/// property to check if the game is paused based on the current <c>DisplayState</c>
|
|
/// </summary>
|
|
// TODO: remove this if not needed
|
|
public bool Paused => _state != DisplayState.Game;
|
|
|
|
/// <summary>
|
|
/// function to set don't destroy on load and check for multiple instances
|
|
/// </summary>
|
|
private void Awake()
|
|
{
|
|
// check if instance hasn't been set yet
|
|
if (Instance == null)
|
|
{
|
|
// set this instance as the singleton instance
|
|
Instance = this;
|
|
// don't destroy this instance on scene load
|
|
DontDestroyOnLoad(gameObject);
|
|
|
|
Debug.Log("GameManager: Awake as singleton instance");
|
|
}
|
|
// check if instance is already set and it's not this instance
|
|
else if (Instance != null && Instance != this)
|
|
{
|
|
Debug.Log("GameManager: Awake as non-singleton instance, destroying self");
|
|
|
|
// destroy the new instance if it's not the singleton instance
|
|
Destroy(gameObject);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// called when game starts, sets state to main menu
|
|
/// </summary>
|
|
private void Start()
|
|
{
|
|
SetDisplayState(DisplayState.ScreenMainMenu);
|
|
}
|
|
|
|
/// <summary>
|
|
/// helper function to hide any menu that is currently showing
|
|
/// </summary>
|
|
private void HideMenuHelper()
|
|
{
|
|
// get all child menus in the "Menus" parent object
|
|
foreach (var menu in GameObject.FindGameObjectsWithTag("Menus"))
|
|
foreach (Transform menuChild in menu.transform)
|
|
{
|
|
// disable the menu
|
|
Debug.Log($"GameManager: HideMenuHelper - hiding menu '{menuChild}'");
|
|
menuChild.gameObject.SetActive(false);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// helper function for <c>SetDisplayState()</c> to pause the game,
|
|
/// called before the incoming game state is set
|
|
/// </summary>
|
|
/// <param name="incomingState">the to-be-set state of the game</param>
|
|
private void PauseGameHelper(DisplayState incomingState)
|
|
{
|
|
// if we're transitioning from a state of gameplay to a state of non-gameplay,
|
|
// then we should pause the game
|
|
if (_state == DisplayState.Game && incomingState != DisplayState.Game)
|
|
{
|
|
Debug.Log("GameManager: PauseGameHelper - actually pausing game");
|
|
Time.timeScale = 0f;
|
|
Cursor.lockState = CursorLockMode.None;
|
|
Cursor.visible = true;
|
|
}
|
|
|
|
// if the current and incoming states are the same, then we shouldn't do anything,
|
|
// so we return early
|
|
if (_state == incomingState)
|
|
{
|
|
Debug.Log("GameManager: PauseGameHelper - states are the same, returning early");
|
|
return;
|
|
}
|
|
|
|
// hide any menu that is currently showing
|
|
HideMenuHelper();
|
|
|
|
// get all child menus in the "Menus" parent object
|
|
foreach (var menuParent in GameObject.FindGameObjectsWithTag("Menus"))
|
|
foreach (Transform menu in menuParent.transform)
|
|
{
|
|
// show the menu based on the incoming state
|
|
// get the associated state of the menu
|
|
var associatedState = menu.gameObject.GetComponent<CommonMenu>().associatedState;
|
|
Debug.Log(
|
|
$"GameManager: PauseGameHelper - found menu '{menu}' "
|
|
+ $"with associated state {associatedState} "
|
|
+ $"against incoming state {incomingState}");
|
|
|
|
// guard clause if the menu isn't what we're looking for
|
|
if (associatedState != incomingState)
|
|
continue;
|
|
|
|
// if the associated state is the same as the incoming state, then show the menu
|
|
Debug.Log($"GameManager: PauseGameHelper - showing menu for {incomingState}");
|
|
menu.gameObject.SetActive(true);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// helper function for <c>SetDisplayState()</c> to resume the game,
|
|
/// called before the incoming game state is set
|
|
/// </summary>
|
|
/// <param name="incomingState">the to-be-set state of the game</param>
|
|
private void ResumeGameHelper(DisplayState incomingState)
|
|
{
|
|
// if we're NOT transitioning from a state of non-gameplay to a state of gameplay,
|
|
// (which means currently we are in a state of gameplay),
|
|
// then we shouldn't do anything, because the game is already running,
|
|
// so we return early
|
|
if (_state == DisplayState.Game || incomingState != DisplayState.Game)
|
|
{
|
|
Debug.Log(
|
|
"GameManager: ResumeGameHelper - returning prematurely as" +
|
|
$" _state={_state} and incomingState={incomingState}");
|
|
|
|
return;
|
|
}
|
|
|
|
// else, we should resume the game
|
|
Time.timeScale = 1f;
|
|
Cursor.lockState = CursorLockMode.Locked;
|
|
Cursor.visible = false;
|
|
|
|
// hide any menu that is currently showing
|
|
HideMenuHelper();
|
|
}
|
|
|
|
/// <summary>
|
|
/// function to show a menu based on the enum passed,
|
|
/// and any other necessary actions
|
|
/// </summary>
|
|
/// <param name="displayState">the game menu to show</param>
|
|
public void SetDisplayState(DisplayState displayState)
|
|
{
|
|
// check if the game is paused or not
|
|
if (displayState == DisplayState.Game)
|
|
{
|
|
Debug.Log($"GameManager: SetDisplayState({displayState}) - resuming game");
|
|
ResumeGameHelper(displayState);
|
|
}
|
|
else
|
|
{
|
|
Debug.Log($"GameManager: SetDisplayState({displayState}) - pausing game");
|
|
PauseGameHelper(displayState);
|
|
}
|
|
|
|
// set the state of the game to the incoming state
|
|
_state = displayState;
|
|
|
|
// post-state change actions case switch
|
|
switch (displayState)
|
|
{
|
|
// if we're transitioning to the game state,
|
|
// change camera to the player camera
|
|
case DisplayState.Game:
|
|
// TODO: change camera to player camera
|
|
return;
|
|
|
|
// if we're transitioning to the main menu state,
|
|
// change camera to the main menu camera
|
|
case DisplayState.ScreenMainMenu:
|
|
// TODO: change camera to main menu camera
|
|
return;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// wrapper function to quit the game
|
|
/// in case of any cleanup needed
|
|
/// </summary>
|
|
public void Quit()
|
|
{
|
|
// quit the application
|
|
Application.Quit();
|
|
}
|
|
|
|
/// <summary>
|
|
/// resets game state and starts a new game, will call <c>SetDisplayState()</c>
|
|
/// </summary>
|
|
public void NewGame()
|
|
{
|
|
// set to game state
|
|
SetDisplayState(DisplayState.Game);
|
|
|
|
// TODO
|
|
}
|
|
} |