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

Unity编辑器中NOTES按键序列偶发失效问题技术咨询

问题描述
  • 在Unity编辑器运行游戏时,按下N-O-T-E-S按键序列可打开笔记窗口;在窗口内输入/close或/exit命令可关闭窗口
  • 关闭窗口后再次输入该序列,无法立即打开窗口,需多次尝试才生效
  • 首次输入序列时,小写按键也可触发;未点击窗口获取焦点时,重复输入序列可正常切换窗口显隐状态
  • 问题仅在点击窗口获取焦点、输入内容并通过命令关闭窗口后出现
相关实现代码
using UnityEngine;

public class GameNotes : MonoBehaviour
{
    private bool showNotes = false;
    private string notesContent = "";
    private static string filePath = "GameNotes.txt";
    private int keySequenceIndex = 0;
    private KeyCode[] keySequence = new KeyCode[] { KeyCode.N, KeyCode.O, KeyCode.T, KeyCode.E, KeyCode.S };

    private void Update()
    {
        if (Input.GetKeyDown(keySequence[keySequenceIndex]))
        {
            keySequenceIndex++;
            if (keySequenceIndex >= keySequence.Length)
            {
                showNotes = !showNotes;
                keySequenceIndex = 0;
                if (showNotes) LoadNotes();
            }
        }
        else if (Input.anyKeyDown)
        {
            keySequenceIndex = 0;
        }
    }

    private void OnGUI()
    {
        if (showNotes)
        {
            GUI.BeginGroup(new Rect(Screen.width / 2 - 150, Screen.height / 2 - 100, 300, 200));
            GUI.Box(new Rect(0, 0, 300, 200), "Notes");
            string prevContent = notesContent;
            notesContent = GUI.TextArea(new Rect(10, 20, 280, 170), notesContent);
            GUI.EndGroup();

            // Detect special commands
            ProcessCommands();

            // Save notes if there's any change and no command was detected
            if (prevContent != notesContent && showNotes)
            {
                SaveNotes();
            }
        }
    }

    private void ProcessCommands()
    {
        if (notesContent.Contains("/close") || notesContent.Contains("/exit"))
        {
            showNotes = false;
            // Remove the command text from the notes
            notesContent = notesContent.Replace("/close", "").Replace("/exit", "").Trim();
            SaveNotes();
        }
    }

    private void SaveNotes()
    {
        System.IO.File.WriteAllText(filePath, notesContent);
    }

    private void LoadNotes()
    {
        if (System.IO.File.Exists(filePath))
        {
            notesContent = System.IO.File.ReadAllText(filePath);
        }
    }
}
问题分析与修复方案

问题根源

  1. GUI焦点拦截按键:当GUI.TextArea获取焦点时,输入的按键会被Unity的GUI系统优先处理,导致Update中的序列检测逻辑无法正确捕获按键,甚至打乱keySequenceIndex的状态
  2. 命令关闭时未重置序列索引:通过/close或/exit关闭窗口时,keySequenceIndex没有被重置,后续输入序列时会从之前的中断位置开始,无法触发完整序列
  3. Input.anyKeyDown的误触发:GUI输入时的按键会触发Input.anyKeyDown,直接重置keySequenceIndex,导致序列检测被频繁打断

修复代码

using UnityEngine;

public class GameNotes : MonoBehaviour
{
    private bool showNotes = false;
    private string notesContent = "";
    private static string filePath = "GameNotes.txt";
    private int keySequenceIndex = 0;
    private KeyCode[] keySequence = new KeyCode[] { KeyCode.N, KeyCode.O, KeyCode.T, KeyCode.E, KeyCode.S };

    private void Update()
    {
        // 窗口显示时,若TextArea有焦点则跳过序列检测
        if (showNotes && GUI.GetNameOfFocusedControl() == "NotesTextArea")
        {
            return;
        }

        if (Input.GetKeyDown(keySequence[keySequenceIndex]))
        {
            keySequenceIndex++;
            if (keySequenceIndex >= keySequence.Length)
            {
                showNotes = !showNotes;
                keySequenceIndex = 0;
                if (showNotes) LoadNotes();
            }
        }
        else if (Input.anyKeyDown)
        {
            keySequenceIndex = 0;
        }
    }

    private void OnGUI()
    {
        if (showNotes)
        {
            GUI.BeginGroup(new Rect(Screen.width / 2 - 150, Screen.height / 2 - 100, 300, 200));
            GUI.Box(new Rect(0, 0, 300, 200), "Notes");
            string prevContent = notesContent;
            // 给TextArea设置名称,用于检测焦点
            GUI.SetNextControlName("NotesTextArea");
            notesContent = GUI.TextArea(new Rect(10, 20, 280, 170), notesContent);
            GUI.EndGroup();

            // 先处理命令再判断保存
            bool wasShowing = showNotes;
            ProcessCommands();

            // 仅在未触发命令且内容变化时保存
            if (prevContent != notesContent && wasShowing && showNotes)
            {
                SaveNotes();
            }
        }
    }

    private void ProcessCommands()
    {
        if (notesContent.Contains("/close") || notesContent.Contains("/exit"))
        {
            showNotes = false;
            // 重置序列索引,确保下次输入能正常触发
            keySequenceIndex = 0;
            // 移除命令文本并保存
            notesContent = notesContent.Replace("/close", "").Replace("/exit", "").Trim();
            SaveNotes();
        }
    }

    private void SaveNotes()
    {
        System.IO.File.WriteAllText(filePath, notesContent);
    }

    private void LoadNotes()
    {
        if (System.IO.File.Exists(filePath))
        {
            notesContent = System.IO.File.ReadAllText(filePath);
        }
    }
}

修复要点

  • 给GUI.TextArea设置名称,通过GUI.GetNameOfFocusedControl()判断焦点状态,在焦点存在时跳过序列检测
  • 在ProcessCommands中关闭窗口时,强制重置keySequenceIndex = 0,确保下次序列检测从初始位置开始
  • 调整保存逻辑,避免触发命令时重复保存

内容的提问来源于stack exchange,提问作者Daniel Lip

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 05:05:05