Unity:使用 GameManager 添加 "Persistent-Scene" 后出现奇怪的场景转换错误

Unity: Weird scene transition bug after adding a "Persistent-Scene" with a GameManager

我做了一个非常基础的 2D 游戏来学习。我有 2 个 Scenes,在它们之间切换效果很好。我使用空 gameObjects 作为 Scene 的 Start/Exit 点,这样游戏就会知道在通过 X 点退出后将玩家放在 X 点上(例如,如果我走出去,则退出屋外门)。

然后我添加了一个“Scene0”,用于持久性通用脚本,如 GameManager、声音、音乐等。只有一个名为 "Controller" 的对象,我 DontDestroyOnLoad()。 添加这个场景然后直接切换 Scenes 到我的 MainScene 之后,游戏突然开始表现得很奇怪;

我第一次从我的主场景(Scene1)移动到我的次要场景(Scene2),它工作正常,但是当我离开时Scene2 回到 Scene1,玩家会在茫茫荒野中重生。 只有当我从 Persistent Scene.

启动游戏时才会发生这种情况

我不知道哪里出了问题,我没有添加任何干扰我的场景转换的东西,到目前为止我添加的只是 playerHealth,用于测试。

附加到我的(持久)控制器的脚本:

DDOL:

public class DDOL : MonoBehaviour {

    // Use this for initialization
    void Awake () {
        DontDestroyOnLoad (gameObject);
    }

}

游戏经理:

public class GameManager : MonoBehaviour {

    public static GameManager manager;

    public int playerMaxHealth;
    public int playerCurrentHealth;

    void Awake(){
        if (manager == null) {
            manager = this;
        } else if (manager != this) {
            Destroy (gameObject);
        }
    }

    // Use this for initialization
    void Start () {
        SceneManager.LoadScene("test_scene");
    }

    // Update is called once per frame
    void Update () {

    }
}

附加到我的 StartPoint 的脚本:

玩家起点:

public class PlayerStartPoint : MonoBehaviour {

    private PlayerController thePlayer;
    private CameraController theCamera;

    public Vector2 startDir;

    public string pointName;

    // Use this for initialization
    void Start () {
        thePlayer = FindObjectOfType<PlayerController> ();

        if (thePlayer.startPoint == pointName) {
            thePlayer.transform.position = transform.position;
            thePlayer.lastMove = startDir;

            theCamera = FindObjectOfType<CameraController> ();
            theCamera.transform.position = new Vector3(transform.position.x, transform.position.y, theCamera.transform.position.z);
        }
    }
}

最后是退出点:

加载新区域:

public class LoadNewArea : MonoBehaviour {

    public string levelToLoad;
    public string exitPoint;
    private PlayerController thePlayer;

    // Use this for initialization
    void Start () {
        thePlayer = FindObjectOfType<PlayerController> ();
    }

    void OnTriggerEnter2D(Collider2D other){
        if (other.gameObject.name == "Player") 
        {
            SceneManager.LoadScene(levelToLoad);
            thePlayer.startPoint = exitPoint;
        }
    }
}

编辑: 将我所有的 DDOL 游戏对象移动到 Pre-Scene 后,它起作用了。因此,我可以假设故障出在 Player 或 Cameras Start() 函数内部,因为当它们在 Scene1 中启动时,每次我进入场景时它们都会被调用(仅 DDOL)。 我尝试调整他们的 Start() 函数如下:

原装相机:

void Start () {
        Debug.Log("Starting camera");
        if (!cameraExists) {
            cameraExists = true;
            DontDestroyOnLoad (gameObject);}
           else{
        Destroy (gameObject);
        }
    }

更改相机:

void Start () {
            DontDestroyOnLoad (gameObject);
        }

在 Player 中进行了完全相同的更改。 显然这不起作用,因为每次我进入 Scene1 时它都会创建一个新的 Camera/Player(顺便说一句,为什么当我进入 Scene2 时它不尝试创建它们?是因为它们是从 Scene1 开始的吗?)。然而,新的 player/camera 确实从正确的位置开始,如果我缩小我可以看到旧的 player/camera 和以前一样在错误的位置。因此,当他们的 Start() 似乎第二次被调用时,会发生一些奇怪的事情。

玩家是否在场景之间持续存在(他是否有 DontDestroyOnLoad)?如果不是,那么这可能是原因 - 您可以尝试使用附加模式加载场景,或者在场景加载时在正确位置实例化播放器。

您现在提到您有类似这样的代码,

void Start () {
        Debug.Log("Starting camera");
        if (!cameraExists) {
            cameraExists = true;
            DontDestroyOnLoad (gameObject);}
           else{
        Destroy (gameObject);
        }
    }

请注意,不幸的是,这只是 "utterly incorrect",呵呵:)

你在问题中提到的问题(预加载场景等)与这里的问题完全无关。


在 Unity 中,如果你有一个角色 C 在你加载这些场景时持续存在于场景 a、b、c 之间,你必须在它自己的(否则可能是空的)场景中启动 C,你 不能使用"a"为了方便开C.

模式是,在每个a,b,c中只有一行代码,如p = FindObjectOfType<Player>();,在场景加载时运行,并根据需要放置C。


现在,关于您所看到的异常行为的特定谜题

我理解您想知道为什么要观察您所做的事情。

这是对以下问题的混淆:1 - Awake 和 Start 之间的区别,2 - 对 脚本执行顺序的混淆 {但见下文1} 3 - 关于 Destroy 与 DestroyImmediate 的混淆 4 - 不使用 Debug.Log 就够了,而不是在那里使用 gameObject.name(在 Unity 中很容易混淆 Debug.Log 中哪个对象在说话) 5 - 哪里你提到你看到了另一个对象 "off to the side",通常 严重混淆 在这种情况下哪个是哪个 6 - "instantiation" 的计算机编程概念之间的混淆(即 class 或对象)和“实例化”(令人困惑的是,它是同一个词 - 完全不相关)nity 中的游戏对象。

如果您 fiddle 遇到所有这些问题,您会发现对您所看到的行为的解释!

但这并不重要;在 "C .. a b c" 示例中的 Unity 中,您必须事先单独创建 C。

1 {顺便说一句,从不fiddle用Unity中的脚本执行排序系统来解决问题;它仅用于研发目的;但是它实际上可以帮助您调查此问题中的手头行为,如果您特别热衷于完全理解为什么您会看到您明显看到的内容}

使用调试器。在相关位置设置断点,例如 PlayerStartPoint.Start()LoadNewArea.OnTriggerEnter2D() 并检查它们是否已执行

  • 适时
  • 正确的次数
  • 符合预期值

这应该会让您看到事情失控的地方。

如果您使用 Visual Studio,请安装 https://marketplace.visualstudio.com/items?itemName=SebastienLebreton.VisualStudio2015ToolsforUnity 以便能够从 Visual Studio 中调试 Unity。 如果您不使用 Visual Studio,您可能应该使用。