211 lines
5.5 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|