Unity - 持久性与检查员添加的参考

时间:2017-08-07 17:06:07

标签: c# unity3d initialization persistence

我有一个持久的game object,我用它来初始化所有东西。我称之为脚本Persistence有一些public引用,我只是通过检查器拖动它们。 我试图让它像我在网上找到的那样持久:

public static Persistence instance;
void Awake()
{
    if (instance != null)
    {
        DestroyImmediate(gameObject);
    }
    else
    {
        DontDestroyOnLoad(gameObject);
        instance = this;
    }
}

问题是,当我从主菜单加载一个级别时,它很好。当我从该级别加载主菜单时,它会显示

  

MissingReferenceException:类型'持久性'的对象已被破坏,但你仍然试图访问它。

所以我决定在加载主菜单时让它创建其他实例,但这会混淆依赖于这些数据的游戏关卡中的所有脚本。

我的问题是,如果我有检查员添加的引用,如何在Unity中正确实现这个〜单身持久模式?

注意我只从我的持久化类中的Awake函数初始化,而不是从其他任何地方初始化。从字面上看,我的InitializeMe脚本是从Persistence类一个接一个地调用的。

我应该采取哪些不同的方式来完成这项工作?从不同的非持久性gameobject初始化?忘了拖到检查员?任何建议使这项工作表示赞赏。

1 个答案:

答案 0 :(得分:0)

我得到了它的工作。所以这里是人们应该知道的事情(我应该知道),然后再讨论Unity中的持久性:

  

您不会通过检查器拖动对持久性GO的引用,因为除了添加剂加载之外,当加载另一个场景时它们就会消失。此外,持久性GO可以保存与多个场景相关的数据,保持为通用目的而构建的功能,因为它可以重复使用,但它本身不会初始化任何内容或干扰除了被调用之外的非持久性GO - 用作工具 - 或提供数据。

这种神秘的智慧虽然是我的,所以任何更有技巧的人都会阅读这篇文章,如果我错了,请先纠正我,然后再将其铭记于心。

确切地说,我做了一个非持久性的主人INITIALIZER来完成确切的事情。我将所有场景变为一次而不是GameObject.Find。我使用LINQ查询来方便地从该集合中过滤我的结果。另一件事是我的InitializeMe抽象类(或更确切地说,它的后代)。

public abstract class InitializeMe : MonoBehaviour
{
    public int orderNumber;
    public abstract void INIT(INITIALIZER init);
}

这里orderNumber用于确定初始化的顺序,如果一个对象依赖于另一个对象。值得一提的是,这样做会导致一种非常可预测的设置方式,因为它是一个接一个地完成的。请注意,这不会产生瓶颈,因为Unity的脚本API只能在主线程中执行 - 将代码划分为多个AwakeStart方法对我的最佳知识不会更好。 2017.它由INITIALIZER中的LINQ查询使用。 INITIALIZER中的好处是 - 再次 - 它保留了所有,包括对持久对象和保存数据的引用,因此通过引用自身{{1}方法他们可以做他们需要的一切 - 因为InitializeMe提供了持久数据的通用工具,而DataBank提供了volatile(希望我使用正确的,我的意思是仅与主菜单相关)数据仅用于主菜单的功能。

现在,持久化不是由持久化类本身确保的,而是由INITIALIZER中的INITIALIZER确保如此:

Awake

其中//find by tag or rename upon instantiation as by doing so will result in a "(Clone)" added to its name. var d = GameObject.FindGameObjectWithTag("DataBank"); if (d == null) { //instantiating it DATA = GameObject.Instantiate<DataBank>(DATA_blueprint); //intializing the databank itself. The parameters are needed for me, // but serve as a good example - all of those are dragged from the inspector to the _INITIALIZER_ but will remain in the whole game as long as databank exists. DATA.LoadDataFromINIT(_baseColor, _baseColor2, _outlineColor, new MMtoolBundle(DATA)); //to make it persistent. DontDestroyOnLoad(DATA); }else { //in this case the main menu is loaded from another scene. //so we only find that loaded object and get its reference, no initialization as it was already setup. this.DATA = d.GetComponent<DataBank>(); } 是我的持久DATA。请注意,默认情况下我在场景中有 NO DataBank 对象。 DataBank是由检查员拖动DATA_blueprint的预制件(因为DataBank不是持久的)。它也可以通过INITIALIZER加载,但这样更方便。

值得一提的是,虽然AssetDatabase本身就是DataBank因此它可以出现在Unity场景中,但它的成员都不是MonoBehaviour所以可以利用继承的力量。如果希望在非单声道工具包中启动MonoBehaviour,则必须使用coroutine本身的引用启动。

这种方法的一个明显缺点是我的持续GO的存在取决于DataBank,因此必须在第一个场景上。但同样,由于大多数游戏都以主菜单开头,这不应该构成一个大问题(谈论单人游戏)。

再来一次我会推荐一些更有技巧的人来纠正我,以防我误导他人,但这个解决方案对我有用 - 在我的所有场景中都没有其他任何东西都是持久的GO创建。