using System; using EscapeRoomEngine.Engine.Runtime.Measurements; using EscapeRoomEngine.Engine.Runtime.Utilities; using NaughtyAttributes; using UnityEngine; using UnityEngine.UI; namespace EscapeRoomEngine.Engine.Runtime.UI { public enum GameState { Stopped, Paused, Running } public class GameControl : MonoBehaviour { public static GameControl Instance { get; private set; } [BoxGroup("Internal")] [SerializeField] private Button startButton, stopButton, pauseButton, addTimeButton, removeTimeButton; [BoxGroup("Internal")] [SerializeField] private Text timeText, roomTimeText, estimateTimeText, targetTimeText; [BoxGroup("Internal")] [SerializeField] private float uiUpdateInterval = 1; [HideInInspector] public GameState gameState = GameState.Stopped; public float TimeElapsed { get; private set; } public float TimeInRoom { get; set; } public float TargetTime { get; private set; } private float _previousUIUpdate; private void Awake() { Instance = this; } private void Start() { TargetTime = Engine.Instance.initialTargetTime; SetTimeText(); } private void Update() { // update time if (gameState == GameState.Running) { TimeElapsed += Time.deltaTime; TimeInRoom += Time.deltaTime; } // update ui if (Time.time > _previousUIUpdate + uiUpdateInterval) { _previousUIUpdate = Time.time; SetTimeText(); } // enable or disable buttons startButton.interactable = gameState == GameState.Stopped; stopButton.interactable = gameState != GameState.Stopped; pauseButton.interactable = gameState is GameState.Running or GameState.Paused; addTimeButton.interactable = gameState != GameState.Stopped; removeTimeButton.interactable = gameState != GameState.Stopped && TargetTime >= TimeElapsed + 60; } #region Time Controls public void StartGame() { gameState = GameState.Running; TimeElapsed = 0; // generate the first room if it hasn't been generated yet Engine.Instance.CurrentRoom.Match(none: () => Engine.Instance.GenerateRoom()); // start a new session Measure.StartSession(); } public void StopGame() { if (gameState != GameState.Stopped) { // was running Measure.EndSession(TimeElapsed); } gameState = GameState.Stopped; } public void PauseGame() { // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault switch (gameState) { case GameState.Running: gameState = GameState.Paused; pauseButton.GetComponent().Paused = true; break; case GameState.Paused: gameState = GameState.Running; pauseButton.GetComponent().Paused = false; break; } } /// /// Change the allowed time by a specified amount of seconds. /// /// The amount of seconds that will be added to the time. Can be negative to remove time. public void ChangeTime(int seconds) { if (TargetTime + seconds >= TimeElapsed) { TargetTime += seconds; } } private void SetTimeText() { timeText.text = TimeToText(TimeElapsed); roomTimeText.text = TimeToText(TimeInRoom); targetTimeText.text = TimeToText(TargetTime); Engine.Instance.CurrentRoom.Match(some: room => { estimateTimeText.text = TimeToText( TimeElapsed - TimeInRoom + Mathf.Max(TimeInRoom, Measure.AverageTime(room)) + Engine.Instance.EstimatedTimeRemaining); }); } private static string TimeToText(float time) => $"{time.ToTimeSpan():mm':'ss}"; #endregion #region Measurements public void StoreMeasurements(Toggle toggle) { Measure.Store = toggle.isOn; } #endregion public void ExitGame() { StopGame(); #if UNITY_STANDALONE Application.Quit(); #endif #if UNITY_EDITOR UnityEditor.EditorApplication.isPlaying = false; #endif } } }