Unity开发Cytus类音游:重叠音符触发异常问题求助
问题描述
开发类似《Cytus》的节奏游戏时遇到重叠音符异常:当判定线同时覆盖两个音符,按下按键会导致两个音符同时消失。已为每个音符分配从1开始递增的noteID,并在GameManager中用notePassCount标记下一个需响应的音符ID,预期仅ID匹配的音符消失,但实际notePassCount递增后所有重叠音符都会消失。
相关代码
GameManager.cs
public void NoteHit() { Debug.Log("Hit!"); notePassCount++; } public void NoteMissed() { Debug.Log("Missed!"); notePassCount++; }
NoteScript.cs
void Update() { if (Input.GetKeyDown(KeyCode.LeftArrow)) { if (canBePressed == true && noteNumbering.noteID == GameManager.instance.notePassCount) { ParentObject.SetActive(false); GameManager.instance.NoteHit(); } } } public void OnTriggerEnter2D(Collider2D other) { if (other.tag == "SecondNeedle") { canBePressed = true; } } public void OnTriggerExit2D(Collider2D other) { if (other.tag == "SecondNeedle" && ParentObject.activeSelf) { canBePressed = false; GameManager.instance.NoteMissed(); ParentObject.SetActive(false); } }
NoteNumbering.cs
public class NoteNumbering : MonoBehaviour { public int noteID; void Start() { } void Update() { } public void SetNoteID(int id) { noteID = id; } }
每个音符均挂载NoteScript.cs和NoteNumbering.cs脚本。
问题原因
Unity中所有脚本的Update方法会在同一帧内依次执行。当两个音符同时处于判定区(canBePressed=true)且noteID为连续值(如2和3)时:
- 初始
notePassCount=2,按下按键后,第一个noteID=2的音符触发条件,调用NoteHit让notePassCount递增为3; - 同一帧内第二个
noteID=3的音符执行Update时,此时notePassCount已经是3,满足noteID == notePassCount的条件,因此也会触发隐藏和NoteHit调用,最终导致两个音符同时消失。
解决方案
在GameManager中添加状态锁,阻止同一帧内多次触发命中/判定逻辑,确保每次按键仅处理一个音符:
修改后的GameManager.cs
private bool isProcessing = false; public void NoteHit() { if (isProcessing) return; isProcessing = true; Debug.Log("Hit!"); notePassCount++; // 下一帧重置状态锁,避免影响后续输入 StartCoroutine(ResetProcessingState()); } public void NoteMissed() { if (isProcessing) return; isProcessing = true; Debug.Log("Missed!"); notePassCount++; StartCoroutine(ResetProcessingState()); } private IEnumerator ResetProcessingState() { yield return null; isProcessing = false; }
修改后的NoteScript.cs
在触发条件中增加状态锁判断,确保仅在未处理判定时执行:
void Update() { if (Input.GetKeyDown(KeyCode.LeftArrow)) { if (canBePressed == true && noteNumbering.noteID == GameManager.instance.notePassCount && !GameManager.instance.isProcessing) { ParentObject.SetActive(false); GameManager.instance.NoteHit(); } } } public void OnTriggerExit2D(Collider2D other) { if (other.tag == "SecondNeedle" && ParentObject.activeSelf && !GameManager.instance.isProcessing) { canBePressed = false; GameManager.instance.NoteMissed(); ParentObject.SetActive(false); } }
额外优化建议
- 将
isProcessing设为private,通过公共属性访问,避免外部直接修改; - 如果有多条判定线/不同按键,可针对不同按键或判定区设置独立的状态锁,避免互相干扰;
- 可考虑将音符命中的检测逻辑移至
GameManager统一处理(如通过事件或列表管理当前可判定的音符),减少每个音符的独立判断,提升逻辑可控性。
内容的提问来源于stack exchange,提问作者user24880186
相关产品推荐
相关产品推荐

