using System.Collections;
using System.Collections.Generic;
using UnityEngine; using Game; using Music; using Player;
using UnityEngine.Events;
using UnityEngine.InputSystem;
namespace Game
{
///
/// The GameManager class manages the overall game logic, including game modes, player states,
/// game events, and game-over conditions. It ensures a single instance exists and provides
/// functionality for starting, updating, and ending the game.
///
///
/// Manages the overall game logic, including game modes, player states, game events, and game-over conditions.
///
public class GameManager : MonoBehaviour
{
public static GameManager Instance { get; private set; }
public float time = 180f;
public delegate void GameEvent();
public event GameEvent StartGameEvent;
public event GameEvent EndGameEvent;
public static List players = new List();
public static List playerColors = new List();
public float offset = 1f;
public static bool music = true;
public bool gameOver = false;
public GameTimer gameTimer;
public static Dictionary playerHoldTimes = new Dictionary();
public static GameMode gameMode = GameMode.freeForAll; // loads a default gamemode as a safety net
public static string map = "Platformer With Headroom"; // loads a default map as a safety net
public Vector2 spawnPosition;
public Vector2 obstacleCourseSpawnPosition;
public List hatSpawnPositions = new List();
public Canvas LeaderboardCanvas;
public Canvas TimerCanvas;
public GameObject hatObject;
///
/// Enum representing the different game modes.
///
public enum GameMode
{
freeForAll,
keepAway,
obstacleCourse
}
///
/// Ensures only one instance of GameManager exists.
///
private void Awake()
{
if (Instance == null)
{
Instance = this;
}
else
{
Destroy(gameObject);
}
}
///
/// Starts the game and initializes music.
///
private void Start()
{
if (MusicManager.Instance != null)
{
MusicManager.Instance.StartPlaylist();
}
StartGame();
}
///
/// Continuously updates player hold times during the game.
///
private void Update()
{
if (gameOver) return;
if (gameMode == GameMode.keepAway)
{
foreach (var player in players)
{
float holdTime = GetPlayerHoldTime(player);
UpdatePlayerHoldTime(player, holdTime);
}
}
}
///
/// Retrieves the hold time of a player.
///
/// The player GameObject.
/// The hold time of the player.
private float GetPlayerHoldTime(GameObject player)
{
UseItem useItem = player.GetComponent();
if (useItem != null)
{
return useItem.holdTime;
}
return 0f;
}
///
/// Sets up the game based on the selected game mode.
///
public void StartGame()
{
GameManager.playerHoldTimes.Clear();
if (GameManager.players.Count == 0) return;
StartGameEvent?.Invoke();
print("Starting game with mode: " + gameMode + " and map: " + map);
if (gameMode == GameMode.freeForAll)
{
foreach (GameObject player in players)
{
player.transform.position = spawnPosition + (offset * players.IndexOf(player) * Vector2.right);
player.GetComponent().lives = 5;
}
}
if (gameMode == GameMode.keepAway)
{
if (gameTimer != null)
{
gameTimer.startTime = time;
gameTimer.StartTimer();
}
foreach (GameObject player in players)
{
player.transform.position = spawnPosition + (offset * players.IndexOf(player) * Vector2.right);
player.GetComponent().lives = 0;
}
}
if (gameMode == GameMode.obstacleCourse)
{
foreach (GameObject player in players)
{
player.transform.position = spawnPosition;
player.GetComponent().lives = 0;
}
}
}
///
/// Handles player deaths based on the current game mode.
///
/// The player that died.
public void PlayerDied(Damageable player)
{
UseItem useItem = player.GetComponent();
if (useItem != null)
{
if (gameOver == false)
{
useItem.DropItem();
}
else
{
//return;
}
}
if (gameMode == GameMode.freeForAll)
{
player.lives--;
if (player.lives <= 0 && !gameOver)
{
player.gameObject.SetActive(false);
if (AlivePlayers().Count <= 1)
{
GameOver();
}
}
else
{
RespawnPlayer(player.gameObject);
}
}
if (gameMode == GameMode.keepAway || gameMode == GameMode.obstacleCourse)
{
RespawnPlayer(player.gameObject);
}
}
///
/// Respawns a player at their designated spawn point.
///
/// The player GameObject to respawn.
private void RespawnPlayer(GameObject player)
{
RespawnOnTriggerEnter respawnScript = player.GetComponent();
if (respawnScript != null)
{
player.transform.position = respawnScript.spawnPoint;
player.GetComponent().ResetDamage();
player.GetComponent().Respawn();
}
}
///
/// Ends the game and determines the winner based on the game mode.
///
public void GameOver()
{
if (LeaderboardCanvas == null){}
gameOver = true;
EndGameEvent?.Invoke();
if (LeaderboardCanvas != null)
{
LeaderboardCanvas.gameObject.SetActive(false);
}
if (TimerCanvas != null)
{
TimerCanvas.gameObject.SetActive(false);
}
if (gameMode == GameMode.freeForAll)
{
GameObject winner = AlivePlayers()[0];
print(winner.name + " is the winner");
FindFirstObjectByType().WinScene(winner);
WinScreen.Instance.ShowWinScreen(players.IndexOf(winner) + 1);
FindFirstObjectByType().HideLifeDisplay();
}
if (gameMode == GameMode.keepAway)
{
GameObject winner = null;
float maxHoldTime = -1f;
foreach (var player in GameManager.playerHoldTimes)
{
if (player.Value > maxHoldTime)
{
maxHoldTime = player.Value;
winner = player.Key;
}
}
if (winner != null)
{
print(winner.name + " is the winner with " + maxHoldTime + " seconds!");
var cameraMovement = FindFirstObjectByType();
if (cameraMovement != null)
{
cameraMovement.WinScene(winner);
}
WinScreen.Instance.ShowWinScreen(players.IndexOf(winner) + 1);
var lifeDisplayManager = FindFirstObjectByType();
if (lifeDisplayManager != null)
{
lifeDisplayManager.HideLifeDisplay();
}
StartCoroutine(MoveHatToWinner(winner));
if (hatObject != null)
{
hatObject.SetActive(true);
hatObject.GetComponent().enabled = true;
hatObject.GetComponent().bodyType = RigidbodyType2D.Dynamic;
}
}
}
if (gameMode == GameMode.obstacleCourse)
{
GameObject winner = ObstacleCourse.playerWon;
print(winner.name + " is the winner!");
FindFirstObjectByType().WinScene(winner);
WinScreen.Instance.ShowWinScreen(players.IndexOf(winner) + 1);
FindFirstObjectByType().HideLifeDisplay();
}
}
///
/// Moves the hat to the winner in keep-away mode.
///
/// The winning player GameObject.
/// An IEnumerator for coroutine execution.
private IEnumerator MoveHatToWinner(GameObject winner)
{
while (!winner.GetComponent().IsHoldingItem())
{
hatObject.transform.position = winner.transform.position + Vector3.up * 3 / 2;
winner.GetComponent().PickUpItem(hatObject);
yield return null;
}
}
///
/// Returns a list of all players that are currently alive.
///
/// A list of alive player GameObjects.
public List AlivePlayers()
{
List alivePlayers = new();
foreach (GameObject player in players)
{
if (player.activeInHierarchy) alivePlayers.Add(player);
}
return alivePlayers;
}
///
/// Updates the player's hold time and updates the leaderboard.
///
/// The player GameObject.
/// The hold time to update.
public void UpdatePlayerHoldTime(GameObject player, float holdTime)
{
bool shouldSort = false;
if (playerHoldTimes.ContainsKey(player))
{
if (holdTime > playerHoldTimes[player])
{
shouldSort = true;
}
playerHoldTimes[player] = holdTime;
}
else
{
playerHoldTimes.Add(player, holdTime);
shouldSort = true;
}
LeaderboardManager.Instance.UpdatePlayerHoldTimeText(player, holdTime);
if (shouldSort)
{
LeaderboardManager.Instance.UpdateLeaderboard();
}
}
}
}