2026-06-19 UI, UI로직
This commit is contained in:
323
Assets/My project/RhythmGame/Scripts/RhythmGameManager.cs
Normal file
323
Assets/My project/RhythmGame/Scripts/RhythmGameManager.cs
Normal file
@@ -0,0 +1,323 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user