GameManager.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. using StarterAssets;
  2. using TMPro;
  3. using UnityEngine;
  4. using UnityEngine.SceneManagement;
  5. public class GameManager : MonoBehaviour
  6. {
  7. public static GameManager Instance;
  8. [Header("Game Settings")]
  9. public int totalOrbsToWin = 20;
  10. public float timeRemaining = 300f;
  11. [Header("UI References")]
  12. public TextMeshProUGUI orbText;
  13. public TextMeshProUGUI timerText;
  14. [Header("Game Over UI")]
  15. public GameObject gameOverPanel;
  16. public TextMeshProUGUI gameOverTitleText;
  17. private int currentOrbs = 0;
  18. private bool isGameOver = false;
  19. public int GetOrbsInternal() { return currentOrbs; }
  20. public void SetDataInternal(int orbs, float time)
  21. {
  22. currentOrbs = orbs;
  23. timeRemaining = time;
  24. UpdateOrbUI();
  25. UpdateTimerUI();
  26. }
  27. void Awake()
  28. {
  29. if (Instance == null) Instance = this;
  30. else Destroy(gameObject);
  31. }
  32. void Start()
  33. {
  34. // 1. ALWAYS reset time and cursor state first
  35. Time.timeScale = 1f;
  36. isGameOver = false;
  37. StarterAssetsInputs inputs = FindFirstObjectByType<StarterAssetsInputs>();
  38. if (inputs != null)
  39. {
  40. inputs.cursorInputForLook = true;
  41. inputs.cursorLocked = true;
  42. }
  43. Cursor.lockState = CursorLockMode.Locked;
  44. Cursor.visible = false;
  45. // 2. Logic for Loading vs. Random Spawning
  46. if (MainMenu.shouldLoadSave)
  47. {
  48. Invoke("DelayedLoad", 0.1f);
  49. }
  50. else
  51. {
  52. Debug.Log("GameManager: Fresh Start/Restart. Randomizing spawn...");
  53. TeleportPlayerToRandomGround();
  54. // Reset stats for a fresh start
  55. currentOrbs = 0;
  56. timeRemaining = 300f;
  57. UpdateOrbUI();
  58. UpdateTimerUI();
  59. }
  60. }
  61. void DelayedLoad()
  62. {
  63. SaveSystem saveSys = FindFirstObjectByType<SaveSystem>();
  64. if (saveSys != null) saveSys.LoadGame();
  65. MainMenu.shouldLoadSave = false;
  66. }
  67. void Update()
  68. {
  69. if (isGameOver) return;
  70. if (timeRemaining > 0)
  71. {
  72. timeRemaining -= Time.deltaTime;
  73. UpdateTimerUI();
  74. }
  75. else
  76. {
  77. GameOver(false);
  78. }
  79. }
  80. public void TeleportPlayerToRandomGround()
  81. {
  82. GameObject player = GameObject.FindGameObjectWithTag("Player");
  83. if (player == null) return;
  84. // Use a loop to ensure we find a valid hit (just in case it hits a hole or edge)
  85. bool foundSpot = false;
  86. int attempts = 0;
  87. while (!foundSpot && attempts < 10)
  88. {
  89. attempts++;
  90. // Adjust these ranges to match your Mesh Generator size (e.g., 250x250)
  91. float randomX = Random.Range(-200f, 200f);
  92. float randomZ = Random.Range(-200f, 200f);
  93. Vector3 rayStart = new Vector3(randomX, 150f, randomZ);
  94. if (Physics.Raycast(rayStart, Vector3.down, out RaycastHit hit, 200f))
  95. {
  96. // IMPORTANT: CharacterController MUST be disabled to move the Transform manually
  97. CharacterController cc = player.GetComponent<CharacterController>();
  98. if (cc != null) cc.enabled = false;
  99. player.transform.position = hit.point + Vector3.up * 2f;
  100. if (cc != null) cc.enabled = true;
  101. foundSpot = true;
  102. Debug.Log($"Player spawned on attempt {attempts} at {hit.point}");
  103. }
  104. }
  105. }
  106. public void AddOrb()
  107. {
  108. currentOrbs++;
  109. UpdateOrbUI();
  110. if (currentOrbs >= totalOrbsToWin)
  111. {
  112. GameOver(true);
  113. }
  114. }
  115. // Cleaned up to use the SaveSystem instead of PlayerPrefs
  116. public void SaveProgress()
  117. {
  118. SaveSystem saveSys = FindFirstObjectByType<SaveSystem>();
  119. if (saveSys != null)
  120. {
  121. saveSys.SaveGame();
  122. Debug.Log("GameManager: Progress saved via JSON.");
  123. }
  124. }
  125. public void LoadProgress()
  126. {
  127. SaveSystem saveSys = FindFirstObjectByType<SaveSystem>();
  128. if (saveSys != null)
  129. {
  130. saveSys.LoadGame();
  131. Debug.Log("GameManager: Progress loaded via JSON.");
  132. }
  133. }
  134. public void ClearSave()
  135. {
  136. string path = Application.persistentDataPath + "/savegame.json";
  137. if (System.IO.File.Exists(path)) System.IO.File.Delete(path);
  138. SceneManager.LoadScene(SceneManager.GetActiveScene().name);
  139. }
  140. void UpdateOrbUI()
  141. {
  142. if (orbText != null)
  143. orbText.text = "Orbs: " + currentOrbs + " / " + totalOrbsToWin;
  144. }
  145. void UpdateTimerUI()
  146. {
  147. if (timerText != null)
  148. {
  149. float minutes = Mathf.FloorToInt(timeRemaining / 60);
  150. float seconds = Mathf.FloorToInt(timeRemaining % 60);
  151. timerText.text = string.Format("Time: {0:00}:{1:00}", minutes, seconds);
  152. }
  153. }
  154. public void GameOver(bool won)
  155. {
  156. isGameOver = true;
  157. Time.timeScale = 0f;
  158. gameOverPanel.SetActive(true);
  159. // --- ADD THIS TO STOP CAMERA ---
  160. StarterAssetsInputs inputs = FindFirstObjectByType<StarterAssetsInputs>();
  161. if (inputs != null)
  162. {
  163. inputs.cursorInputForLook = false; // Disables mouse look
  164. inputs.cursorLocked = false; // Unlocks the mouse
  165. }
  166. if (won)
  167. {
  168. gameOverTitleText.text = "VICTORY!";
  169. gameOverTitleText.color = Color.green;
  170. }
  171. else
  172. {
  173. gameOverTitleText.text = "NIGHT HAS FALLEN...";
  174. gameOverTitleText.color = Color.red;
  175. }
  176. Cursor.lockState = CursorLockMode.None;
  177. Cursor.visible = true;
  178. }
  179. public void RestartGame()
  180. {
  181. Time.timeScale = 1f; // Ensure time flows again before loading
  182. SceneManager.LoadScene(SceneManager.GetActiveScene().name);
  183. }
  184. public void LoadMainMenu()
  185. {
  186. Time.timeScale = 1f;
  187. SceneManager.LoadScene("MainMenu");
  188. }
  189. }