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,您可能应该使用。
我做了一个非常基础的 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,您可能应该使用。