来回切换时场景未正确加载 [英] Scene not properly loaded when switching back and forth

查看:125
本文介绍了来回切换时场景未正确加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Problem
The Unity project I build is targeting iOS, Android and Windows X64. I have two scenes, A and B, whereas A is the main menu scene of my game and scene B is kind of a level selection scene in which the user can choose a level to play. From scene A I can navigate to scene B and back again. When running the game in the Unity Editor, everything behaves as expected. The problem arises, when I run the game on the target platforms (real devices). Then, when navigating like A --> B --> A, I end up in scene A being rendered as a black screen, except the FPSIndicator game object which is still rendered and doing its job. The FPSIndicator game object is a small piece of code which draws itself to the scene in the OnGUI callback. Nothing else is displayed.

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

Setup of Scene A
I have a Unity UI button there ("Drag and Drop"), which, when clicked, loads scene B using this code:

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的常规子画面.该按钮上的脚本如下所示:

Setup of Scene B
In scene B, I have a button in the lower left which brings me back to scene A when clicked. This is not a Unity UI button, but a regular sprite with a CircleCollider2D attached. The script on that button looks like this:

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];
    }
}

场景如下:

一般说明
两个对象使用DontDestroyOnLoad:GameManagerMusicPlayer.

General Notes
Two objects use DontDestroyOnLoad: GameManager and MusicPlayer.

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

  • 在构建设置"中正确引用了场景
  • 在我使用Unity Cloud Build时,我已禁用库缓存功能,以避免旧的构建工件出现问题(因此,每次构建时,我都会进行正确,干净的构建)
  • 我可以在本地构建所有三个平台(Unity称其为构建成功").因此没有构建错误.
  • 我正在使用LoadSceneMode.Single(默认)
  • 我在本地和Unity Cloud Build:2018.3.0f2中使用相同的Unity版本
  • Scenes are properly referenced in Build Settings
  • As I use Unity Cloud Build, I have disabled the Library Caching feature to avoid issues with old build artifacts (so every time I build, I do a proper, clean build)
  • I can locally build all three platforms (Unity reports it as "Build successful"). So no build errors.
  • I am using LoadSceneMode.Single (default)
  • I am using the same Unity version locally and in Unity Cloud Build: 2018.3.0f2

更新2019-02-19:
当我使用相同的机制(称为协程"的精灵按钮)从第三个场景C导航回场景A时,我最终也会出现在完全相同的黑屏上.那么问题可能存在于场景A中吗?

Update 2019-02-19:
When I navigate from a third scene C back to scene A using the same mechanism (a sprite button calling a coroutine), I also end up on the very same black screen. So the issue probably exists within scene A?

2019年2月19日的更新2:
这是我的GameManager代码:

Update 2 from 2019-02-19:
Here's my GameManager code:

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;
    }
}

感谢任何提示!

推荐答案

因此,我终于设法自己解决了这个问题.这是我为了消除问题而经历的步骤列表:

So, I finally managed to solve the issue on my own. Here's a list of steps I went through in order to eliminate my issue:

  1. 我在Visual Studio 2017中安装了使用Unity开发游戏"工作负载,以便能够使用Visual Studio调试器.这使我可以正确调试脚本(设置断点,检查值等)并逐步进行调试.请参见

  1. I installed the "Game development with Unity" workload in Visual Studio 2017 in order to be able to use the Visual Studio Debugger. That gave me the possibility to properly debug my scripts (setting breakpoints, inspect values, ...) and go through them, step by step. See this link for some details on how to accomplish this. Unfortunately, this did not solve my problem yet, but gave a good basis for troubleshooting my issue.

由于上述问题也出现在Windows x64构建上,因此我决定对Windows构建上的问题进行故障排除.因此,通过将Script Debugging设置为true,将Development build设置为true,将Copy PDB files设置为true,在构建播放器设置"中重新配置了Windows构建.然后我运行了另一个Windows版本.

As the issue described above, also arised on Windows x64 builds, I've decided to troubleshoot my issue on a windows build. So I reconfigured my Windows build in the Build Player Settings, by setting Script Debugging to true, Development build to true, Copy PDB filesto true. Then I've ran another windows build.

如果您现在运行游戏,它将在左下方屏幕上显示一个开发控制台,其中提供了许多有用的信息(抛出异常等).您也可以直接在游戏中打开日志文件,该日志文件提供了大量有用的信息来解决实际问题.

If you now run your game, it will show a development console in the lower left screen, giving a lot of useful information (exceptions thrown, etc...). Also you can open the log file directly from within the game, which provides a LOT of useful informations to tackle down the real issue.

因此,我在日志中有一些PlatformNotSupportedExceptions,我可以修复此错误和其他一些错误.现在可以了.

So, I had some PlatformNotSupportedExceptions in the logs, which I was able to fix and some other errors. Now it is working.

尽管我已经回答了我自己的问题,但我希望这对某些人有用.

Although, I've answered my own question, I hope this will be useful to some of you.

这篇关于来回切换时场景未正确加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