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

211 lines
5.5 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CatNoteSpawner : MonoBehaviour
{
[Header("References")]
[SerializeField] private RectTransform noteRoot;
[SerializeField] private RectTransform noteSpawnPoint;
[SerializeField] private RectTransform hitZone;
[Header("Note Prefabs")]
[SerializeField] private RhythmNote pawNotePrefab;
[SerializeField] private RhythmNote fishNotePrefab;
[SerializeField] private RhythmNote musicNotePrefab;
[Header("Spawn Settings")]
[SerializeField] private float normalSpawnInterval = 0.9f;
[SerializeField] private float easySpawnInterval = 1.2f;
[SerializeField] private float normalNoteSpeed = 360f;
[SerializeField] private float easyNoteSpeed = 300f;
[SerializeField] private float firstSpawnDelay = 0.5f;
[SerializeField] private float autoMissDistance = 90f;
[SerializeField] private int maxActiveNotes = 12;
[Header("Debug")]
[SerializeField] private bool showDebugLog = false;
private readonly List<RhythmNote> activeNotes = new List<RhythmNote>();
private Coroutine spawnRoutine;
private bool spawning;
private bool easyMode;
public event Action<RhythmNote> NoteAutoMissed;
public bool IsSpawning => spawning;
public IReadOnlyList<RhythmNote> ActiveNotes => activeNotes;
public void StartSpawn(bool useEasyMode)
{
StopSpawn(false);
easyMode = useEasyMode;
spawning = true;
spawnRoutine = StartCoroutine(SpawnRoutine());
}
public void StopSpawn(bool clearNotes = true)
{
spawning = false;
if (spawnRoutine != null)
{
StopCoroutine(spawnRoutine);
spawnRoutine = null;
}
if (clearNotes)
ClearNotes();
}
private IEnumerator SpawnRoutine()
{
yield return new WaitForSeconds(firstSpawnDelay);
while (spawning)
{
if (activeNotes.Count < maxActiveNotes)
SpawnNote();
yield return new WaitForSeconds(GetSpawnInterval());
}
}
public RhythmNote SpawnNote()
{
RhythmNote prefab = PickNotePrefab();
if (prefab == null)
{
Debug.LogWarning("[CatNoteSpawner] 사용할 노트 프리팹이 없습니다.");
return null;
}
if (noteRoot == null || noteSpawnPoint == null || hitZone == null)
{
Debug.LogWarning("[CatNoteSpawner] NoteRoot, NoteSpawnPoint, HitZone 중 연결되지 않은 값이 있습니다.");
return null;
}
RhythmNote note = Instantiate(prefab, noteRoot);
RectTransform noteRect = note.RectTransform;
noteRect.localScale = Vector3.one;
noteRect.localRotation = Quaternion.identity;
noteRect.localPosition = noteRoot.InverseTransformPoint(noteSpawnPoint.position);
float hitX = noteRoot.InverseTransformPoint(hitZone.position).x;
note.Initialize(GetNoteSpeed(), hitX, autoMissDistance);
note.PassedHitZone += OnNotePassedHitZone;
activeNotes.Add(note);
if (showDebugLog)
Debug.Log("[CatNoteSpawner] Note Spawned");
return note;
}
private RhythmNote PickNotePrefab()
{
List<RhythmNote> availablePrefabs = new List<RhythmNote>();
if (pawNotePrefab != null)
availablePrefabs.Add(pawNotePrefab);
if (fishNotePrefab != null)
availablePrefabs.Add(fishNotePrefab);
if (musicNotePrefab != null)
availablePrefabs.Add(musicNotePrefab);
if (availablePrefabs.Count == 0)
return null;
return availablePrefabs[UnityEngine.Random.Range(0, availablePrefabs.Count)];
}
private float GetSpawnInterval()
{
return easyMode ? easySpawnInterval : normalSpawnInterval;
}
private float GetNoteSpeed()
{
return easyMode ? easyNoteSpeed : normalNoteSpeed;
}
private void OnNotePassedHitZone(RhythmNote note)
{
NoteAutoMissed?.Invoke(note);
RemoveNote(note, true);
}
public RhythmNote GetClosestNote()
{
CleanupNullNotes();
RhythmNote closest = null;
float closestDistance = float.MaxValue;
for (int i = 0; i < activeNotes.Count; i++)
{
RhythmNote note = activeNotes[i];
if (note == null || note.IsJudged)
continue;
float distance = note.GetDistanceToHitZone();
if (distance < closestDistance)
{
closest = note;
closestDistance = distance;
}
}
return closest;
}
public void RemoveNote(RhythmNote note, bool destroyObject)
{
if (note == null)
return;
note.PassedHitZone -= OnNotePassedHitZone;
activeNotes.Remove(note);
if (destroyObject)
note.Remove();
else
note.MarkJudged();
}
public void ClearNotes()
{
for (int i = activeNotes.Count - 1; i >= 0; i--)
{
RhythmNote note = activeNotes[i];
if (note == null)
continue;
note.PassedHitZone -= OnNotePassedHitZone;
note.Remove();
}
activeNotes.Clear();
}
private void CleanupNullNotes()
{
for (int i = activeNotes.Count - 1; i >= 0; i--)
{
if (activeNotes[i] == null)
activeNotes.RemoveAt(i);
}
}
}