You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)时:

  1. 初始notePassCount=2,按下按键后,第一个noteID=2的音符触发条件,调用NoteHit让notePassCount递增为3;
  2. 同一帧内第二个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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 21:00:41