Unity C# Input.GetKeyDown单次按键触发多次问题排查与解决
问题根因
这个问题和枚举搭配switch的写法完全无关,核心原因是Unity的输入生命周期和脚本执行顺序规则:
Input.GetKeyDown(KeyCode.A)的返回值在同一帧的所有Update执行周期内都是true,不会因为中途修改了游戏状态就重置为false- 如果你的
GameController脚本的执行顺序早于Attacking脚本,同一帧内会先执行GameController的Update:检测到A键按下,把状态改成PlayerAttackUnit;之后执行Attacking的Update时,读到的已经是新状态,同时Input.GetKeyDown(KeyCode.A)还是返回true,就会直接触发对应逻辑。
解决方案
给你三个可落地的方案,按实现复杂度从低到高选择即可:
方案1:调整脚本执行顺序(最简单快速)
让GameController的Update晚于所有业务逻辑脚本执行,保证同一帧内所有脚本都是按修改前的状态跑逻辑,状态修改后下一帧才生效:
- 打开Unity编辑器的
Edit > Project Settings > Script Execution Order - 点击
+号,选择GameController脚本,把它的排序值调到大于默认的0(比如设为100,值越大执行越晚) - 保存设置即可,不需要修改任何业务代码。
方案2:增加输入消费标记(灵活度高)
新增全局标记判断当前帧的输入是否已经被消费,避免同一输入被多次触发:
修改GameController代码
public class GameController : MonoBehaviour { public static GameState CurrentState; // 新增输入消费标记 public static bool InputConsumed; void Start() { CurrentState = GameState.PlayerSelectTile; } void Update() { // 每帧开头重置消费标记 InputConsumed = false; switch (CurrentState) { case GameState.PlayerSelectAction: // 检测输入前先判断是否已被消费 if (!InputConsumed && Input.GetKeyDown(KeyCode.A)) { CurrentState = GameState.PlayerAttackUnit; Debug.Log("Game State is Player Attack Unit"); // 标记输入已被消费 InputConsumed = true; } break; // 其余case逻辑保持不变 } } }
修改Attacking脚本的输入检测逻辑
case GameState.PlayerAttackUnit: // 检测输入前先判断是否已被消费 if (!GameController.InputConsumed && Input.GetKeyDown(KeyCode.A)) { // 原有攻击逻辑保持不变 } break;
方案3:统一输入管理(架构更规范)
所有输入检测统一只在GameController一个脚本中实现,其他业务脚本不要直接读取Input,改由状态切换后发送事件、或者GameController主动调用业务脚本方法的方式触发逻辑,从根源上避免输入被多次检测的问题。
内容的提问来源于stack exchange,提问作者denil87
相关产品推荐
相关产品推荐

