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

Unity跨场景调用方法异常:切换场景后无法访问当前场景对象

问题描述

我在场景中有一个设置了DontDestroyOnLoad的GameObject,尝试在场景切换后调用LobbyManager中的方法。调用onEnterLobbySucceed方法时,直接执行内部的_onEnterLobbySucceed无法访问当前场景对象,但通过Update函数中检测标记的方式执行该方法却能正常工作。请问如何实现直接正确调用?


设置了DontDestroyOnLoad的对象中的方法

private void onEnterLobbySucceed(SocketIOResponse data)
{
    Util.logData<DataOnEnterLobbySucceed>(data);
    LobbyManager manager = (LobbyManager)this.currentManager;
    manager.onEnterLobbySucceed();
}

LobbyManager中的方法

private void Update()
{
    if(this._lobbyEnterSucceed == true)
    {
        this._onEnterLobbySucceed(); // <-- 此方式有效
        this._lobbyEnterSucceed = false;
    }
}
public void onEnterLobbySucceed()
{
    Debug.Log("Enter Lobby Succeed!");
    this._lobbyEnterSucceed = true;
    this._onEnterLobbySucceed(); // <-- 此方式无效
}
public void _onEnterLobbySucceed()
{
    Destroy(GameObject.FindGameObjectWithTag("GrayLayer"));
    Destroy(GameObject.FindGameObjectWithTag("Loading"));
    string userName = PlayerDataContainer.getInstance().getPlayerData().name;
    NameField.GetComponent<TMP_Text>().text = userName;
}

问题原因

场景切换后,新场景中的对象(比如GrayLayer、Loading、NameField)还未完成初始化流程,此时直接调用_onEnterLobbySucceed会因找不到目标对象而失效。而Update方法是在场景加载完成后的下一帧执行,此时所有场景对象已就绪,因此能正常访问。

解决方法

  • 方法一:监听场景加载完成事件
    利用Unity的SceneManager.sceneLoaded事件,确保场景完全加载后再执行逻辑:

    private void Awake()
    {
        SceneManager.sceneLoaded += OnSceneLoaded;
    }
    
    private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
    {
        // 替换为你的大厅场景名称
        if(scene.name == "LobbyScene")
        {
            if(_lobbyEnterSucceed)
            {
                _onEnterLobbySucceed();
                _lobbyEnterSucceed = false;
            }
        }
    }
    
    private void OnDestroy()
    {
        SceneManager.sceneLoaded -= OnSceneLoaded;
    }
    

    这样即使在场景切换过程中触发了onEnterLobbySucceed,也会等到场景加载完成后再执行目标逻辑。

  • 方法二:用协程延迟一帧执行
    在onEnterLobbySucceed中通过协程等待下一帧,确保场景对象初始化完成:

    public void onEnterLobbySucceed()
    {
        Debug.Log("Enter Lobby Succeed!");
        StartCoroutine(ExecuteAfterFrame());
    }
    
    private IEnumerator ExecuteAfterFrame()
    {
        yield return null; // 等待下一帧
        _onEnterLobbySucceed();
    }
    
  • 方法三:提前缓存场景对象引用
    在LobbyManager的初始化阶段获取目标对象的引用,避免每次调用都用Find,同时确保引用在场景加载后正确初始化:

    [SerializeField] private TMP_Text nameField;
    
    private void Awake()
    {
        if(nameField == null)
        {
            nameField = GameObject.Find("NameField").GetComponent<TMP_Text>();
        }
    }
    
    public void _onEnterLobbySucceed()
    {
        Destroy(GameObject.FindGameObjectWithTag("GrayLayer"));
        Destroy(GameObject.FindGameObjectWithTag("Loading"));
        string userName = PlayerDataContainer.getInstance().getPlayerData().name;
        nameField.text = userName;
    }
    

内容的提问来源于stack exchange,提问作者Jeong Seong Jin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 07:07:40