Unity自定义手柄键盘输入系统跨脚本通信失效问题求助
问题原因与修复方案
常见异常原因
- GameManager未正确挂载:初始场景中没有激活的GameObject挂载GameManager脚本,或存在多个挂载GameManager的物体,导致单例
GM未完成初始化就被访问,触发空引用异常 - 脚本执行顺序错误:Unity默认脚本执行顺序不固定,Controlsscript的
Start()方法可能早于GameManager的Awake()执行,此时GM还未赋值 - 代码笔误:Controlsscript的
Start()方法中,MenuKey和ItemKey的赋值错误调用了restart属性,属于修改变量名时未同步修改的疏漏 - GameManager所在物体异常:GameManager挂载的物体存在父物体、或被后续逻辑销毁,导致单例实例丢失
修复方法
检查GameManager挂载配置
确认首加载场景中仅存在一个激活的、无父物体的GameObject挂载GameManager脚本,避免实例被意外销毁或重复生成。固定脚本执行顺序
打开Unity编辑器的Edit > Project Settings > Script Execution Order,将GameManager添加到优先级列表,调整其执行顺序高于Controlsscript,确保Awake()先于所有访问单例的脚本执行。修正Controlsscript代码笔误
将Start()方法中错误的赋值逻辑替换为正确内容:
// 原错误代码 // if (menuPanel.GetChild(i).name == "MenuKey") // menuPanel.GetChild(i).GetComponentInChildren<Text>().text = GameManager.GM.restart.ToString(); // if (menuPanel.GetChild(i).name == "ItemKey") // menuPanel.GetChild(i).GetComponentInChildren<Text>().text = GameManager.GM.restart.ToString(); // 替换为正确代码 if (menuPanel.GetChild(i).name == "MenuKey") menuPanel.GetChild(i).GetComponentInChildren<Text>().text = GameManager.GM.menu.ToString(); if (menuPanel.GetChild(i).name == "ItemKey") menuPanel.GetChild(i).GetComponentInChildren<Text>().text = GameManager.GM.item.ToString();
- 增加单例鲁棒性与空保护
优化GameManager单例实现,支持自动初始化:
public class GameManager : MonoBehaviour { // 修改单例实现为懒加载模式 public static GameManager GM { get { if(_gm == null) { GameObject gmObj = new GameObject("AutoGenerated_GameManager"); _gm = gmObj.AddComponent<GameManager>(); DontDestroyOnLoad(gmObj); } return _gm; } } private static GameManager _gm; // 其他属性不变 public KeyCode drift { get; set; } public KeyCode forward { get; set; } public KeyCode backward { get; set; } public KeyCode left { get; set; } public KeyCode right { get; set; } public KeyCode restart { get; set; } public KeyCode menu { get; set; } public KeyCode item { get; set; } void Awake() { if (_gm == null) { DontDestroyOnLoad(gameObject); _gm = this; } else if (_gm != this) { Destroy(gameObject); return; // 多余实例直接终止后续逻辑执行 } // 原有按键初始化逻辑不变 drift = (KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("driftKey", "Space")); forward = (KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("forwardKey", "W")); backward = (KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("backwardKey", "S")); left = (KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("leftKey", "A")); right = (KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("rightKey", "D")); restart = (KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("restartKey", "R")); menu = (KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("menuKey", "M")); item = (KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("itemKey", "LeftControl")); } }
在访问单例的位置增加非空判断,提前暴露问题:
在Controlsscript的Start()方法最开头添加判断:
void Start() { if(GameManager.GM == null) { Debug.LogError("GameManager单例初始化失败,请检查场景配置"); return; } // 原有逻辑不变 }
内容的提问来源于stack exchange,提问作者andAnother1
相关产品推荐
相关产品推荐

