GameManager.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. using UnityEngine;
  2. using System.Collections;
  3. /// <summary>
  4. /// Central manager for game state, death, and respawn logic.
  5. /// Handles party wipe detection, death sequence, and respawn coordination.
  6. /// </summary>
  7. public class GameManager : MonoBehaviour
  8. {
  9. public static GameManager Instance { get; private set; }
  10. [Header("References")]
  11. public TeamCohesionManager cohesionManager;
  12. public CheckpointSystem checkpointSystem;
  13. public DeathScreenUI deathScreenUI;
  14. public GridMovement playerMovement;
  15. [Header("Death & Respawn Settings")]
  16. public float deathDelay = 2f;
  17. public float respawnFadeTime = 1f;
  18. public bool resetMonstersOnRespawn = false;
  19. [Header("Optional Penalties")]
  20. public bool applyGoldPenalty = false;
  21. public float goldPenaltyPercent = 0f;
  22. private bool isPlayerDead = false;
  23. private CanvasGroup fadeCanvasGroup;
  24. #region Initialization
  25. private void Awake()
  26. {
  27. if (Instance != null && Instance != this)
  28. {
  29. Destroy(gameObject);
  30. return;
  31. }
  32. Instance = this;
  33. CreateFadeOverlay();
  34. }
  35. private void Start()
  36. {
  37. FindReferences();
  38. ValidateSetup();
  39. }
  40. private void FindReferences()
  41. {
  42. if (cohesionManager == null)
  43. cohesionManager = FindFirstObjectByType<TeamCohesionManager>();
  44. if (checkpointSystem == null)
  45. checkpointSystem = FindFirstObjectByType<CheckpointSystem>();
  46. if (deathScreenUI == null)
  47. deathScreenUI = FindFirstObjectByType<DeathScreenUI>();
  48. if (playerMovement == null)
  49. playerMovement = FindFirstObjectByType<GridMovement>();
  50. }
  51. private void ValidateSetup()
  52. {
  53. bool hasAllReferences = cohesionManager != null && checkpointSystem != null &&
  54. deathScreenUI != null && playerMovement != null;
  55. if (!hasAllReferences)
  56. {
  57. Debug.LogError("[GameManager] Missing references! Respawn system may not work.");
  58. }
  59. }
  60. #endregion
  61. #region Death & Respawn
  62. public void OnPartyWiped()
  63. {
  64. if (isPlayerDead) return;
  65. isPlayerDead = true;
  66. StartCoroutine(HandleDeathSequence());
  67. }
  68. private IEnumerator HandleDeathSequence()
  69. {
  70. if (playerMovement != null)
  71. playerMovement.enabled = false;
  72. StopAllMonsterAttacks();
  73. yield return new WaitForSeconds(deathDelay);
  74. yield return StartCoroutine(FadeToBlack(respawnFadeTime));
  75. if (deathScreenUI != null)
  76. {
  77. deathScreenUI.Show();
  78. }
  79. else
  80. {
  81. Debug.LogWarning("[GameManager] Death Screen UI not found, auto-respawning");
  82. RespawnParty();
  83. }
  84. }
  85. public void RespawnParty()
  86. {
  87. StartCoroutine(RespawnSequence());
  88. }
  89. private IEnumerator RespawnSequence()
  90. {
  91. if (deathScreenUI != null)
  92. deathScreenUI.Hide();
  93. yield return new WaitForSeconds(0.2f);
  94. if (checkpointSystem != null)
  95. {
  96. checkpointSystem.LoadCheckpoint();
  97. }
  98. else
  99. {
  100. Debug.LogWarning("[GameManager] CheckpointSystem not found, basic respawn");
  101. BasicRespawn();
  102. }
  103. if (applyGoldPenalty && goldPenaltyPercent > 0)
  104. ApplyGoldPenalty();
  105. if (resetMonstersOnRespawn)
  106. ResetMonsters();
  107. yield return new WaitForSeconds(0.3f);
  108. yield return StartCoroutine(FadeFromBlack(respawnFadeTime));
  109. if (playerMovement != null)
  110. playerMovement.enabled = true;
  111. isPlayerDead = false;
  112. }
  113. private void BasicRespawn()
  114. {
  115. if (cohesionManager == null || cohesionManager.groupMembers == null) return;
  116. foreach (var character in cohesionManager.groupMembers)
  117. {
  118. character.currentHP = character.maxHP;
  119. character.currentFatigue = character.maxFatigue;
  120. character.currentMana = character.maxMana;
  121. UIUpdater.Instance?.UpdateCharacterHP(character);
  122. UIUpdater.Instance?.UpdateCharacterFatigue(character);
  123. }
  124. }
  125. #endregion
  126. #region Monster Management
  127. private void StopAllMonsterAttacks()
  128. {
  129. MonsterFormationGroup[] monsterGroups = FindObjectsByType<MonsterFormationGroup>(FindObjectsSortMode.None);
  130. foreach (var group in monsterGroups)
  131. {
  132. group.StopAllCoroutines();
  133. group.isChasing = false;
  134. group.hasDetectedPlayer = false;
  135. foreach (var monster in group.frontRow)
  136. {
  137. if (monster != null)
  138. monster.StopMove();
  139. }
  140. foreach (var monster in group.backRow)
  141. {
  142. if (monster != null)
  143. monster.StopMove();
  144. }
  145. }
  146. }
  147. private void ResetMonsters()
  148. {
  149. MonsterFormationGroup[] monsterGroups = FindObjectsByType<MonsterFormationGroup>(FindObjectsSortMode.None);
  150. foreach (var group in monsterGroups)
  151. {
  152. group.StopAllCoroutines();
  153. group.isChasing = false;
  154. group.hasDetectedPlayer = false;
  155. }
  156. }
  157. private void ApplyGoldPenalty()
  158. {
  159. // TODO: Implement gold penalty when currency system exists
  160. }
  161. #endregion
  162. #region Fade Effects
  163. private void CreateFadeOverlay()
  164. {
  165. GameObject fadeObj = new GameObject("FadeOverlay");
  166. fadeObj.transform.SetParent(transform);
  167. Canvas canvas = fadeObj.AddComponent<Canvas>();
  168. canvas.renderMode = RenderMode.ScreenSpaceOverlay;
  169. canvas.sortingOrder = 100;
  170. fadeCanvasGroup = fadeObj.AddComponent<CanvasGroup>();
  171. fadeCanvasGroup.alpha = 0f;
  172. fadeCanvasGroup.interactable = false;
  173. fadeCanvasGroup.blocksRaycasts = false;
  174. GameObject panel = new GameObject("BlackPanel");
  175. panel.transform.SetParent(fadeObj.transform, false);
  176. UnityEngine.UI.Image image = panel.AddComponent<UnityEngine.UI.Image>();
  177. image.color = Color.black;
  178. RectTransform rect = panel.GetComponent<RectTransform>();
  179. rect.anchorMin = Vector2.zero;
  180. rect.anchorMax = Vector2.one;
  181. rect.sizeDelta = Vector2.zero;
  182. }
  183. private IEnumerator FadeToBlack(float duration)
  184. {
  185. float elapsed = 0f;
  186. while (elapsed < duration)
  187. {
  188. elapsed += Time.deltaTime;
  189. fadeCanvasGroup.alpha = Mathf.Lerp(0f, 1f, elapsed / duration);
  190. yield return null;
  191. }
  192. fadeCanvasGroup.alpha = 1f;
  193. }
  194. private IEnumerator FadeFromBlack(float duration)
  195. {
  196. float elapsed = 0f;
  197. while (elapsed < duration)
  198. {
  199. elapsed += Time.deltaTime;
  200. fadeCanvasGroup.alpha = Mathf.Lerp(1f, 0f, elapsed / duration);
  201. yield return null;
  202. }
  203. fadeCanvasGroup.alpha = 0f;
  204. }
  205. #endregion
  206. #region Public API
  207. public bool IsPlayerDead() => isPlayerDead;
  208. #endregion
  209. }