324 lines
7.3 KiB
C#
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);
|
|
}
|
|
}
|