在Unity中第一次场景加载时实例化对象

时间:2015-03-24 18:14:30

标签: unity3d

我有一个包含各种场景的Unity项目。我的第一人称控制器有一个脚本,我保留了几个我希望为整个游戏保留的变量。

我会不断改变场景,所以我的剧本有

void Awake() { DontDestroyOnLoad(transform.gameObject); }

让我的变数'价值不会丢失。现在,我将对象放在场景1上,当我加载第一个场景时,我的对象可用。当我改变场景时,一切都表现得像预期的那样:我的变量'价值是守恒的。然而,当我返回场景1时,我的第一人称控制器对象没有被破坏,现在我有两个第一人称控制器(我从另一个场景带来的那个和场景1里面的那个)。相机没有& #39;知道要跟随哪一个。

如何在第一次加载场景时才实例化我的GameObject?

5 个答案:

答案 0 :(得分:3)

如果您使用该对象重新加载场景,则无法避免重复的Awake调用。您可以采用两种方法处理:

  • 有一个专门用于静态启动的场景。将所有永久加载的脚本放在DontDestroyOnLoad中,并始终使用此场景启动应用程序。
  • 将静态引用存储到第一个初始化对象。如果实例已经存在,则在Awake中销毁self。

第二个选项的示例:

static private MyClass instance = null;
void Awake() {
    if (instance != null) {
        Destroy(this);
        return;
    }
    instance = this;
}

答案 1 :(得分:0)

如果要在加载开始时实例化第一人称控制器,则在实例化时,可以进行条件检查以查看它是否已存在于场景中(然后删除或不实例化)。就跨场景保存信息而言,我建议您改为使用PlayerPrefs

答案 2 :(得分:0)

你可以把你的第一人控制器(事实上,你喜欢的整个球员)放在预制件中。

然后,不要在场景中使用实例预制件,而是将带有参考的Spawner组件写入预制件。 Spawner可以检查(在Awake中)第一个人控制器是否已经存在,并且只有在预制件已经存在的情况下才会实例化该预制件。

答案 3 :(得分:0)

我知道这是一篇较老的帖子,但当我在寻找一种自动实例化一个静态GameObject的方法时,谷歌的结果很少。不确定旧版本,但这与5.6.1完美配合。我需要一种方法来存储游戏设置并从许多场景中访问它们。我还需要访问某些只能从MonoBehaviour访问的统一函数(如屏幕res等),因此不能选择普通的静态类。我提出的基本上是单例类型的统一GameObject,如果您获得对Instance的引用,并且场景中没有其中一个,它会自动创建它。如果存在,(更改回创建它的场景),重复的自我破坏,以便游戏中只有其中一个。

我想要这个的原因是因为我使用Unity ScriptableObjects存储数据,因为它们可以在编辑和运行时从编辑器中进行编辑,并且运行时的更改不会恢复(如果您使用旧的OnGUI,则非常方便)可以将rect位置存储在可编写脚本的对象中,并观察控件在运行时移动,并且当您停止播放模式时位置不会恢复)

这是我非常基础的课程(从中删除了我的具体数据)

using UnityEngine;

public class GameSettings : MonoBehaviour
{
    private static GameSettings _instance;

    public static GameSettings Instance
    {
        get
        {
            if (_instance != null) return _instance;
            else
            {
                Setup();
                return _instance;
            }
        }
    }

    public void Start ()
    {
        DontDestroyOnLoad(this);
    }

    public void Awake()
    {
        if (_instance != null) Destroy(this);
    }

    public static void Setup()
    {
        GameObject settings = GameObject.Find("GameSettings");
        if (settings == null)
        {
            settings = new GameObject("GameSettings");
            settings.AddComponent<GameSettings>();
        }
        _instance = settings.GetComponent<GameSettings>();
    }
}

您可以使用以下两种方式:

1:将它添加到第一个场景中的GameObject(这样您就可以修改检查器中的值)。如果您更改回该场景,则由于检查_instance而不会创建重复项。如果你确实手动将它添加到场景中,请确保将GameObject.Find字符串编辑为GameObject的名称,否则它将创建一个新的。

2:只需创建对ClassName.Instance的引用,如果该对象不存在,它将自动创建该对象。

场景的示例实现脚本:

public class TestScene : MonoBehaviour
    {
        private GameSettings _settings;

        public void Awake()
        {
            _settings = GameSettings.Instance;
        }
        public void Start()
        {
        }

        public void Update()
        {

        }
    }

现在你要做的就是将你的公共数据(字符串,整数等)添加为GameSettings类的公共非静态成员,只需使用_settings.MemberName来访问数据。

希望这有助于某人寻找一种动态自动创建GameObjects的方法。如果您构建预制件并将此脚本附加到其任何对象,这也适用。可以方便地在特定场景中自动创建UI元素。

如果你只需要在一个场景中并且不需要它在级别加载中持续存在(例如在某些场景中自动实例化某些UI元素,比如说npc对话框等),只需从类的start函数中删除DontDestroyOnLoad即可。附在预制件上的那些。

答案 4 :(得分:0)

使用属性RuntimeInitializeOnLoadMethod和属性RuntimeInitializeLoadType.BeforeSceneLoad创建一个静态void函数,它将在第一个场景加载之前被调用。通过该功能,您应该能够创建所需的游戏对象等。

using UnityEngine;

public class GameStartupHelper
{
    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    static void OnBeforeSceneLoad()
    {
        Debug.Log("OnBeforeSceneLoad(");
        // Create your stuff from here...
    }
}

ps。无需将类添加到任何场景,只需将脚本文件保留在项目中就可以调用回调。

有关更多说明,请参见this post