Files
WhaleAdventure_VR/Assets/My project/RhythmGame/Scripts/RhythmGameManager.cs
skrwns304@gmail.com b1e85a5b89 2026-06-19 UI, UI로직
2026-06-19 14:27:40 +09:00

324 lines
7.3 KiB
C#

using UnityEngine;
using UnityEngine.Events;
public class RhythmGameManager : MonoBehaviour
{
public enum ResultType
{
Perfect,
Good,
Miss
}
[Header("References")]
[SerializeField] private RhythmGameUI ui;
[SerializeField] private CatNoteSpawner noteSpawner;
[SerializeField] private RhythmHapticManager haptic;
[Header("Game Settings")]
[SerializeField] private string songTitle = "고양이 합창단의 노래";
[SerializeField] private bool startOnAwake = false;
[SerializeField] private bool useFishBonusOnStart = false;
[Header("Rules")]
[SerializeField] private int requiredScore = 1000;
[SerializeField] private int allowedMisses = 5;
[SerializeField] private int perfectScore = 150;
[SerializeField] private int goodScore = 80;
[Header("Judgment Distance")]
[Tooltip("HitZone 중심과 노트 중심의 거리입니다. 값이 작을수록 판정이 어려워집니다.")]
[SerializeField] private float perfectDistance = 35f;
[SerializeField] private float goodDistance = 75f;
[SerializeField] private float missRemoveDistance = 120f;
[Header("Events")]
public UnityEvent onGameStarted;
public UnityEvent onGameSuccess;
public UnityEvent onGameFailed;
public UnityEvent onPerfect;
public UnityEvent onGood;
public UnityEvent onMiss;
[Header("Debug")]
[SerializeField] private bool showDebugLog = true;
private int score;
private int combo;
private int missCount;
private bool activeGame;
private bool fishBonusActive;
public int Score => score;
public int Combo => combo;
public int MissCount => missCount;
public bool IsPlaying => activeGame;
public bool FishBonusActive => fishBonusActive;
private void OnEnable()
{
if (noteSpawner != null)
noteSpawner.NoteAutoMissed += HandleAutoMiss;
}
private void OnDisable()
{
if (noteSpawner != null)
noteSpawner.NoteAutoMissed -= HandleAutoMiss;
}
private void Start()
{
if (startOnAwake)
StartGame(useFishBonusOnStart);
else
InitializeIdleState();
}
private void InitializeIdleState()
{
score = 0;
combo = 0;
missCount = 0;
activeGame = false;
if (ui != null)
{
ui.InitializeUI(songTitle);
ui.ShowFishBonus(false);
}
if (noteSpawner != null)
noteSpawner.StopSpawn(true);
}
public void StartGame()
{
StartGame(false);
}
public void StartGameWithFishBonus()
{
StartGame(true);
}
public void StartGame(bool useFishBonus)
{
score = 0;
combo = 0;
missCount = 0;
fishBonusActive = useFishBonus;
activeGame = true;
if (ui != null)
{
ui.InitializeUI(songTitle);
ui.ShowFishBonus(fishBonusActive);
ui.UpdateScore(score);
ui.UpdateCombo(combo);
}
if (noteSpawner != null)
noteSpawner.StartSpawn(fishBonusActive);
onGameStarted?.Invoke();
if (showDebugLog)
Debug.Log("[RhythmGameManager] 리듬게임 시작");
}
public void SubmitHit()
{
if (!activeGame)
return;
if (noteSpawner == null)
{
RegisterMiss(null, false);
return;
}
RhythmNote closestNote = noteSpawner.GetClosestNote();
if (closestNote == null)
{
RegisterMiss(null, false);
return;
}
float distance = closestNote.GetDistanceToHitZone();
ResultType result = EvaluateResult(distance);
switch (result)
{
case ResultType.Perfect:
RegisterPerfect(closestNote);
break;
case ResultType.Good:
RegisterGood(closestNote);
break;
case ResultType.Miss:
bool removeNote = distance <= missRemoveDistance;
RegisterMiss(closestNote, removeNote);
break;
}
CheckGameEnd();
}
private ResultType EvaluateResult(float distance)
{
if (distance <= perfectDistance)
return ResultType.Perfect;
if (distance <= goodDistance)
return ResultType.Good;
return ResultType.Miss;
}
private void RegisterPerfect(RhythmNote note)
{
score += perfectScore;
combo++;
if (noteSpawner != null)
noteSpawner.RemoveNote(note, true);
if (ui != null)
{
ui.UpdateScore(score);
ui.UpdateCombo(combo);
ui.ShowJudgment("완벽!");
}
if (haptic != null)
haptic.Perfect();
onPerfect?.Invoke();
if (showDebugLog)
Debug.Log("[RhythmGameManager] Perfect");
}
private void RegisterGood(RhythmNote note)
{
score += goodScore;
combo++;
if (noteSpawner != null)
noteSpawner.RemoveNote(note, true);
if (ui != null)
{
ui.UpdateScore(score);
ui.UpdateCombo(combo);
ui.ShowJudgment("좋아!");
}
if (haptic != null)
haptic.Good();
onGood?.Invoke();
if (showDebugLog)
Debug.Log("[RhythmGameManager] Good");
}
private void RegisterMiss(RhythmNote note, bool removeNote)
{
missCount++;
combo = 0;
if (removeNote && noteSpawner != null && note != null)
noteSpawner.RemoveNote(note, true);
if (ui != null)
{
ui.UpdateCombo(combo);
ui.ShowJudgment("실패!");
}
if (haptic != null)
haptic.Miss();
onMiss?.Invoke();
if (showDebugLog)
Debug.Log($"[RhythmGameManager] Miss {missCount}/{allowedMisses}");
}
private void HandleAutoMiss(RhythmNote note)
{
if (!activeGame)
return;
RegisterMiss(note, false);
CheckGameEnd();
}
private void CheckGameEnd()
{
if (!activeGame)
return;
if (score >= requiredScore)
{
GameSuccess();
return;
}
if (missCount >= allowedMisses)
{
GameFail();
}
}
private void GameSuccess()
{
activeGame = false;
if (noteSpawner != null)
noteSpawner.StopSpawn(true);
if (ui != null)
ui.ShowFinalResult("리듬 성공!");
onGameSuccess?.Invoke();
if (showDebugLog)
Debug.Log("[RhythmGameManager] 리듬게임 성공");
}
private void GameFail()
{
activeGame = false;
if (noteSpawner != null)
noteSpawner.StopSpawn(true);
if (ui != null)
ui.ShowFinalResult("리듬 실패!");
onGameFailed?.Invoke();
if (showDebugLog)
Debug.Log("[RhythmGameManager] 리듬게임 실패");
}
public void StopGame()
{
activeGame = false;
if (noteSpawner != null)
noteSpawner.StopSpawn(true);
}
public void ResetGame()
{
StartGame(fishBonusActive);
}
}