Files
PacManUdon/Assets/Scripts/GameManager.cs
2025-12-26 16:05:03 +01:00

501 lines
15 KiB
C#

#define RECORDING_DEMO
namespace Marro.PacManUdon
{
using System;
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
using VRC.SDK3.Components;
using VRC.Udon.Common.Interfaces;
using VRC.SDK3.Data;
public partial class GameManager : UdonSharpBehaviour
{
[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] public StatusDisplay statusDisplay; // This one is public so other scripts can write to the debug display
[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 GameObject recorder;
[Header("Game settings")]
[SerializeField] private int startingExtraLives = 3;
[SerializeField] private int scoreToExtraLife = 10000;
[Tooltip("Override amount of pellets needed to clear stage, set to -1 to disable.")]
[SerializeField] private int pelletCountOverride = -1;
private Maze maze;
private VRCObjectPool pelletPool;
private Intermission2Pole intermission2Pole;
private Animator mazeSpriteAnimator;
private int pelletCountTotal;
private int pelletCountRemaining;
private GameObject[] attractScreenElements;
private GameObject[] intermissionScreenElements;
[UdonSynced, FieldChangeCallback(nameof(GameState))] private PacManGameState gameState;
[UdonSynced, FieldChangeCallback(nameof(Score))] private int score;
[UdonSynced, FieldChangeCallback(nameof(Level))] private int level;
[UdonSynced, FieldChangeCallback(nameof(HighScore))] private int highScore;
[UdonSynced, FieldChangeCallback(nameof(ExtraLives))] 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];
pelletPool = maze.pelletContainer.GetComponent<VRCObjectPool>();
mazeSpriteAnimator = maze.mazeSprite.GetComponent<Animator>();
intermission2Pole = intermissionScreenElements[4].GetComponent<Intermission2Pole>();
ghostManager.Initialize(maze.ghostTargets, pacMan, this);
pacMan.Initialize(playerInput, pelletPool, this);
bonusFruit.Initialize();
pelletManager.Initialize(pelletPool);
statusDisplay.Initialize();
playerInput.Initialize(this);
soundManager.Initialize();
intermission2Pole.Initialize(this, ghostManager.Ghosts[0]);
HideEverything();
SetScore(0);
SetHighScore(0);
SetLevel(0);
StartAttractMode();
}
public void FixedUpdate()
{
TimeSequenceUpdate(Time.deltaTime);
}
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!");
TakeOwnership();
StartTimeSequence(PacManTimeSequence.StartNewGame);
}
public void SkipLevelButtonPressed()
{
if (Networking.IsOwner(gameObject))
{
Debug.Log($"{gameObject} Skip level button pressed!");
StartTimeSequence(PacManTimeSequence.BoardClear);
TimeSequenceSkipToNextStep();
}
}
public void StartDemoButtonPressed()
{
if (Networking.IsOwner(gameObject))
{
Debug.Log($"{gameObject} Start demo button pressed!");
StartTimeSequence(PacManTimeSequence.Intermission1);
}
}
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!");
if (Networking.IsOwner(gameObject))
{
pelletCountTotal = pelletPool.Pool.Length;
pelletCountRemaining = pelletCountTotal;
ghostManager.SetPelletsRemaining(pelletCountRemaining);
ghostManager.NewLevel();
pelletManager.RestoreAllPellets();
if (pelletCountOverride > 0)
{
pelletCountRemaining = pelletCountOverride;
}
}
mazeSpriteAnimator.SetBool("Blinking", false);
}
private void RestartLevel()
{
Debug.Log($"{gameObject} (Re)started level!");
// SetInGameComponentVisibility(true);
ghostManager.Reset();
pacMan.Reset();
bonusFruit.Despawn();
soundManager.Reset();
pelletManager.SetPowerPelletsBlink(false);
}
public void GotPellet(bool addScore = true)
{
pelletCountRemaining--;
if (addScore) AddScore(10);
ghostManager.PelletConsumed();
soundManager.PlayPelletSound();
soundManager.UpdatePelletCount(pelletCountRemaining);
int pelletsConsumed = pelletCountTotal - pelletCountRemaining;
if (pelletCountRemaining <= 0)
{
StartTimeSequence(PacManTimeSequence.BoardClear);
}
else if (pelletsConsumed == 70 || pelletsConsumed == 170)
{
bonusFruit.Spawn();
}
}
public void GotPowerPellet()
{
if (gameState == PacManGameState.AttractMode)
{
TimeSequenceSkipToNextStep();
return;
}
GotPellet(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)
{
if (gameState == PacManGameState.AttractMode)
{
TimeSequenceSkipToNextStep();
return;
}
AddScore(scoreBonus);
StartTimeSequence(PacManTimeSequence.GhostCaught);
pacMan.HideUntilUnfrozen();
}
public void PacManCaught()
{
StartTimeSequence(PacManTimeSequence.PacManCaught);
}
public void NoGhostsScared()
{
soundManager.SetGhostBlue(false);
}
public void NoGhostsRetreating()
{
soundManager.SetGhostRetreat(false);
}
public void Intermission2PoleUpdate()
{
TimeSequenceSkipToNextStep();
}
void BoardClearAnimation()
{
ghostManager.gameObject.SetActive(false);
mazeSpriteAnimator.SetBool("Blinking", true);
}
private void HideEverything()
{
SetMazeActive(false);
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 SetMazeActive(bool active)
{
maze.gameObject.SetActive(active);
}
void SetPelletsActive(bool active)
{
pelletPool.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;
if (Networking.IsOwner(gameObject))
{
RequestSerialization();
}
}
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);
RequestSerialization();
}
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()
{
if (!Networking.IsOwner(gameObject))
{
return;
}
// Debug.Log($"{gameObject} Decremented lives from {extraLives} to {extraLives - 1}");
SetExtraLives(extraLives - 1);
}
void IncrementLives()
{
if (!Networking.IsOwner(gameObject))
{
return;
}
// 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);
}
}
void TakeOwnership()
{
Networking.SetOwner(Networking.LocalPlayer, gameObject);
Networking.SetOwner(Networking.LocalPlayer, pacMan.gameObject);
Networking.SetOwner(Networking.LocalPlayer, pelletPool.gameObject);
ghostManager.SetOwner(Networking.LocalPlayer);
}
public int ExtraLives
{
set
{
SetExtraLives(value);
}
get => extraLives;
}
public PacManGameState GameState
{
set
{
SetGameState(value);
}
get => gameState;
}
public bool GhostsScared
{
set
{
}
get => GhostsScared;
}
public int Score
{
set
{
SetScore(value);
}
get => score;
}
public int HighScore
{
set
{
SetHighScore(value);
}
get => score;
}
public int Level
{
set
{
SetLevel(value);
}
get => level;
}
}
}