如何取消订阅游戏管理员内部的活动?

时间:2018-04-18 22:18:42

标签: c# unity3d events delegates singleton

在Unity中,在我的GameManager脚本中,我有一个代表。在我的Door脚本中,我订阅了这个代理。我已尝试在OnDisable脚本中的OnDestroyDoor方法中取消订阅。在这两种情况下,当我在编辑器中停止运行游戏时出现错误:

  

关闭场景时,某些对象未被清除。 (你是否从OnDestroy产生了新的GameObjects?)

使用Debug.Log,我发现这是因为GameManager将始终在Door脚本之前销毁。即使我在null脚本的OnDisableOnDestroy内进行了Door检查,看看GameManager是否为null,得到同样的错误

if (GameManager.Instance)
{
    GameManager.Instance.OnAllEnemiesKilled -= OpenDoor;
}

有人告诉我,我不需要取消订阅,因为当Door对象被销毁时,委托将自动变为空,但事实并非如此。在运行期间,在Door被销毁之后,GameManager内部的更新循环仍在打印代表有一个订户:Door

2 个答案:

答案 0 :(得分:1)

我怀疑你在被销毁之后致电GameManager.Instance时会产生一个新的单身人士吗?如果是这样,请改为做这样的事情:

public class GameManager : MonoBehaviour
{
    public static GameManager Instance
    {
        get
        {
            if (isDestroyed) return null;

            // Your spawn logic...
        }
    }

    static bool isDestroyed;

    void OnDestroy()
    {
        isDestroyed = true;
    }
}

答案 1 :(得分:0)

正如Lece指出的那样,当我调用GameManager.Instance时,我会产生一个新的单例。然而,我没有创建静态bool来解决问题,而是在我的Instance getter中用if (_instance == null)替换了if ((object)_instance == null),它解决了问题。这是因为,虽然对象在本机代码中被销毁,但它仍然存在于托管代码中。所以我现在在托管世界中引用它。此外,Unity make是这样的,当一个对象在本机代码中被销毁时,它在托管代码中的值仍将返回null。