diff --git a/Assets/scripts/gamePlay_gameplay/BaseNote.cs b/Assets/scripts/gamePlay_gameplay/BaseNote.cs new file mode 100644 index 00000000..ce7eaea8 --- /dev/null +++ b/Assets/scripts/gamePlay_gameplay/BaseNote.cs @@ -0,0 +1,21 @@ +using UnityEngine; + +public abstract class BaseNote : MonoBehaviour +{ + // 新增:控制音符显示状态 + [System.NonSerialized] // 避免暴露在Inspector + public bool shouldBeVisible = true; + public int TrackIndex { get; protected set; } + public string NoteColor { get; protected set; } + public float Speed { get; protected set; } + protected float hitTime; + + public virtual void Initialize(int trackIndex, string noteColor, float speed, float hitTime) + { + TrackIndex = trackIndex; + NoteColor = noteColor; + Speed = speed; + this.hitTime = hitTime; + } + +} diff --git a/Assets/scripts/gamePlay_gameplay/BaseNote.cs.meta b/Assets/scripts/gamePlay_gameplay/BaseNote.cs.meta new file mode 100644 index 00000000..6f2acf95 --- /dev/null +++ b/Assets/scripts/gamePlay_gameplay/BaseNote.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1685ef287fcd6ee449c4bc269594b792 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/scripts/gamePlay_gameplay/BeatmapManager.cs b/Assets/scripts/gamePlay_gameplay/BeatmapManager.cs new file mode 100644 index 00000000..97c061c7 --- /dev/null +++ b/Assets/scripts/gamePlay_gameplay/BeatmapManager.cs @@ -0,0 +1,131 @@ +using System.IO; +using UnityEngine; +using UnityEngine.UI; + + +public class BeatmapManager : MonoBehaviour + +{ + public Beatmap beatmap; // 褰撳墠璋遍潰鏁版嵁 + + // 闊崇鐢熸垚鍣ㄥ紩鐢 + public NoteSpawner noteSpawner; + + + + // 淇濆瓨璋遍潰鏁版嵁鍒 JSON 鏂囦欢 + //public void SaveBeatmap(string fileName) + //{ + // string json = JsonUtility.ToJson(beatmap, true); // 鏍煎紡鍖 JSON 杈撳嚭 + // File.WriteAllText(Application.dataPath + "/" + fileName, json); + // Debug.Log("璋遍潰宸蹭繚瀛橈細" + Application.dataPath + "/" + fileName); + //} + + // 浠 JSON 鏂囦欢鍔犺浇璋遍潰鏁版嵁 + public void LoadBeatmap(string fileName) + { + string path = Application.streamingAssetsPath + "/" + fileName; + if (File.Exists(path)) + { + string json = File.ReadAllText(path); + beatmap = JsonUtility.FromJson(json); + //Debug.Log("璋遍潰宸插姞杞斤細" + json); + + // 鍦ㄥ姞杞藉悗绔嬪嵆璋冪敤闊崇鐢熸垚 + noteSpawner.LoadBeatmap(beatmap); + + } + else + { + //Debug.LogError("鏂囦欢涓嶅瓨鍦細" + path); + } + } + public void LoadBeatmap(Beatmap loadedBeatmap) + { + beatmap = loadedBeatmap; + //Debug.Log("璋遍潰宸插姞杞斤細" + beatmap.title); + + // 鍦ㄥ姞杞藉悗绔嬪嵆璋冪敤闊崇鐢熸垚 + noteSpawner.LoadBeatmap(beatmap); + } + + //public void LoadBeatmapFromFile(string fileName) + //{ + // string path = Application.persistentDataPath + "/" + fileName; + // if (File.Exists(path)) + // { + // string json = File.ReadAllText(path); + // Beatmap beatmap = JsonUtility.FromJson(json); + // beatmapManager.LoadBeatmap(beatmap); // 浣跨敤 LoadBeatmap 鏂规硶浼犻 Beatmap 瀵硅薄 + // } + // else + // { + // Debug.LogError("鏂囦欢涓嶅瓨鍦細" + path); + // } + //} + + // 鍒涘缓涓涓ず渚嬭氨闈㈠苟淇濆瓨 + //public void CreateSampleBeatmap() + //{ + // beatmap = new Beatmap + // { + // title = "Moonlight Sonata", + // composer = "Ludwig van Beethoven", + // illustrator = "John Doe", + // charter = "Jane Smith", + // beatmapId = "ML-001", + // duration = 120.5f, + // bpm = 128f, + // difficulty = 5, + // difficultyName = "Hard", + // createdDate = System.DateTime.Now.ToString("yyyy-MM-dd"), + // musicFile = "moonlight_sonata.mp3", + // backgroundFile = "moonlight_art.png", + + // tracks = new TrackData[] + // { + // new TrackData { color = "red" }, + // new TrackData { color = "green" }, + // new TrackData { color = "yellow" }, + // new TrackData { color = "purple" }, + // new TrackData { color = "blue" } + // }, + + // notes = new NoteData[] + // { + // new NoteData { trackIndex = 0, time = 1.0f, color = "red", type = "tap", length = 0.0f }, + // new NoteData { trackIndex = 4, time = 2.0f, color = "blue", type = "tap", length = 0.0f }, + // new NoteData { trackIndex = 1, time = 3.5f, color = "green", type = "tap", length = 0.0f }, + // new NoteData { trackIndex = 2, time = 3.5f, color = "yellow", type = "tap", length = 0.0f }, + // new NoteData { trackIndex = 2, time = 3.5f, color = "yellow", type = "tap", length = 0.0f }, + // new NoteData { trackIndex = 3, time = 3.5f, color = "purple", type = "tap", length = 0.0f }, + // } + // }; + + // SaveBeatmap("test_beatmap.json"); + //} + + // 璇诲彇骞跺姞杞藉綋鍓嶈氨闈㈠埌闊崇鐢熸垚鍣 + public void LoadBeatmapFromFile() + { + string path = Application.streamingAssetsPath + "/Emilia_demo.json"; + if (File.Exists(path)) + { + string json = File.ReadAllText(path); + beatmap = JsonUtility.FromJson(json); + noteSpawner.LoadBeatmap(beatmap); + } + else + { + //Debug.LogError("璋遍潰鏂囦欢鏈壘鍒帮紒"); + } + } + + // 鍦 Start() 鏂规硶涓垵濮嬪寲 + void Start() + { + // 杩欓噷鍙互閫夋嫨鍦ㄥ惎鍔ㄦ椂鍒涘缓涓涓ず渚嬭氨闈㈠苟鍔犺浇 + //CreateSampleBeatmap(); // 鍒涘缓骞朵繚瀛樹竴涓ず渚嬭氨闈 + LoadBeatmap("Emilia_demo.json"); // 鍔犺浇骞跺疄渚嬪寲闊崇 + } +} diff --git a/Assets/scripts/gamePlay_gameplay/BeatmapManager.cs.meta b/Assets/scripts/gamePlay_gameplay/BeatmapManager.cs.meta new file mode 100644 index 00000000..df5f3a02 --- /dev/null +++ b/Assets/scripts/gamePlay_gameplay/BeatmapManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c80308880c1feca40bcf476848142e2b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/scripts/gamePlay_gameplay/GameManager.cs b/Assets/scripts/gamePlay_gameplay/GameManager.cs new file mode 100644 index 00000000..9ab41124 --- /dev/null +++ b/Assets/scripts/gamePlay_gameplay/GameManager.cs @@ -0,0 +1,119 @@ +using System.IO; +using System.Linq; +using UnityEngine; +using static HoldNote; +public enum NoteScore +{ + Perfect, + Good, + Okay, + Miss +} + +public class GameManager : MonoBehaviour +{ + public static GameManager Instance { get; private set; } + public BeatmapManager beatmapManager; // 负责加载和管理谱面 + public NoteSpawner noteSpawner; // 音符生成器 + public AudioSource musicSource; // 音乐播放器 + public int CurrentScore { get; private set; } + public int MaxCombo { get; private set; } + public int CurrentCombo { get; private set; } + + // 添加计分方法 + public void AddScore(NoteScore scoreType) + { + // 计分逻辑 + switch (scoreType) + { + case NoteScore.Perfect: + CurrentScore += 100; + Debug.Log("Perfect! +100"); + break; + case NoteScore.Good: + CurrentScore += 80; + Debug.Log("Good! +80"); + break; + case NoteScore.Okay: + CurrentScore += 50; + Debug.Log("Okay +50"); + break; + case NoteScore.Miss: + CurrentCombo = 0; // 连击中断 + Debug.Log("Miss! 连击中断"); + return; // 不增加分数 + } + + // 连击处理 + CurrentCombo++; + if (CurrentCombo > MaxCombo) + MaxCombo = CurrentCombo; + } + private void Awake() + { + if (Instance != null && Instance != this) + { + Destroy(gameObject); + } + else + { + Instance = this; + DontDestroyOnLoad(gameObject); + } + } + void Start() + { + //Debug.Log("GameManager Start() 被调用"); + + // 检查关键组件是否为空 + if (beatmapManager == null) Debug.LogError("beatmapManager 未赋值!"); + if (noteSpawner == null) Debug.LogError("noteSpawner 未赋值!"); + if (musicSource == null) Debug.LogError("musicSource 未赋值!"); + + // 在游戏开始时加载并初始化谱面 + string beatmapFilePath = Path.Combine(Application.streamingAssetsPath, "Emilia_demo.json"); + + if (!File.Exists(beatmapFilePath)) + { + //Debug.LogError($"谱面文件不存在: {beatmapFilePath}"); + return; + } + + string json = File.ReadAllText(beatmapFilePath); + Beatmap beatmap = JsonUtility.FromJson(json); // 解析 JSON 为 Beatmap 对象 + + if (beatmap == null) + { + //Debug.LogError("谱面解析失败,JSON 格式可能错误!"); + return; + } + + beatmapManager.LoadBeatmap(beatmap); // 传递给 BeatmapManager + noteSpawner.LoadBeatmap(beatmap); // 传递给 NoteSpawner + + + // 播放背景音乐 + if (!string.IsNullOrEmpty(beatmap.musicFile)) + { + string musicPath = Path.Combine("song_songIndex/1002001_emilia", Path.GetFileNameWithoutExtension(beatmap.musicFile)); + AudioClip musicClip = Resources.Load(musicPath); + + if (musicClip == null) + { + //Debug.LogError($"音乐文件加载失败,尝试路径: {musicPath}"); + // 列出Resources文件夹下所有音频文件用于调试 + var allAudio = Resources.LoadAll(""); + //Debug.Log("可用音频文件:" + string.Join(", ", allAudio.Select(a => a.name))); + } + else + { + musicSource.clip = musicClip; + musicSource.Play(); + } + } + else + { + //Debug.LogError("谱面中 musicFile 为空!"); + } + } +} diff --git a/Assets/scripts/gamePlay_gameplay/GameManager.cs.meta b/Assets/scripts/gamePlay_gameplay/GameManager.cs.meta new file mode 100644 index 00000000..19270cb6 --- /dev/null +++ b/Assets/scripts/gamePlay_gameplay/GameManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0a3cb3ef9478edd4a8b6718a11a0fc3c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/scripts/gamePlay_gameplay/HoldNote.cs b/Assets/scripts/gamePlay_gameplay/HoldNote.cs new file mode 100644 index 00000000..087f44ff --- /dev/null +++ b/Assets/scripts/gamePlay_gameplay/HoldNote.cs @@ -0,0 +1,444 @@ +锘縰sing System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public enum NoteSegment { None, Start, Middle, End } + +[RequireComponent(typeof(HoldNoteController))] +public class HoldNote : BaseNote +{ + [Header("鍒ゅ畾瀹瑰樊")] + public float startHitWindow = 0.1f; // 璧峰娈靛垽瀹氱獥鍙 + public float endHitWindow = 0.15f; // 缁撴潫娈靛垽瀹氱獥鍙 + public float segmentGracePeriod = 0.05f; // 鍒嗘闂村闄愭椂闂 + + private KeyCode keyToPress = KeyCode.None; + private string noteColor = string.Empty; + private string noteID = string.Empty; + private NoteSegment segment = NoteSegment.None; + + private new float hitTime = 0f; + private float releaseTime = 0f; + private bool hasReleased = true; + private bool hasEnteredLine = false; + + private Coroutine autoReturnCoroutine; + private HoldNoteController controller; + private static Dictionary _holdNoteValidity = new Dictionary(); + + // 鏂板鍙橀噺锛氭寜閿寜浣忔娴 + private bool _isKeyHeld = false; + private float _lastKeyPressTime = 0f; + private const float KEY_CHECK_INTERVAL = 0.05f; + private Coroutine _keyCheckCoroutine; + + public int id; + public int trackIndex; + public float speed; + public float startTime; + public float delay; + public bool isEnd; + public float scheduledEndTime; + public string color; + public KeyCode key; + public string type; // "start", "middle", or "end" + + private void Awake() + { + controller = GetComponent(); + } + + private void OnEnable() + { + ResetState(); + } + + public void Setup(int id, int trackIndex, float speed, float time, float delay, + bool isEnd, float scheduledEnd, string color, KeyCode key, string type) + { + this.id = id; + this.trackIndex = trackIndex; + this.speed = speed; + this.startTime = time; + this.delay = delay; + this.isEnd = isEnd; + this.scheduledEndTime = scheduledEnd; + this.color = color; + this.key = key; + this.type = type; + + this.noteID = id.ToString(); + this.keyToPress = key; + this.noteColor = color; + this.hitTime = time + delay; + this.segment = (delay == 0f) ? NoteSegment.Start : + (isEnd ? NoteSegment.End : NoteSegment.Middle); + this.hasEnteredLine = false; + this.hasReleased = false; + + JudgeManager.Instance?.RegisterNoteReleased(noteID, false); + if (segment == NoteSegment.Start) + JudgeManager.Instance?.RegisterStartJudged(noteID, false); + + if (segment == NoteSegment.End) + JudgeManager.Instance?.RegisterScheduledEndTime(noteID, scheduledEndTime); + + // 濡傛灉鏄捣濮嬫锛屽垵濮嬪寲鐘舵佷负true + if (type == "start") + { + _holdNoteValidity[id] = true; + } + + // 绔嬪嵆妫鏌ユ湁鏁堟 + if (type != "start" && (!_holdNoteValidity.ContainsKey(id) || !_holdNoteValidity[id])) + { + JudgeMiss(); + } + + controller?.SetSpeed(speed); + controller?.SetSegmentDelay(delay); + } + + private void Update() + { + // 妫鏌ラ暱闊崇鏄惁鏈夋晥 + if (!IsHoldNoteValid()) return; + + if (segment == NoteSegment.Start && Input.GetKeyDown(keyToPress)) + { + if (hasEnteredLine) + HandleStart(); + } + else if (segment == NoteSegment.End && Input.GetKeyUp(keyToPress)) + { + HandleEnd(); + } + + // 鏇存柊鎸夐敭鐘舵 + if (segment == NoteSegment.Middle && hasEnteredLine) + { + if (JudgeManager.Instance.IsStartJudged(noteID) && + !JudgeManager.Instance.HasNoteReleased(noteID)) + { + if (!Input.GetKey(keyToPress)) + { + // 涓旀澗寮鎸夐敭锛屽垽瀹氬け璐 + _holdNoteValidity[id] = false; + JudgeMiss(); + } + } + } + } + + private bool IsHoldNoteValid() + { + // 璧峰娈垫绘槸鏈夋晥锛堝洜涓哄畠鍐冲畾鏈夋晥鎬э級 + if (segment == NoteSegment.Start) return true; + + // 鍏朵粬娈垫鏌ユ湁鏁堟 + return _holdNoteValidity.ContainsKey(id) && _holdNoteValidity[id]; + } + + private IEnumerator CheckKeyHold() + { + while (true) + { + if (Input.GetKey(keyToPress)) + { + _isKeyHeld = true; + _lastKeyPressTime = Time.time; + } + else if (_isKeyHeld && Time.time - _lastKeyPressTime > KEY_CHECK_INTERVAL) + { + // 鎸夐敭鏉惧紑瓒呰繃妫鏌ラ棿闅旓紝鍒ゅ畾涓烘澗寮 + _isKeyHeld = false; + if (segment == NoteSegment.Middle || segment == NoteSegment.End) + { + // 涓棿娈垫垨缁撴潫娈垫澗寮鎸夐敭锛屾爣璁伴暱闊崇鏃犳晥 + _holdNoteValidity[id] = false; + JudgeMiss(); + yield break; // 鍋滄妫鏌 + } + } + yield return new WaitForSeconds(KEY_CHECK_INTERVAL); + } + } + + private void OnTriggerEnter2D(Collider2D collision) + { + if (!collision.CompareTag("JudgmentLine")) return; + if (!IsHoldNoteValid()) return; + + if (segment == NoteSegment.Start || segment == NoteSegment.Middle) + { + hasEnteredLine = true; + } + + if (segment == NoteSegment.Middle) + { + //Debug.Log($"[HoldNote] Middle娈佃繘鍏ュ垽瀹氱嚎: color={noteColor}, isStartJudged={JudgeManager.Instance.IsStartJudged(noteID)}, hasReleased={JudgeManager.Instance.HasNoteReleased(noteID)}, isKeyDown={Input.GetKey(keyToPress)}"); + + if (autoReturnCoroutine != null) + StopCoroutine(autoReturnCoroutine); + + autoReturnCoroutine = StartCoroutine(DelayedAutoReturnCheck()); + } + + if (segment == NoteSegment.End) + { + if (autoReturnCoroutine != null) + StopCoroutine(autoReturnCoroutine); + + autoReturnCoroutine = StartCoroutine(DelayedAutoReturnCheck()); + } + } + + private void OnTriggerExit2D(Collider2D collision) + { + if (!collision.CompareTag("JudgmentLine")) return; + if (!IsHoldNoteValid()) return; + + if (segment == NoteSegment.Start) + { + if (!JudgeManager.Instance.IsStartJudged(noteID)) + { + ReturnToPool(); + } + } + if (segment == NoteSegment.Middle) + { + if (!JudgeManager.Instance.IsStartJudged(noteID) || + JudgeManager.Instance.HasNoteReleased(noteID)) + { + //Debug.Log($"[HoldNote] Middle娈电寮鍒ゅ畾绾垮己鍒跺洖鏀: {noteColor}"); + ReturnToPool(); + } + } + else if (segment == NoteSegment.End) + { + if (!JudgeManager.Instance.IsStartJudged(noteID) || JudgeManager.Instance.HasNoteReleased(noteID)) + { + ReturnToPool(); + } + } + } + + private IEnumerator DelayedAutoReturnCheck() + { + yield return null; + + if (!IsHoldNoteValid()) yield break; + + bool isStartJudgedBefore = JudgeManager.Instance.IsStartJudged(noteID); + bool isKeyHeldNow = Input.GetKey(keyToPress); + + //Debug.Log($"[HoldNote] 寤惰繜妫鏌ュ紑濮: noteID={noteID}, color={noteColor}, isStartJudged={isStartJudgedBefore}, isKeyHeld={isKeyHeldNow}"); + + if (!isStartJudgedBefore && isKeyHeldNow) + { + //Debug.Log($"[HoldNote] 寤惰繜鍥炶ˉ Start 鍒ゅ畾瑙﹀彂: {noteColor}"); + HandleStart(); + } + + bool isStartJudged = JudgeManager.Instance.IsStartJudged(noteID); + bool hasReleased = JudgeManager.Instance.HasNoteReleased(noteID); + bool isKeyHeld = Input.GetKey(keyToPress); + + //Debug.Log($"[HoldNote] 寤惰繜纭鐘舵: isStartJudged={isStartJudged}, hasReleased={hasReleased}, isKeyHeld={isKeyHeld}"); + + if (segment == NoteSegment.Middle && isStartJudged && isKeyHeld) + { + float waitTime = Mathf.Max(0f, hitTime - Time.time); + //Debug.Log($"[HoldNote] Middle娈甸氳繃寤惰繜纭锛屽噯澶囩瓑寰呭埌 hitTime 鍥炴敹: {noteColor}, 鍓╀綑鏃堕棿={waitTime:F2}s"); + + yield return new WaitForSeconds(waitTime); + + if (Input.GetKey(keyToPress) && !JudgeManager.Instance.HasNoteReleased(noteID)) + { + //Debug.Log($"[HoldNote] Middle娈靛湪 hitTime 杈炬垚鏉′欢锛屽洖鏀: {noteColor}"); + ReturnToPool(); + } + else + { + //Debug.Log($"[HoldNote] Middle娈靛湪 hitTime 鏉′欢涓嶇锛屼笉鍥炴敹: {noteColor}"); + } + } + else if (segment == NoteSegment.End && !hasReleased) + { + //Debug.Log($"[HoldNote] End娈靛欢杩熸鏌ュ悗浠嶆湭閲婃斁: {noteColor}"); + } + else + { + //Debug.Log($"[HoldNote] DelayedAutoReturnCheck 鏃犻渶澶勭悊: segment={segment}, color={noteColor}"); + } + } + + private void HandleStart() + { + if (!IsHoldNoteValid()) return; + + float pressTime = Time.time; + float offset = Mathf.Abs(pressTime - hitTime); + + if (offset < startHitWindow) + { + //Debug.Log($"[HoldNote] START鍒ゅ畾鎴愬姛锛堝亸宸={offset:F2}绉掞級: {noteColor}"); + JudgeManager.Instance.RegisterStartJudged(noteID, true); + JudgeManager.Instance.RegisterHoldNoteStart(noteID, Time.time); + + // 寮濮嬫寜閿寜浣忔娴 + _isKeyHeld = true; + _lastKeyPressTime = Time.time; + if (_keyCheckCoroutine != null) + StopCoroutine(_keyCheckCoroutine); + _keyCheckCoroutine = StartCoroutine(CheckKeyHold()); + + hasEnteredLine = true; + StartCoroutine(DelayedReturn()); + } + else + { + _holdNoteValidity[id] = false; + //Debug.Log($"[HoldNote] START Miss锛堝亸宸={offset:F2}绉掞紝绐楀彛={startHitWindow:F2}绉掞級: {noteColor}"); + JudgeMiss(); + } + } + + private void JudgeMiss() + { + // 鎵цMiss鍒ゅ畾閫昏緫 + //Debug.Log($"[HoldNote] 鍒ゅ畾涓篗iss: {noteColor}"); + ReturnToPool(); + } + + private IEnumerator DelayedReturn() + { + yield return new WaitForSeconds(0.05f); + ReturnToPool(); + } + + private void HandleEnd() + { + if (!IsHoldNoteValid()) return; + if (!JudgeManager.Instance.IsStartJudged(noteID)) + { + Debug.Log($"[HoldNote] 缁撴潫娈靛垽瀹氬け璐ワ細璧峰娈垫湭姝g‘鍒ゅ畾"); + return; + } + + releaseTime = Time.time; + hasReleased = true; + float diff = Mathf.Abs(releaseTime - scheduledEndTime); + string result = "Miss"; + + if (diff < endHitWindow) + { + result = "Perfect"; + JudgeManager.Instance.RegisterNoteReleased(noteID, true); + ReturnToPool(); + } + else if (diff < endHitWindow * 2f) + { + result = "Good"; + JudgeManager.Instance.RegisterNoteReleased(noteID, true); + ReturnToPool(); + } + + Debug.Log($"[HoldNote] END鍒ゅ畾缁撴灉: {noteColor} {result} (release={releaseTime:F2}, target={scheduledEndTime:F2})"); + } + + private void OnTriggerStay2D(Collider2D collision) + { + if (!collision.CompareTag("JudgmentLine")) return; + if (!IsHoldNoteValid()) return; + + if (segment == NoteSegment.Middle && + JudgeManager.Instance.IsStartJudged(noteID) && + Input.GetKey(keyToPress)) + { + hasEnteredLine = true; + } + } + + private void OnDisable() + { + if (autoReturnCoroutine != null) + { + StopCoroutine(autoReturnCoroutine); + autoReturnCoroutine = null; + } + + if (_keyCheckCoroutine != null) + { + StopCoroutine(_keyCheckCoroutine); + _keyCheckCoroutine = null; + } + + if (segment == NoteSegment.End && + !hasReleased && + !JudgeManager.Instance.HasNoteReleased(noteID) && + keyToPress != KeyCode.None && + !Input.GetKey(keyToPress)) + { + hasReleased = true; + JudgeManager.Instance.RegisterNoteReleased(noteID, true); + //Debug.Log($"[HoldNote] OnDisable琛ュ伩KeyUp: {noteColor}"); + } + + controller?.StopMovement(); + } + + private void ReturnToPool() + { + if (!gameObject.activeSelf) return; + + if (segment == NoteSegment.Start && !hasEnteredLine) + { + //Debug.LogWarning($"[HoldNote] 闃绘鍥炴敹灏氭湭杩涘叆鍒ゅ畾绾跨殑 Start娈: {noteColor}"); + return; + } + + gameObject.SetActive(false); + + if (segment == NoteSegment.Start) + NotePool.Instance.ReturnStartNote(gameObject, noteColor); + else + NotePool.Instance.ReturnHoldNoteSegment(gameObject, noteColor); + } + + public void ResetState() + { + hasReleased = false; + segment = NoteSegment.None; + keyToPress = KeyCode.None; + noteColor = string.Empty; + noteID = string.Empty; + hitTime = 0f; + scheduledEndTime = 0f; + hasEnteredLine = false; + _isKeyHeld = false; + _lastKeyPressTime = 0f; + + if (autoReturnCoroutine != null) + { + StopCoroutine(autoReturnCoroutine); + autoReturnCoroutine = null; + } + + if (_keyCheckCoroutine != null) + { + StopCoroutine(_keyCheckCoroutine); + _keyCheckCoroutine = null; + } + + controller?.StopMovement(); + } + + private void OnDestroy() + { + if (segment == NoteSegment.End && _holdNoteValidity.ContainsKey(id)) + { + _holdNoteValidity.Remove(id); + } + } +} diff --git a/Assets/scripts/gamePlay_gameplay/HoldNote.cs.meta b/Assets/scripts/gamePlay_gameplay/HoldNote.cs.meta new file mode 100644 index 00000000..38a8e0e3 --- /dev/null +++ b/Assets/scripts/gamePlay_gameplay/HoldNote.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 86977693d5a2d364bb086303f60ca1b3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: