场景更改后,在Start()函数中未引用Singleton

时间:2018-10-16 15:04:09

标签: c# visual-studio unity3d singleton

我试图理解为什么在使用单身人士时场景改变后却缺少参考异常。

所以,我在第一个场景中有两个GameObjects。一个主摄像机附加了GameManager脚本,另一个商店对象附加了购买者脚本。这两个脚本也是这样创建的单例,例如:

public static Purchaser Instance

    void Awake(){
        Instance = this
    }

然后它们都在Start()函数中互相引用,再次例如,如下所示:

    void Start(){
        game = GameManager.Instance
    }

在更改场景之前,两个脚本都使用彼此的单例引用来相互调用方法,并且一切似乎都正常进行。更改场景后,这些对象都不在下一个场景中,因此它们都将被销毁。但是,一旦我回到主场景,当购买者脚本尝试使用从Start()获取的单例引用从GameManager调用方法时,就会收到缺少的参考异常,这会更改附加到主场景的文本对象的文本。相机。在按下按钮后,将调用此函数,该按钮附加到在购买者脚本中调用该函数的商店对象:

UpdateMoney(){
    game.UpdateMoney(100);
}

我环顾四周,发现这可能是因为Start()在整个游戏过程中只会被调用一次。这意味着“购买者”脚本的GameManger单例实例仍然是场景改变之前的旧实例,并且该实例被销毁。但是,我只是通过在每个脚本Start()函数中放置一个调试日志来测试这是否成立,并且看到在每个场景更改回主场景后,调试日志将从两个脚本Start()中通过。因此,可以说在脚本的生命周期中仅一次调用过Start()而不是整个游戏运行正确吗?难道这还不意味着一旦游戏变回主场景并再次创建了两个GameObject,自从再次调用Start()以来,购买者脚本现在就应该具有对新创建的GameManager脚本的更新引用?

我还发现,它可以代替UpdateMoney()中的游戏引用来工作:

UpdateMoney(){
    GameManager.Instance.UpdateMoney(100);
}

那么,为什么这样做而不使用Start()中检索到的游戏引用呢?这是否意味着当Start()称为GameManager.Instance仍然是旧的GameManager.Instance时,这就是为什么game = GameManager.Instance无法正常工作的原因?对不起,这很罗word。非常感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

根据我的理解,您在主场景中制作了一个单例。切换场景后,附着了单例的游戏对象将被破坏。

首先,您是否有理由需要单身人士成为MonoBehaviour并附加到游戏对象上?因为你可以用

 ruby -run -e httpd -- -p 5000

╭─ ~/learn/ruby/ruby-way/stackoverflow/q-static-html-007/html 
╰─ tree
.
.
├── 1.html
└── 2.html

这样,您的单例将始终具有一个值,并且可以通过场景传递,除非instance设置为null。

第二,private static MyClass instance = null public static MyClass Instance { get { if(instance == null) instance = new MyClass(); return instance; } } 仅被调用一次。但是,在将MonoBehaviour附加到禁用的游戏对象上之前,我遇到过问题,Start()将不会被调用。当您切换回主要场景时,您可以检查这是怎么回事。

第三,如果您确实需要将单例作为MonoBehaviour,则可以使用Start(),因此即使在场景切换后,单例的游戏对象也不会被破坏。然而。我假设游戏对象已放置在场景中。如果不是来自预制件,则可以执行以下操作

DontDestroyOnLoad(instance.gameObject)

如果这样做,则可以从主场景中删除预设的游戏对象,并让第一个调用private static MyClass instance = null; public static MyClass Instance { get { if(instance == null){ GameObject inst = new GameObject("MyClass Singleton"); instance = inst.AddComponent<MyClass>(); DontDestroyOnLoad(inst); } return instance; } } 成为您的游戏对象。

最后,如果您不想这样做,则应在游戏对象的MyClass.Instance上设置instance = null;,以便在进入主场景时将新实例设置为单例。这意味着在将场景切换到主场景之外之后,单例将没有值。