Files
bansonic_beta_main/Assets/scripts/gamePlay_gameplay/NoteSpawner.cs
T

248 lines
8.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using UnityEngine;
using System.Collections;
using TMPro;
public class NoteSpawner : MonoBehaviour
{
public NotePool notePool; // 引用 NotePool
public Transform[] spawnPoints; // 对应轨道的生成点
public GameObject[] notePrefabs; // 短音符预制体
public TextMeshProUGUI globalGameTime;
// 长音符预制体数组(分别为 start, middle, end
public GameObject[] holdNoteStartPrefabs;
public GameObject[] holdNoteMiddlePrefabs;
public GameObject[] holdNoteEndPrefabs;
public float spawnOffset = 0f; // 生成音符时的时间偏移量
public float bpm;
private HoldNote _holdNoteComponentCache; // 缓存HoldNote组件
private Beatmap beatmap;
private float startTime; // 存储歌曲开始时间
private bool isSpawning = false;
private void Awake()
{
// 初始化HoldNote组件缓存
if (holdNoteStartPrefabs != null && holdNoteStartPrefabs.Length > 0)
{
_holdNoteComponentCache = holdNoteStartPrefabs[0].GetComponent<HoldNote>();
}
}
public void LoadBeatmap(Beatmap loadedBeatmap)
{
if (isSpawning) return;
isSpawning = true;
beatmap = loadedBeatmap;
if (beatmap == null)
{
//Debug.LogError("加载的谱面为空!");
return;
}
bpm = beatmap.bpm;
startTime = Time.time;
//Debug.Log($"歌曲开始时间: {startTime}");
StartCoroutine(SpawnNotes());
}
private IEnumerator SpawnNotes()
{
if (beatmap == null || beatmap.notes == null)
{
//Debug.LogError("谱面数据为空!");
isSpawning = false;
yield break;
}
foreach (NoteData note in beatmap.notes)
{
float travelTime = (60f / bpm) * 4;
float spawnTime = note.time - travelTime;
float delay = spawnTime - (Time.time - startTime) + spawnOffset;
Debug.Log($"delay: {delay}");
if (delay > 0)
yield return new WaitForSeconds(delay);
if (note.type == "hold")
{
SpawnHoldNote(note);
}
else
{
SpawnNote(note);
}
}
isSpawning = false;
}
// 生成短音符
public void SpawnNote(NoteData noteData)
{
if (noteData.trackIndex < 0 || noteData.trackIndex >= spawnPoints.Length)
{
//Debug.LogError("轨道索引超出范围!");
return;
}
KeyCode key = KeyBindingManager.GetKeyForColor(noteData.color);
if (key == KeyCode.None)
{
//Debug.LogError($"未找到颜色 {noteData.color} 对应的按键!请检查 KeyBindingManager 是否正确初始化。");
return;
}
//Debug.Log($"生成短音符:颜色={noteData.color}, 按键={key}, 轨道={noteData.trackIndex}");
GameObject note = notePool.GetNote(noteData.color);
if (note == null)
{
//Debug.LogError("对象池返回了一个空音符!");
return;
}
note.transform.position = spawnPoints[noteData.trackIndex].position;
note.transform.rotation = Quaternion.identity;
Note noteScript = note.GetComponent<Note>();
if (noteScript != null)
{
float noteSpawnTime = Time.time;
noteScript.Setup(key, noteData.trackIndex, CalculateSpeed(), noteData.time, noteData.color);
//Debug.Log($"到达时间:{noteSpawnTime + (60f / bpm) * 4}");
}
else
{
//Debug.LogError("音符预制体缺少 Note 组件!");
}
}
public void SpawnHoldNote(NoteData noteData)
{
if (noteData == null)
{
//Debug.LogError("NoteData为空!");
return;
}
if (noteData.trackIndex < 0 || noteData.trackIndex >= spawnPoints.Length)
{
//Debug.LogError("轨道索引超出范围!");
return;
}
KeyCode key = KeyBindingManager.GetKeyForColor(noteData.color);
if (key == KeyCode.None)
{
//Debug.LogError($"未找到颜色 {noteData.color} 对应的按键!");
return;
}
if (string.IsNullOrEmpty(noteData.color))
{
//Debug.LogError("[NoteSpawner] noteData.color 为空,无法生成音符!");
return;
}
//Debug.Log($"生成时间:{Time.time}");
//Debug.Log($"生成长音符:颜色={noteData.color}, 按键={key}, 轨道={noteData.trackIndex}");
float segmentInterval = (60f / bpm) / 4f;
int segmentCount = Mathf.CeilToInt(noteData.length / segmentInterval);
Transform spawnPoint = spawnPoints[noteData.trackIndex];
float scheduledEndTime = noteData.time + noteData.length;
// 生成唯一ID
int holdNoteId = GenerateHoldNoteId();
// 生成 Start 段
GameObject startObj = notePool.GetStartNote(noteData.color);
if (startObj == null)
{
//Debug.LogError("对象池返回空 hold note start");
return;
}
SetupHoldNoteSegment(startObj, spawnPoint, holdNoteId, noteData, key, 0f, false, "start", scheduledEndTime);
// 生成 Middle 和 End 段
for (int i = 1; i < segmentCount; i++)
{
float segmentDelay = i * segmentInterval;
bool isEndSegment = (i == segmentCount - 1);
string partType = isEndSegment ? "end" : "middle";
// 应用gracePeriod
segmentDelay = CalculateSegmentDelay(segmentDelay, isEndSegment);
GameObject segObj = notePool.GetHoldNoteSegment(noteData.color);
if (segObj == null)
{
Debug.LogError("对象池返回空 hold note 片段!");
continue;
}
SetupHoldNoteSegment(segObj, spawnPoint, holdNoteId, noteData, key, segmentDelay, isEndSegment, partType, scheduledEndTime);
}
}
private int GenerateHoldNoteId()
{
return System.Guid.NewGuid().GetHashCode() & 0x7FFFFFFF; // 确保生成正数ID
}
private float CalculateSegmentDelay(float delay, bool isEndSegment)
{
if (!isEndSegment && _holdNoteComponentCache != null)
{
delay -= _holdNoteComponentCache.segmentGracePeriod;
return Mathf.Max(delay, 0);
}
return delay;
}
private void SetupHoldNoteSegment(GameObject noteObj, Transform spawnPoint, int holdNoteId,
NoteData noteData, KeyCode key, float delay,
bool isEnd, string type, float scheduledEndTime)
{
noteObj.transform.position = spawnPoint.position;
noteObj.transform.rotation = Quaternion.identity;
HoldNote holdNote = noteObj.GetComponent<HoldNote>();
if (holdNote != null)
{
holdNote.Setup(holdNoteId, noteData.trackIndex, CalculateSpeed(),
noteData.time, delay, isEnd, scheduledEndTime,
noteData.color, key, type);
// 注册结束时间
if (isEnd)
{
JudgeManager.Instance.RegisterScheduledEndTime(holdNoteId.ToString(), scheduledEndTime);
}
}
else
{
//Debug.LogError("长音符片段缺少 HoldNote 组件!");
}
}
private float CalculateSpeed()
{
float noteTravelTime = (60f / bpm) * 4;
return 10.75f / noteTravelTime;
}
public void ResetAllHoldNotes()
{
JudgeManager.Instance.ResetAllHoldNotes();
//Debug.Log("重置所有长音符状态");
}
}