repaired the motherfucking hold note problem which troubled us longer than 2 months

added some UI
This commit is contained in:
FloatGaming
2025-08-02 00:28:35 +08:00
parent 373f0511e3
commit 774d3aeb7f
160 changed files with 5472 additions and 841 deletions
+227 -219
View File
@@ -1,5 +1,4 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum NoteSegment { None, Start, Middle, End }
@@ -7,30 +6,19 @@ 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 hitTime = 0f;
private float releaseTime = 0f;
private bool hasReleased = true;
private bool hasEnteredLine = false;
private Coroutine autoReturnCoroutine;
private HoldNoteController controller;
private static Dictionary<int, bool> _holdNoteValidity = new Dictionary<int, bool>();
// 新增变量:按键按住检测
private bool _isKeyHeld = false;
private float _lastKeyPressTime = 0f;
private const float KEY_CHECK_INTERVAL = 0.05f;
private Coroutine _keyCheckCoroutine;
private AnimationController anim;
public int id;
public int trackIndex;
@@ -43,9 +31,16 @@ public class HoldNote : BaseNote
public KeyCode key;
public string type; // "start", "middle", or "end"
private bool isJudged = false; // 分段判定标记,一旦判定(无论成功失败)就设为true,避免重复判定
private bool isHoldActive = false; // 长按有效标记:Start段成功判定且按键未松开
// 新增变量
private bool hasBeenHeldFromStart = false; // 进入判定区时是否已按住 (用于辅助判断,但不再直接阻断判定)
private void Awake()
{
controller = GetComponent<HoldNoteController>();
anim = GetComponent<AnimationController>();
}
private void OnEnable()
@@ -53,6 +48,25 @@ public class HoldNote : BaseNote
ResetState();
}
private void PlayHitAnimation()
{
if (anim != null)
{
// 激活动画效果 GameObject
anim.gameObject.SetActive(true);
anim.PlayDestroyAnimation(noteColor);
// 延迟禁用动画效果 GameObject,确保动画播放完毕
StartCoroutine(DelayedDisableAnimation(anim.gameObject, 0.5f)); // 0.5秒后禁用
}
}
private IEnumerator DelayedDisableAnimation(GameObject animationObject, float delay)
{
yield return new WaitForSeconds(delay);
animationObject.SetActive(false);
}
public void Setup(int id, int trackIndex, float speed, float time, float delay,
bool isEnd, float scheduledEnd, string color, KeyCode key, string type)
{
@@ -72,123 +86,134 @@ public class HoldNote : BaseNote
this.noteColor = color;
this.hitTime = time + delay;
this.segment = (delay == 0f) ? NoteSegment.Start :
(isEnd ? NoteSegment.End : NoteSegment.Middle);
(isEnd ? NoteSegment.End : NoteSegment.Middle);
this.hasEnteredLine = false;
this.hasReleased = false;
// 在 Setup 时注册初始状态
JudgeManager.Instance?.RegisterNoteReleased(noteID, false);
if (segment == NoteSegment.Start)
JudgeManager.Instance?.RegisterStartJudged(noteID, false);
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 (isJudged) return;
if (segment == NoteSegment.Start && Input.GetKeyDown(keyToPress))
// **通用长按状态更新:**
// 只有当isHoldActive为true时才检查松开操作,避免误判
// 且仅在GetKeyUp时更新状态,避免重复操作
if (isHoldActive && Input.GetKeyUp(keyToPress))
{
if (hasEnteredLine)
isHoldActive = false;
Debug.Log($"[HoldNote] 按键 {keyToPress} 松开,长按状态失效。NoteID: {noteID}, Segment: {segment}, Type: {type}");
// 如果是中间段或结束段,且因为松手导致长按失效,可以立即回收
if (segment == NoteSegment.Middle || segment == NoteSegment.End)
{
// 注意:End段的判定在HandleEnd里,松手只是让isHoldActive为false,不代表End段判定已完成
// 如果 End 段的判定窗口还没过,松手后 isHoldActive = falseEnd 段在 OnTriggerExit2D 才会回收
// 或者在 HandleEnd 之前松手导致长按失效,HandleEnd 内部会判定 Miss
}
}
// 如果按键被按下,且Start段已经判定成功,则激活长按状态
// 考虑到玩家可能在Start段通过后瞬间松手再按下,这里需要确保只要Start段判定成功且按键按住,isHoldActive就为true
if (JudgeManager.Instance.IsStartJudged(noteID) && Input.GetKey(keyToPress))
{
isHoldActive = true;
}
// Start段判定
if (segment == NoteSegment.Start && hasEnteredLine)
{
// 在判定窗口内按下按键才触发判定
if (Input.GetKeyDown(keyToPress))
{
HandleStart();
isJudged = true; // 无论成功失败都标记为已判定,避免重复尝试
}
// 如果Start段进入判定区但玩家未按键,且已经错过最佳判定时机,可以考虑Miss并回收
// 这部分逻辑现在放在 OnTriggerExit2D 里处理更合适
}
else if (segment == NoteSegment.End && Input.GetKeyUp(keyToPress))
// Middle段判定:
// 只有当头部已判定、且长按有效(按键持续按住),并且已经到达该Middle段的命中时间点时,才认为该Middle段通过。
// Middle段本身没有独立的按键输入判定,它只是长按的延续。
else if (segment == NoteSegment.Middle
&& JudgeManager.Instance.IsStartJudged(noteID) // 头部必须已判定
&& isHoldActive // 必须处于长按有效状态(按键持续按住)
&& !JudgeManager.Instance.HasNoteReleased(noteID)) // 确保End段还未被判定释放
{
HandleEnd();
}
// 更新按键状态
if (segment == NoteSegment.Middle && hasEnteredLine)
{
if (JudgeManager.Instance.IsStartJudged(noteID) &&
!JudgeManager.Instance.HasNoteReleased(noteID))
// Debug.Log($"[HoldNote] Middle段状态检查: Time.time={Time.time:F2}, hitTime={hitTime:F2}, hasEnteredLine={hasEnteredLine}");
if (Time.time >= hitTime)
{
if (!Input.GetKey(keyToPress))
// 确保它进入了判定线,但在Update中,即使没完全进入,只要时间到了且条件满足,也算通过
// 但是,我们主要希望它在通过判定线后被回收
// 因此,Middle段的回收逻辑更多依赖于DelayedAutoReturnCheck或OnTriggerExit2D
if (hasEnteredLine) // 确保已经进入过判定线,防止音符提前消失
{
// 中途松开按键,判定失败
_holdNoteValidity[id] = false;
JudgeMiss();
Debug.Log($"[HoldNote] Middle段通过 (持续长按): {noteColor}");
PlayHitAnimation();
ReturnToPool();
isJudged = true;
}
}
}
}
private bool IsHoldNoteValid()
{
// 起始段总是有效(因为它决定有效性)
if (segment == NoteSegment.Start) return true;
// 其他段检查有效性
return _holdNoteValidity.ContainsKey(id) && _holdNoteValidity[id];
}
private IEnumerator CheckKeyHold()
{
while (true)
// End段判定
else if (segment == NoteSegment.End
&& JudgeManager.Instance.IsStartJudged(noteID) // 头部必须已判定
&& !JudgeManager.Instance.HasNoteReleased(noteID)) // 确保还未被判定释放
{
if (Input.GetKey(keyToPress))
// 只有当玩家松开按键时才触发End段判定
if (Input.GetKeyUp(keyToPress))
{
_isKeyHeld = true;
_lastKeyPressTime = Time.time;
HandleEnd();
isJudged = true; // 标记为已判定
}
else if (_isKeyHeld && Time.time - _lastKeyPressTime > KEY_CHECK_INTERVAL)
// 如果 End 段已经达到或超过了预定的释放时间 (scheduledEndTime)
// 但玩家仍未松手,且长按状态仍然有效,这可能是玩家按得过长
// 这种情况应该给予一个差的判定或者Miss
else if (Time.time >= scheduledEndTime + 0.1f && isHoldActive) // 给予一点容错时间
{
// 按键松开超过检查间隔,判定为松开
_isKeyHeld = false;
if (segment == NoteSegment.Middle || segment == NoteSegment.End)
{
// 中间段或结束段松开按键,标记长音符无效
_holdNoteValidity[id] = false;
JudgeMiss();
yield break; // 停止检查
}
Debug.Log($"[HoldNote] End段超时未松手,判定为Miss: {noteColor}");
HandleEnd(true); // 传入true表示强制Miss
isJudged = true;
}
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;
}
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)}");
// 进入判定区时记录是否已按住
hasBeenHeldFromStart = Input.GetKey(keyToPress);
Debug.Log($"[HoldNote] Middle段进入判定线: color={noteColor}, isStartJudged={JudgeManager.Instance.IsStartJudged(noteID)}, hasReleased={JudgeManager.Instance.HasNoteReleased(noteID)}, isKeyHeld={Input.GetKey(keyToPress)}, hasBeenHeldFromStart={hasBeenHeldFromStart}");
if (autoReturnCoroutine != null)
StopCoroutine(autoReturnCoroutine);
autoReturnCoroutine = StartCoroutine(DelayedAutoReturnCheck());
// Middle段的延迟回收主要确保即使按住也能在适当时间回收
// 重新思考这里的必要性,可能让Update和OnTriggerExit2D处理更直接
// 暂时移除这里的 DelayedAutoReturnCheck,让 Update 和 OnTriggerExit2D 主导 Middle 段的生命周期
// autoReturnCoroutine = StartCoroutine(DelayedAutoReturnCheck());
}
if (segment == NoteSegment.End)
else if (segment == NoteSegment.End)
{
if (autoReturnCoroutine != null)
StopCoroutine(autoReturnCoroutine);
// End段的延迟回收主要用于处理玩家是否松手,以及超时回收
autoReturnCoroutine = StartCoroutine(DelayedAutoReturnCheck());
}
}
@@ -196,27 +221,45 @@ public class HoldNote : BaseNote
private void OnTriggerExit2D(Collider2D collision)
{
if (!collision.CompareTag("JudgmentLine")) return;
if (!IsHoldNoteValid()) return;
// Start段离开判定线时如果未被判定,则视为Miss并回收
if (segment == NoteSegment.Start)
{
if (!JudgeManager.Instance.IsStartJudged(noteID))
{
Debug.Log($"[HoldNote] Start段离开判定线未判定,强制回收 (Miss): {noteColor}");
// 可以触发一个Miss判定
// JudgeManager.Instance.RecordMiss(noteID);
ReturnToPool();
}
// 如果Start段已判定,那么它会通过DelayedReturn被回收,这里不做额外处理
}
if (segment == NoteSegment.Middle)
// Middle段离开判定线时,如果头部未判定,或者长按已经失效(松手),则回收
else if (segment == NoteSegment.Middle) // 这里修正了拼写错误
{
if (!JudgeManager.Instance.IsStartJudged(noteID) ||
JudgeManager.Instance.HasNoteReleased(noteID))
{
//Debug.Log($"[HoldNote] Middle段离开判定线强制回收: {noteColor}");
ReturnToPool();
}
// 无论Start段是否判定,如果Middle段离开了判定线,就应该回收
// 因为它已经完成了它的“通过”或者“错过”的职责
Debug.Log($"[HoldNote] Middle段离开判定线强制回收: {noteColor}");
ReturnToPool();
}
// End段离开判定线时,如果头部未判定,或者长按已经失效,或者 End 段已经完成判定,则回收
else if (segment == NoteSegment.End)
{
if (!JudgeManager.Instance.IsStartJudged(noteID) || JudgeManager.Instance.HasNoteReleased(noteID))
if (!isJudged) // 如果End段还没有被判定
{
// 如果头部没判,或者长按中断,或者玩家按得过久(已经过了scheduledEndTime很多了)
if (!JudgeManager.Instance.IsStartJudged(noteID) || !isHoldActive || Time.time > scheduledEndTime + 0.15f)
{
Debug.Log($"[HoldNote] End段离开判定线强制回收 (头部未判定或长按中断或超时): {noteColor}");
// 可以在这里强制一个Miss判定,如果之前没触发过
if (!JudgeManager.Instance.HasNoteReleased(noteID)) // 确保没有重复判定
{
HandleEnd(true); // 传入true表示强制Miss
}
ReturnToPool();
}
}
else // 如果End段已经被判定过了,直接回收
{
ReturnToPool();
}
@@ -225,139 +268,110 @@ public class HoldNote : BaseNote
private IEnumerator DelayedAutoReturnCheck()
{
// 这里的 DelayedAutoReturnCheck 主要是针对 End 段的超时未松手检查
// 或者 Start 段的延迟补判(这部分已经移到 Update 和 HandleStart
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)
if (segment == NoteSegment.End)
{
//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))
// 在这里等待,看玩家是否在 scheduledEndTime 之前松手
// 如果到达 scheduledEndTime 玩家仍未松手,且长按有效,则继续等待
// 如果玩家按得过长,可以在 Update 中触发 Miss 判定
float timeToWait = Mathf.Max(0f, scheduledEndTime - Time.time);
if (timeToWait > 0f)
{
//Debug.Log($"[HoldNote] Middle段在 hitTime 达成条件,回收: {noteColor}");
ReturnToPool();
yield return new WaitForSeconds(timeToWait);
}
else
// 到达 scheduledEndTime 后再次检查
// 如果此时玩家仍在按住,并且 Start 段已判定,但 End 段还没被判定释放
// 说明玩家按得太久,判定为 Miss
if (!isJudged && JudgeManager.Instance.IsStartJudged(noteID) && Input.GetKey(keyToPress))
{
//Debug.Log($"[HoldNote] Middle段在 hitTime 条件不符,不回收: {noteColor}");
Debug.Log($"[HoldNote] DelayedAutoReturnCheck (End段) 判定:玩家按得过长,Miss! {noteColor}");
HandleEnd(true); // 强制 Miss
}
}
else if (segment == NoteSegment.End && !hasReleased)
{
//Debug.Log($"[HoldNote] End段延迟检查后仍未释放: {noteColor}");
}
else
{
//Debug.Log($"[HoldNote] DelayedAutoReturnCheck 无需处理: segment={segment}, color={noteColor}");
// 无论如何,如果 End 段已经过去了,但还没回收,就回收
if (!gameObject.activeSelf)
{
yield break; // 修正!使用 yield break 来结束协程
}
ReturnToPool();
}
}
private void HandleStart()
{
if (!IsHoldNoteValid()) return;
float pressTime = Time.time;
float offset = Mathf.Abs(pressTime - hitTime);
if (offset < startHitWindow)
if (offset < 0.1f) // 判定成功
{
//Debug.Log($"[HoldNote] START判定成功(偏差={offset:F2}秒): {noteColor}");
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());
isHoldActive = true; // 成功判定Start,长按状态激活
PlayHitAnimation();
}
else
{
_holdNoteValidity[id] = false;
//Debug.Log($"[HoldNote] START Miss(偏差={offset:F2}秒,窗口={startHitWindow:F2}秒): {noteColor}");
JudgeMiss();
Debug.Log($"[HoldNote] START Miss(偏差={offset:F2}秒): {noteColor}");
JudgeManager.Instance.RegisterStartJudged(noteID, false); // 明确标记未判定
isHoldActive = false; // Start Miss,长按状态不激活
}
}
private void JudgeMiss()
{
// 执行Miss判定逻辑
//Debug.Log($"[HoldNote] 判定为Miss: {noteColor}");
ReturnToPool();
// Start段判定后立即回收,因为它的视觉部分可能只需要短暂显示
StartCoroutine(DelayedReturn());
}
private IEnumerator DelayedReturn()
{
yield return new WaitForSeconds(0.05f);
ReturnToPool();
yield return new WaitForSeconds(0.05f); // 短暂延迟,确保视觉效果或数据更新
if (gameObject.activeSelf) // 确保对象还活跃,防止重复回收
{
ReturnToPool();
}
}
private void HandleEnd()
// 重载 HandleEnd 方法,增加一个强制Miss的参数
private void HandleEnd(bool forceMiss = false)
{
if (!IsHoldNoteValid()) return;
if (!JudgeManager.Instance.IsStartJudged(noteID))
{
Debug.Log($"[HoldNote] 结束段判定失败:起始段未正确判定");
return;
}
releaseTime = Time.time;
hasReleased = true;
float diff = Mathf.Abs(releaseTime - scheduledEndTime);
string result = "Miss";
hasReleased = true; // 标记此音符已被释放
if (diff < endHitWindow)
JudgeManager.Instance.RegisterNoteReleased(noteID, true); // 在 JudgeManager 中注册释放
string result;
// 如果强制Miss,或者头部未判定,或者长按已经中断,则直接判定为Miss
if (forceMiss || !JudgeManager.Instance.IsStartJudged(noteID) || !isHoldActive)
{
result = "Perfect";
JudgeManager.Instance.RegisterNoteReleased(noteID, true);
ReturnToPool();
result = "Miss";
Debug.LogWarning($"[HoldNote] END判定失败({noteColor}):{(forceMiss ? "Miss" : (!JudgeManager.Instance.IsStartJudged(noteID) ? "" : ""))}");
}
else if (diff < endHitWindow * 2f)
else
{
result = "Good";
JudgeManager.Instance.RegisterNoteReleased(noteID, true);
ReturnToPool();
float diff = Mathf.Abs(releaseTime - scheduledEndTime);
// End段的判定规则
if (diff <= 0.05f) // 更严格的完美判定窗口
{
result = "Perfect";
}
else if (diff < 0.15f) // 适当放宽的Great判定
{
result = "Great";
}
else if (diff < 0.3f) // 再次放宽的Good判定
{
result = "Good";
}
else
{
result = "Bad"; // 更大的偏差可能视为Bad或Miss
}
}
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;
}
ReturnToPool(); // 判定后回收
}
private void OnDisable()
@@ -368,21 +382,27 @@ public class HoldNote : BaseNote
autoReturnCoroutine = null;
}
if (_keyCheckCoroutine != null)
{
StopCoroutine(_keyCheckCoroutine);
_keyCheckCoroutine = null;
}
// OnDisable时对End段的补偿处理:
// 如果是End段,且尚未被判定,且Start段已判定,但此时按键已经松开 (通过 !Input.GetKey(keyToPress) 判断)
// 这意味着玩家在离开判定区或因其他原因导致 OnDisable 时松手,但未触发正常的 HandleEnd
if (segment == NoteSegment.End &&
!hasReleased &&
!JudgeManager.Instance.HasNoteReleased(noteID) &&
keyToPress != KeyCode.None &&
!Input.GetKey(keyToPress))
!isJudged && // 尚未判定
JudgeManager.Instance.IsStartJudged(noteID)) // 头部已判定
{
hasReleased = true;
JudgeManager.Instance.RegisterNoteReleased(noteID, true);
//Debug.Log($"[HoldNote] OnDisable补偿KeyUp: {noteColor}");
// 如果按键已经松开,或者长按状态已经失效 (可能因为松开过快)
if (!Input.GetKey(keyToPress) || !isHoldActive)
{
Debug.Log($"[HoldNote] OnDisable补偿End段Miss判定: {noteColor}");
HandleEnd(true); // 强制Miss
isJudged = true; // 标记已判定
}
else if (Input.GetKey(keyToPress))
{
// 如果End段离开了判定区,但是玩家还在按住,这属于按得过长
Debug.Log($"[HoldNote] OnDisableEnd段在离开判定区时玩家仍未松手,判定为Miss: {noteColor}");
HandleEnd(true); // 强制Miss
isJudged = true;
}
}
controller?.StopMovement();
@@ -390,11 +410,11 @@ public class HoldNote : BaseNote
private void ReturnToPool()
{
if (!gameObject.activeSelf) return;
if (!gameObject.activeSelf) return; // 再次检查以防止对象已被禁用
if (segment == NoteSegment.Start && !hasEnteredLine)
{
//Debug.LogWarning($"[HoldNote] 阻止回收尚未进入判定线的 Start段: {noteColor}");
Debug.LogWarning($"[HoldNote] 阻止回收尚未进入判定线的 Start段: {noteColor}");
return;
}
@@ -416,8 +436,10 @@ public class HoldNote : BaseNote
hitTime = 0f;
scheduledEndTime = 0f;
hasEnteredLine = false;
_isKeyHeld = false;
_lastKeyPressTime = 0f;
isJudged = false;
isHoldActive = false; // 重置长按标记
hasBeenHeldFromStart = false; // 重置
// canJudgeThisSegment = false; // 此变量已被移除或不再关键
if (autoReturnCoroutine != null)
{
@@ -425,20 +447,6 @@ public class HoldNote : BaseNote
autoReturnCoroutine = null;
}
if (_keyCheckCoroutine != null)
{
StopCoroutine(_keyCheckCoroutine);
_keyCheckCoroutine = null;
}
controller?.StopMovement();
}
private void OnDestroy()
{
if (segment == NoteSegment.End && _holdNoteValidity.ContainsKey(id))
{
_holdNoteValidity.Remove(id);
}
}
}
}