using UdonSharp; using UnityEngine; namespace Marro.PacManUdon { public partial class GameManager : SyncedObject { [Header("Static game components")] [SerializeField] private Maze[] mazes; [SerializeField] private PacMan pacMan; [SerializeField] private GhostManager ghostManager; [SerializeField] private BonusFruit bonusFruit; [SerializeField] private PelletManager pelletManager; [SerializeField] private StatusDisplay statusDisplay; [SerializeField] private PelletManager attractScreen; [SerializeField] private GameObject intermissionScreen; [SerializeField] private GameObject pressStartButtonScreen; [SerializeField] private PlayerInput playerInput; [SerializeField] private Animator demo; [SerializeField] private SoundManager soundManager; [SerializeField] private NetworkManager networkManagerSetup; [SerializeField] private GameObject recorder; [Header("Game settings")] [SerializeField] private int startingExtraLives = 3; [SerializeField] private int scoreToExtraLife = 10000; private Maze maze; private Intermission2Pole intermission2Pole; private Animator mazeSpriteAnimator; private GameObject[] attractScreenElements; private GameObject[] intermissionScreenElements; private PacManGameState gameState; private int score; private int level; private int highScore; private int extraLives; public void Start() { attractScreenElements = new GameObject[attractScreen.transform.childCount]; for (int i = 0; i < attractScreenElements.Length; i++) { attractScreenElements[i] = attractScreen.transform.GetChild(i).gameObject; } intermissionScreenElements = new GameObject[intermissionScreen.transform.childCount]; for (int i = 0; i < intermissionScreenElements.Length; i++) { intermissionScreenElements[i] = intermissionScreen.transform.GetChild(i).gameObject; } maze = mazes[0]; mazeSpriteAnimator = maze.mazeSprite.GetComponent(); intermission2Pole = intermissionScreenElements[4].GetComponent(); networkManager.Initialize(); ghostManager.Initialize(maze.ghostStarts, maze.ghostTargets, pacMan, pelletManager, this); pacMan.Initialize(playerInput, maze.pacManStart, this); bonusFruit.Initialize(); pelletManager.Initialize(); statusDisplay.Initialize(); playerInput.Initialize(this); soundManager.Initialize(); intermission2Pole.Initialize(this, ghostManager.Ghosts[0]); HideEverything(); SetScore(0); SetHighScore(0); SetLevel(0); StartAttractMode(); } public override void SyncedUpdate() { TimeSequenceUpdate(networkManager.SyncedDeltaTime); } public void JoystickGrabbed() { if (gameState == PacManGameState.AttractMode || gameState == PacManGameState.AttractModeDemo) StartTimeSequence(PacManTimeSequence.WaitForStart); } public void JoystickReleased() { if (gameState == PacManGameState.WaitForStart) StartTimeSequence(PacManTimeSequence.WaitForStartTimeout); } public void ResetButtonPressed() { Debug.Log($"{gameObject} Reset button was pressed!"); Start(); } public void StartGameButtonPressed() { Debug.Log($"{gameObject} Start Game Button was pressed!"); if (networkManager.IsOwner) { networkManager.SendEventNow(NetworkEventType.StartGameButtonPressed); } StartTimeSequence(PacManTimeSequence.StartNewGame); } private void StartAttractMode() { // #if RECORDING_DEMO // recorder.gameObject.SetActive(true); StartTimeSequence(PacManTimeSequence.AttractScreenIntroduction); // #else // SetGameState(PacManGameState.AttractMode); // HideEverything(); // demo.gameObject.SetActive(true); // #endif } private void InitializeNewGame() { Debug.Log($"{gameObject} Started new game!"); SetScore(0); SetExtraLives(startingExtraLives); SetLevel(1); } private void InitializeLevel() { Debug.Log($"{gameObject} New level started!"); pelletManager.RestoreAllPellets(); ghostManager.NewLevel(); mazeSpriteAnimator.SetBool("Blinking", false); } private void RestartLevel(bool afterLifeLost = false) { Debug.Log($"{gameObject} (Re)started level!"); // SetInGameComponentVisibility(true); ghostManager.RestartLevel(afterLifeLost); pacMan.Reset(); bonusFruit.Despawn(); soundManager.Reset(); pelletManager.SetPowerPelletsBlink(false); } private void PrepareForCutscene() { HideEverything(); RestartLevel(); SetFrozen(true); } public void GotPellet(Pellet pellet, bool addScore = true) { var pelletCollectedCount = pelletManager.PelletCollected(pellet); if (addScore) AddScore(10); ghostManager.PelletConsumed(); soundManager.PlayPelletSound(); var pelletCountRemaining = pelletManager.PelletCount - pelletCollectedCount; soundManager.UpdatePelletCount(pelletCountRemaining); if (pelletCountRemaining <= 0) { StartTimeSequence(PacManTimeSequence.BoardClear); } else if (pelletCollectedCount == 70 || pelletCollectedCount == 170) { bonusFruit.Spawn(); } } public void GotPowerPellet(Pellet pellet) { Debug.Log($"{gameObject} GotPowerPellet"); if (gameState == PacManGameState.AttractMode) { TimeSequenceSkipToNextStep(); return; } GotPellet(pellet, addScore: false); AddScore(50); ghostManager.SetPowerPellet(true); pacMan.SetPowerPellet(true); soundManager.SetGhostBlue(true); } public void EndPowerPellet() { ghostManager.SetPowerPellet(false); pacMan.SetPowerPellet(false); soundManager.SetGhostBlue(false); } public void GotFruit() { AddScore(bonusFruit.Collected()); soundManager.PlayFruitSound(); } public void GhostCaught(int scoreBonus) { Debug.Log($"{gameObject} GhostCaught"); if (gameState == PacManGameState.AttractMode) { TimeSequenceSkipToNextStep(); return; } AddScore(scoreBonus); StartTimeSequence(PacManTimeSequence.GhostCaught); pacMan.HideUntilUnfrozen(); } public void PacManCaught() { return; StartTimeSequence(PacManTimeSequence.PacManCaught); } public void NoGhostsScared() { soundManager.SetGhostBlue(false); } public void NoGhostsRetreating() { soundManager.SetGhostRetreat(false); } public void Intermission2PoleUpdate() { Debug.Log($"{gameObject} Intermission2PoleUpdate"); TimeSequenceSkipToNextStep(); } void BoardClearAnimation() { ghostManager.gameObject.SetActive(false); mazeSpriteAnimator.SetBool("Blinking", true); } private void HideEverything() { SetPelletsActive(false); SetMazeVisible(false); SetGhostsActive(false); SetPacManActive(false); SetPressStartButtonScreenVisible(false); SetIntermissionScreenVisible(false); statusDisplay.SetGameOverTextVisible(false); statusDisplay.SetExtraLivesDisplayVisible(false); statusDisplay.SetLevelDisplayVisible(false); statusDisplay.SetPlayer1TextVisible(false); statusDisplay.SetReadyTextVisible(false); demo.gameObject.SetActive(false); } void SetPelletsActive(bool active) { pelletManager.gameObject.SetActive(active); } void SetMazeVisible(bool visible) { mazeSpriteAnimator.SetBool("Hidden", !visible); } void SetGhostsActive(bool active) { ghostManager.SetActive(active); } void SetPacManActive(bool active) { pacMan.SetActive(active); } void SetPressStartButtonScreenVisible(bool visible) { pressStartButtonScreen.SetActive(visible); } void SetIntermissionScreenVisible(bool visible) { intermissionScreen.SetActive(visible); } void SetGameState(PacManGameState newGameState) { // Debug.Log($"{gameObject} State transitioning from {gameState} to {newGameState}"); gameState = newGameState; } private void IncrementLevel() { SetLevel(level + 1); } private void SetLevel(int level) { this.level = level; pacMan.SetLevel(level); ghostManager.SetLevel(level); statusDisplay.SetLevel(level); bonusFruit.SetFruitType(PacManConstants.GetFruitTypeForLevel(level)); } void AddScore(int score) { if (gameState == PacManGameState.AttractMode || gameState == PacManGameState.AttractModeDemo) { return; } if (this.score < scoreToExtraLife && this.score + score >= scoreToExtraLife) { BonusLifeReached(); } SetScore(this.score + score); } void SetScore(int score) { this.score = score; statusDisplay.Set1UPScore(score); if (score > highScore) { highScore = score; statusDisplay.SetHighScore(score); } } void SetHighScore(int highScore) { this.highScore = highScore; statusDisplay.SetHighScore(score); } public void DecrementLives() { // Debug.Log($"{gameObject} Decremented lives from {extraLives} to {extraLives - 1}"); SetExtraLives(extraLives - 1); } void IncrementLives() { // Debug.Log($"{gameObject} Incremented lives from {extraLives} to {extraLives + 1}"); SetExtraLives(extraLives + 1); } void SetExtraLives(int extraLives) { // Debug.Log($"{gameObject} Set lives from {this.extraLives} to {extraLives}"); this.extraLives = extraLives; statusDisplay.SetExtraLives(extraLives); } void BonusLifeReached() { IncrementLives(); soundManager.PlayExtraLifeSound(); } public void SetFrozen(bool frozen, bool ghostIgnoreIfCaught = false, bool ghostKeepAnimating = false) { // Debug.Log($"{gameObject} Set Frozen: {frozen}"); pacMan.SetFrozen(frozen); bonusFruit.SetFrozen(frozen); ghostManager.SetFrozen(frozen, ignoreIfCaught: ghostIgnoreIfCaught); if (!frozen) { pelletManager.SetPowerPelletsBlink(true); } } public override void CollectSyncedData(byte[] data, ref int offset, NetworkEventType eventType) { //data[offset++] = new byte[] { NetworkManager.Int32ToByte((int)gameState) }; //data[offset++] = BitConverter.GetBytes(currentlyInTimeSequence); //data[offset++] = new byte[] { NetworkManager.Int32ToByte((int)currentTimeSequence) }; //data[offset++] = BitConverter.GetBytes(timeSequenceSecondsPassed); } public override bool WriteSyncedData(byte[] data, ref int offset, NetworkEventType eventType) { if (eventType == NetworkEventType.StartGameButtonPressed) { StartGameButtonPressed(); } //SetGameState((PacManGameState)data[offset++]); //var currentlyInTimeSequence = BitConverter.ToBoolean(data, offset++); //var currentTimeSequence = (PacManTimeSequence)data[offset++]; //var timeSequenceSecondsPassed = BitConverter.ToSingle(data, offset); //offset += 4; //TimeSequenceSyncWithRemote(currentlyInTimeSequence, currentTimeSequence, timeSequenceSecondsPassed); return true; } public PacManGameState GameState => gameState; public int Level => level; } }