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