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
相关产品推荐
相关产品推荐

