【问题标题】:DontDestroyOnLoad() in Unity and Referencing In Later Scenes (Using C#)Unity 中的 DontDestroyOnLoad() 和后续场景中的引用(使用 C#)
【发布时间】:2018-05-03 00:38:31
【问题描述】:

我正在 Unity 中构建 Doodle Jump 的克隆,以自学基础知识,但遇到了问题。这个游戏的流程是这样的:

主菜单 ---(点击开始)--> 关卡选择 ---(点击关卡)--> 选定的关卡

玩家控制的对象实际上是在主菜单屏幕中创建的。从一开始就可以控制它,GameObject.DontDestroyOnLoad() 阻止它在每个场景转换过程中被破坏。一旦你进入你选择的关卡,就会有一个脚本附加到相机上,让它随着你的角色移动。

我在处理相机移动的 LateUpdate 方法中有一些代码:

void LateUpdate () {

    if (gameObject.transform.position.y > transform.position.y) {

        Vector3 newPosition = new Vector3(transform.position.x, gameObject.transform.position.y, transform.position.z);
        transform.position = Vector3.SmoothDamp(transform.position, newPosition, ref currentVelocity, smoothSpeed * Time.deltaTime);

    }

}

但要使其正常工作,我需要能够引用玩家(上面代码中的游戏对象)。我最初是通过使用

GameObject gameObject = GameObject.Find("Doodler");

在相同的 LateUpdate 方法中,但我没有理由在每一帧都找到 Doodler,因为它不应该被替换,直到你结束游戏。出于这个原因,我将 GameObject.Find 行移到了 Start 方法中,但它似乎没有找到 Doodler,因此相机没有移动。有人可以帮忙吗?

编辑:

我现在已将 Start 方法更改为:

private GameObject gameObject;

void Start() {
    gameObject = GameObject.Find("Doodler");
    Debug.Log("START Found the Doodler: " + gameObject.GetInstanceID());
}

而不是这样:

void Start() {
    GameObject gameObject = GameObject.Find("Doodler");
    Debug.Log("START Found the Doodler: " + gameObject.GetInstanceID());
}

这似乎奏效了。我猜第二种方法意味着 LateUpdate 无法访问 gameObject?

最终解决方案:

虽然编辑中的代码确实有效,但它会发出警告,因为我调用了我的 GameObject 游戏对象,这是一个预定义的对象,指的是脚本附加到的对象。最终代码应如下所示:

private GameObject doodler;

void Start() {
    doodler = GameObject.Find("Doodler");
    Debug.Log("START Found the Doodler: " + doodler.GetInstanceID());
}

【问题讨论】:

  • “但它似乎没有找到 Doodler,因此” 如果 Doodler 对象未处于活动状态,GameObject.Find 将找不到它。如果还没有出现在场景中,GameObject.Find 也找不到。是哪一个?
  • 它是在 LateUpdate 方法中找到的,但不是在 Start 方法中找到的,所以我想知道什么时候 DontDestroyOnLoad 对象在新场景中可用。但是,看起来我已经按照上面的编辑修复了它。
  • 在您使用当前和旧代码更新问题后,我决定留下答案。请阅读。

标签: c# unity3d


【解决方案1】:

处理此问题的一种(多种)方法是使用 SceneManager.sceneLoaded 回调 (https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager-sceneLoaded.html)。因为您可以在加载新场景后执行查找操作。

但是,如果您在上面引用的这个脚本已经在“Doodler”游戏对象上,并且您收到 null ref 错误,那么可能还有另一个问题。 MonoBehaviour 类中的“gameObject”成员应该始终是组件(MonoBehaviour 派生类)附加到的游戏对象。如果它变成了 null,那么你就是在强迫它以某种方式被摧毁,但是 Monobehaviour 仍然活着,这很奇怪。

【讨论】:

  • 自从发布这个问题以来,我实际上已经设法修复它,方法是在 Start 方法之外初始化一个私有 GameObject,而不是在 Start 方法中创建它(请参阅我在帖子中的编辑)。你知道我做的两种方式有什么区别吗?我将更改它以使用您提到的 SceneManager.sceneLoaded 方法 - 谢谢!
【解决方案2】:

在对您的问题进行编辑并找到修复后,由于您当前的代码,我仍然认为值得留下这个问题的答案。

显然,您需要先将变量设为全局变量,然后才能在另一个函数中访问它。你解决了这个问题,但是有一个你还不知道的大问题,当你试图从另一个函数访问在本地函数中声明的变量时,你从来没有出错是有原因的。您的原始代码应该收到错误,但您没有。

您目前正在这样做:

private GameObject gameObject;

void Start() 
{
    gameObject = GameObject.Find("Doodler");
}

然后在LateUpdate函数中使用它:

void LateUpdate () 
{
    if (gameObject.transform.position.y > transform.position.y) {...}
}

问题

您的脚本派生自MonoBehaviour,后者派生自Behaviour,后者又派生自Component

Component 脚​​本中,有一个名为“gameObject”的变量,它是GameObject 的一种类型。它是这样声明的:

public GameObject gameObject { get; }

由于您的脚本派生自MonoBehaviour,因此gameObject 变量已被声明并可供您使用。 It refers to theGameObjectthat this script is attached to..

事实上,现在,您应该会收到类似这样的警告:

严重性代码描述项目文件行抑制状态 警告 CS0108 'YourScript.gameObject' 隐藏继承的成员 '组件.gameObject'。如果要隐藏,请使用 new 关键字。

做什么

您当然可以使用 new 关键字来隐藏它并删除该警告:

private new GameObject gameObject;

不要那样做。不要将变量命名为“gameObject”或任何已在 MonoBehaviour 类中使用的名称。您将遇到此代码的许多问题。我已经看到了几个由此引起的问题,很难发现这是问题所在。像下面这样的应该没问题:

private GameObject doodler;

void Start()
{
    doodler = GameObject.Find("Doodler");
}

【讨论】:

  • 我收到了这个警告,谢谢你解决它。我将更新问题以反映最终代码。澄清一下,当我在 Start 方法中定义 GameObject 时,是否默认只在该方法的范围内?我可以添加“公共”以使其对 LateUpdate 可见吗?
  • 1.是的。假设你在Start函数中做GameObject doodler = GameObject.Find("Doodler");,你只能在Start函数中使用它。事实上,{ ... } 内部的变量只能在{ ... } 内部使用。我建议您阅读 C# 中的范围和声明以获取更多信息。 2.您无需设置Public 即可在LateUpdate 中访问它。如果您想从 另一个 脚本访问它,或者如果您希望它显示在编辑器中以便您可以在运行时从编辑器中查看它的值,您可以将其设为 public
  • 你只需要在GameObject doodler;这样的函数外声明它然后在void Start() { doodler = GameObject.Find("Doodler"); }这样的函数内初始化它publicprivateprotected只是用来确定访问权限该变量/函数的级别来自 另一个 脚本而不是来自该脚本。
  • 这样就更清楚了,谢谢。我将在 C# 中查找范围和声明。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-10
  • 1970-01-01
相关资源
最近更新 更多