【问题标题】:Unity WebGL Gameobject disabled from somewhereUnity WebGL Gameobject 从某处禁用
【发布时间】:2019-12-02 16:49:03
【问题描述】:

所以,我在场景中的单一行为脚本(我们称之为脚本 A)上运行了更新。此更新会触发一个事件,因此其他非单一行为脚本可以在需要更新某些内容时收听此事件。但是,在应用程序启动时,它会在短时间内运行脚本 A 上的更新,但过了一段时间它会随机停止调用脚本 A 上的更新。

所以我开始在标准的单体行为函数中进行一些调试,例如唤醒、启动、禁用、启用等。结果发现该对象在没有我在任何地方使用或调用它的情况下从某个地方被禁用。此问题仅发生在 WebGL 上。在编辑器中,永远不会调用 OnDisable 事件,并且更新保持正常运行。

我尝试了各种修复,就像到处都是调试日志一样,我尝试调试堆栈跟踪以找出调用此 OnDisable 的原因,据说这不会显示在 WebGL 控制台中。它只是说:StackTrace:

public class UpdateManager : MonoBehaviour
{
    private static UpdateManager _instance;
    public static UpdateManager Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = FindObjectOfType<UpdateManager>();

                if (_instance == null)
                {
                    GameObject updateManager = new GameObject("UpdateManager");
                    _instance = updateManager.AddComponent<UpdateManager>();
                }
            }

            return _instance;
        }
    }

    public delegate void OnUpdateEvent();
    public event OnUpdateEvent OnUpdate;

    private void Awake()
    {
        Debug.Log("UpdateManager: Awake!"); 
    }     

    private void Start()
    {
        Debug.Log("UpdateManager: Start!"); 
    }

    private void OnEnable()
    {
        Debug.Log("UpdateManager: OnEnable!"); 
    }

    private void OnDisable()
    {
        Debug.Log("UpdateManager: OnDisable!, Stacktrace: " + UnityEngine.StackTraceUtility.ExtractStackTrace()); 
    }

    private void Update()
    {
        Debug.Log("UpdateManager: Update!");
        OnUpdate?.Invoke();
    }

我想知道是什么禁用了这个对象,因为我不知道。这里需要注意的是,它只在开始时禁用了一次,在我再次启用它之后,它在剩余时间内运行良好。

我称这个脚本的唯一地方是某个静态类:

    private static void initializeRefreshCycle(int expiresIn)
    {
        if (expiresIn > 0)
        {
            if (_refreshRoutine != null)
            {
                CoroutineManager.Instance.Stop(_refreshRoutine);
                _refreshRoutine = null;
            }

            DateTime expirationDateTime = DateTime.Now;
            _refreshTime = expirationDateTime.AddSeconds(expiresIn * 0.85f);
            Debug.Log(string.Format("<< API TOKEN WILL BE AUTOMATICALLY REFRESHED IN {0} SECONDS >>", expiresIn * 0.85f));

            UpdateManager.Instance.OnUpdate += OnUpdateEarly;
        }
    }

然后是真正监听调用的函数:

   public static void OnUpdateEarly()
    {
        if (!HasAlmostExpired) return;

        SSOCommunicator.RefreshToken(_refresh);
        UpdateManager.Instance.OnUpdate -= OnUpdateEarly;
    }

好像第一次停在某个地方,一旦它再次到达订阅,它在剩余时间内运行良好。

【问题讨论】:

  • “一开始只禁用一次,我再次启用它后,它在剩余时间内运行良好”——您如何在 WebGL 构建中再次启用它?
  • 没有具体说明。我假设它再次启用,因为我重新订阅了该事件。因为这是我唯一尝试打电话的事情。但进一步注意,这听起来很愚蠢。禁用后现在的流程如下 > 我点击场景中的一个按钮,然后循环几个函数,最终到达 UpdateManager.Instance.OnUpdate += OnUpdateEarly;
  • 是的,最好不要做出这样的假设。这样做只会使追踪问题变得更加困难。我怀疑您最终会得到多个单例实例,因此很可能会丢失“第一个”订阅。
  • 这听起来合乎逻辑,是的。我想了想。但是,我看不出我最终会如何获得超过 1 个实例。它总是检查是否已经有一个。此外,这并不能解释奇怪的 OnDisable 调用。更奇怪的是,只有在 WebGL 中
  • 有趣,很高兴你解决了它!

标签: c# unity3d gameobject


【解决方案1】:

我发现这是一个垃圾收集问题。因为我总是调用 UpdateManager.Instance 来调用一个函数,所以我从来没有硬引用那个实例。所以它只在 WebGL 上以某种方式在开始时被破坏了。我通过在脚本清醒时保持硬引用来解决它。所以只要有一个简单的 _updatamanager = Updatemanager.Instance 就解决了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 2015-10-25
    • 2017-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多