【问题标题】:Scene not properly loaded when switching back and forth来回切换时未正确加载场景
【发布时间】:2019-03-01 17:03:16
【问题描述】:

问题
我构建的 Unity 项目面向 iOS、Android 和 Windows X64。我有两个场景,A 和 B,而 A 是我游戏的主菜单场景,场景 B 是一种关卡选择场景,用户可以在其中选择要玩的关卡。从场景 A 我可以导航到场景 B 并再次返回。在 Unity Editor 中运行游戏时,一切都按预期运行。当我在目标平台(真实设备)上运行游戏时,问题就出现了。然后,当像 A --> B --> A 那样导航时,我最终会在场景 A 中渲染为黑屏,但 FPSIndicator 游戏对象仍然在渲染并完成其工作。 FPSIndicator 游戏对象是一小段代码,它在 OnGUI 回调中将自己吸引到场景中。没有其他内容显示。

场景 A 的设置
我有一个 Unity UI 按钮(“拖放”),单击该按钮时,使用以下代码加载场景 B:

using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.EventSystems;

public class GameTypeButtonController : MonoBehaviour, IPointerClickHandler
{
    public ButtonSounds ButtonSounds;
    public string SceneNameToLoad;
    public GameType GameType;

    public void OnPointerClick(PointerEventData eventData)
    {
        StartCoroutine(Do());
    }

    private IEnumerator Do()
    {
        var animator = gameObject.GetComponent<Animator>();

        if (animator != null)
        {
            animator.SetTrigger("Clicked");
        }

        var audioSource = gameObject.GetComponent<AudioSource>();

        if (audioSource != null)
        {
            var clip = GetRandomAudioClip(ButtonSounds);
            audioSource.clip = clip;
            audioSource.Play();
            yield return new WaitWhile(() => audioSource.isPlaying);
        }

        Logger.LogInfo("[GameTypeButtonController.Do] Setting game type " + GameType);
        GameManager.Instance.CurrentGameType = GameType;
        SceneManager.LoadScene(SceneNameToLoad);
    }

    private AudioClip GetRandomAudioClip(ButtonSounds buttonSounds)
    {
        var numberOfAudioClips = buttonSounds.AudioClips.Length;
        var randomIndex = Random.Range(0, numberOfAudioClips);
        return buttonSounds.AudioClips[randomIndex];
    }
}

场景是这样的:

场景 B 的设置
在场景 B 中,我在左下角有一个按钮,点击后我会回到场景 A。这不是 Unity UI 按钮,而是附加了 CircleCollider2D 的常规精灵。该按钮上的脚本如下所示:

using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;

public class HomeButtonController : MonoBehaviour
{
    public ButtonSounds ButtonSounds;
    public string SceneNameToLoad;

    void OnMouseDown()
    {
        StartCoroutine(Do());
    }

    private IEnumerator Do()
    {
        var animator = gameObject.GetComponent<Animator>();

        if (animator != null)
        {
            animator.SetTrigger("Clicked");
        }

        var audioSource = gameObject.GetComponent<AudioSource>();

        if (audioSource != null)
        {
            var clip = GetRandomAudioClip(ButtonSounds);
            audioSource.clip = clip;
            audioSource.Play();
            yield return new WaitWhile(() => audioSource.isPlaying);
        }

        SceneManager.LoadScene(SceneNameToLoad);
    }

    private AudioClip GetRandomAudioClip(ButtonSounds buttonSounds)
    {
        var numberOfAudioClips = buttonSounds.AudioClips.Length;
        var randomIndex = UnityEngine.Random.Range(0, numberOfAudioClips);
        return buttonSounds.AudioClips[randomIndex];
    }
}

场景是这样的:

一般说明
两个对象使用DontDestroyOnLoadGameManagerMusicPlayer

到目前为止我检查过的内容

  • 在构建设置中正确引用了场景
  • 在使用 Unity Cloud Build 时,我禁用了库缓存功能以避免旧的构建工件出现问题(因此每次构建时,我都会进行正确、干净的构建)
  • 我可以在本地构建所有三个平台(Unity 将其报告为“构建成功”)。所以没有构建错误。
  • 我正在使用LoadSceneMode.Single(默认)
  • 我在本地和 Unity Cloud Build 中使用相同的 Unity 版本:2018.3.0f2

2019 年 2 月 19 日更新:
当我使用相同的机制(调用协程的精灵按钮)从第三个场景 C 导航回场景 A 时,我也最终进入了相同的黑屏。那么问题可能存在于场景 A 中?

