Unity中的DontDestroyOnLoad()和后续场景中的引用(使用C#)

时间:2017-11-19 19:28:04

标签: c# unity3d

我正在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 = 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 gameObject,这是一个预定义的对象,指的是脚本附加到的对象。最终代码应如下所示:

private GameObject doodler;

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

2 个答案:

答案 0 :(得分:3)

在您的问题编辑和您找到的修补程序之后,我仍然认为由于您当前的代码而值得为此问题留下答案。

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

您目前正在执行此操作:

private GameObject gameObject;

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

然后在LateUpdate函数中使用它:

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

<强>问题

您的脚本派生自MonoBehaviourBehaviour派生自Component,然后派生自Component

gameObject脚本中,有一个名为&#34; GameObject&#34;的变量。这是一种public GameObject gameObject { get; } 。声明如下:

MonoBehaviour

由于您的脚本派生自gameObject,因此It refers to the变量已经声明并可供您使用。 that this script is attached to. {游戏物体{1}}。

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

  

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

怎么做

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

private new GameObject gameObject;

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

private GameObject doodler;

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

答案 1 :(得分:0)

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

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