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

Unity自定义手柄键盘输入系统跨脚本通信失效问题求助

问题原因与修复方案

常见异常原因

  • GameManager未正确挂载:初始场景中没有激活的GameObject挂载GameManager脚本,或存在多个挂载GameManager的物体,导致单例GM未完成初始化就被访问,触发空引用异常
  • 脚本执行顺序错误:Unity默认脚本执行顺序不固定,Controlsscript的Start()方法可能早于GameManager的Awake()执行,此时GM还未赋值
  • 代码笔误:Controlsscript的Start()方法中,MenuKey和ItemKey的赋值错误调用了restart属性,属于修改变量名时未同步修改的疏漏
  • GameManager所在物体异常:GameManager挂载的物体存在父物体、或被后续逻辑销毁,导致单例实例丢失

修复方法

  1. 检查GameManager挂载配置
    确认首加载场景中仅存在一个激活的、无父物体的GameObject挂载GameManager脚本,避免实例被意外销毁或重复生成。

  2. 固定脚本执行顺序
    打开Unity编辑器的 Edit > Project Settings > Script Execution Order,将GameManager添加到优先级列表,调整其执行顺序高于Controlsscript,确保Awake()先于所有访问单例的脚本执行。

  3. 修正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();
  1. 增加单例鲁棒性与空保护

优化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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 23:45:04