2019-02-19 更新 2:
这是我的 GameManager 代码:

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;

public class GameManager : MonoBehaviour
{
    public EventHandler<LevelStartedEventArgs> LevelStarted;
    public EventHandler<LevelFinishedEventArgs> LevelFinished;

    // General 
    public GameType CurrentGameType;
    public GameScene CurrentScene;
    public int CurrentLevel;
    public static GameManager Instance;
    public GameLanguage Language;
    public bool IsMusicEnabled;
    private string gameStateFile;

    void Start()
    {
        if (Instance == null)
        {
            gameStateFile = Application.persistentDataPath + "/gamestate.dat";
            Load(gameStateFile);
            DontDestroyOnLoad(gameObject);
            Instance = this;
        }
        else if (Instance != this)
        {
            Destroy(gameObject);
        }
    }

    public void Save()
    {
        Logger.LogInfo("[GameManager.Save] Saving game state to " + gameStateFile);
        var bf = new BinaryFormatter();
        var file = File.Create(gameStateFile);

        var gameState = new GameState();
        gameState.Language = Language;
        gameState.IsMusicEnabled = IsMusicEnabled;

        bf.Serialize(file, gameState);
        file.Close();
        Logger.LogInfo("[GameManager.Save] Successfully saved game state");
    }

    public void Load(string gameStateFile)
    {
        Logger.LogInfo("[GameManager.Load] Loading game state from " + gameStateFile);
        if (File.Exists(gameStateFile))
        {
            var bf = new BinaryFormatter();
            var file = File.Open(gameStateFile, FileMode.Open);
            var gameState = (GameState)bf.Deserialize(file);
            file.Close();
            Language = gameState.Language;
            IsMusicEnabled = gameState.IsMusicEnabled;
        }
        Logger.LogInfo("[GameManager.Load] Successfully loaded game state");
    }

    [Serializable]
    class GameState {
        public GameLanguage Language;
        public bool IsMusicEnabled;
    }
}

感谢任何提示!

【问题讨论】:

  • 感觉是相机问题。您的游戏管理器是否以某种方式链接到相机?你说游戏管理器不会在场景中被破坏,但它所指的任何东西都会被破坏,除非它也被标记为DontDestroyOnLoad
  • @IvayloSlavov 感谢您的意见。我添加了我的 GameManager 类的代码。我在那里没有引用任何相机,只是一些枚举、字符串和布尔值。但是当 GameManager 初始化时,我从 gamestate.dat 文件中加载了一些设置(参见代码)。
  • 你的代码看起来很简单。由于我没有尝试过桌面模式以外的其他模式,我可以建议您通过一些实验来找到问题。首先尝试查看禁用序列化逻辑是否会改变任何内容。也许有序列化异常会破坏其余代码?另外,请尝试更改 Awake() 中的 GameManager 初始化,而不是 Start()。一步一步地做这些,而不是一次,我们需要看看真正导致问题的原因。在这里和那里记录将有助于确定代码停止工作的位置。
  • @IvayloSlavov 好建议。今晚将尝试并报告成功/失败。

标签: unity3d


【解决方案1】:

所以,我终于设法自己解决了这个问题。以下是我为消除我的问题所经历的步骤列表:

  1. 我在 Visual Studio 2017 中安装了“使用 Unity 进行游戏开发”工作负载,以便能够使用 Visual Studio 调试器。这使我有可能正确调试我的脚本(设置断点,检查值,...)并逐步完成它们。有关如何完成此操作的一些详细信息,请参阅this link。不幸的是,这还没有解决我的问题,但为解决我的问题提供了良好的基础。

  2. 由于上述问题也出现在 Windows x64 版本上,我决定在 Windows 版本上解决我的问题。所以我在 Build Player Settings 中重新配置了我的 Windows 版本,将 Script Debugging 设置为 trueDevelopment build 设置为 trueCopy PDB filesto true。然后我运行了另一个 Windows 版本。

如果你现在运行你的游戏,它会在左下角显示一个开发控制台,提供很多有用的信息(抛出的异常等等......)。您也可以直接在游戏中打开日志文件,这提供了很多有用的信息来解决真正的问题。

所以,我在日志中有一些PlatformNotSupportedExceptions,我能够修复这些错误和其他一些错误。现在它正在工作。

虽然,我已经回答了我自己的问题,但我希望这对你们中的一些人有用。

【讨论】:

    猜你喜欢
    • 2016-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多