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); } } }
问题分析与修复方案
问题根源
- GUI焦点拦截按键:当
GUI.TextArea获取焦点时,输入的按键会被Unity的GUI系统优先处理,导致Update中的序列检测逻辑无法正确捕获按键,甚至打乱keySequenceIndex的状态 - 命令关闭时未重置序列索引:通过
/close或/exit关闭窗口时,keySequenceIndex没有被重置,后续输入序列时会从之前的中断位置开始,无法触发完整序列 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
相关产品推荐
相关产品推荐

