UI上InvokeRepeating 不执行

因为 Time.scale = 0 了 ><。

InvokeRepeating 的同名函数调用

对同一个函数的 InvokeRepeating调用,前一个不会覆盖之前的同名函数调用。

有关Invoke和 Coroutine 的执行条件的误解

之前一直以为在父物体未激活的状态下, invoke 和 Coroutine 都不会执行。这里面有一点误区。

正解

  1. Coroutine 在父物体未激活状态下,确实不会执行。并且如果在父物体(包括祖先节点)没有激活的情况下,直接调用 StartCoroutine 会抛出不可 catch 的错误
    在这里插入图片描述2. invoke 在父物体(包括祖先节点)未激活的情况下,如果被调用,依然会执行。

测试代码

代码下载:Test_CallInvoke_CallCoroutine_When_GameObject_Active.unitypackage

物体层级:
在这里插入图片描述在这里插入图片描述
父物体代码:

using UnityEngine;

public class ParentNode : MonoBehaviour
{
    [SerializeField]
    private ChildNode ChildNode;

    private void Awake()
    {
        ChildNode.SetParent(this);
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.W))
        {
            Debug.Log("Get W Key Down");
            gameObject.SetActive(true);
            ChildNode.gameObject.SetActive(false);
            ChildNode.CallInvoke();
            ChildNode.CallCoroutine();
        }
    }

    [ContextMenu(nameof(Call_When_Inactive))]
    public void Call_When_Inactive()
    {
        gameObject.SetActive(false);
        ChildNode.gameObject.SetActive(false);
        ChildNode.CallInvoke();
        ChildNode.CallCoroutine();
    }

    [ContextMenu(nameof(Call_When_Active_Then_Inactive))]
    public void Call_When_Active_Then_Inactive()
    {
        gameObject.SetActive(true);
        ChildNode.gameObject.SetActive(true);
        ChildNode.CallInvoke();
        ChildNode.CallCoroutine();
        ChildNode.gameObject.SetActive(false);
    }
}

子物体的代码:

using System;
using System.Collections;
using UnityEngine;

public class ChildNode : MonoBehaviour
{
    private ParentNode _parentNode;

    public void SetParent(ParentNode parentNode)
    {
        _parentNode = parentNode;
    }
    
    private void Update()
    {
        Debug.Log(nameof(ChildNode));
    }

    public void CallCoroutine()
    {
        // if (!gameObject.activeInHierarchy)
        //     return;
        
        try
        {
            StartCoroutine(Internal_Called_From_Coroutine());
        }
        catch (Exception e)
        {
            // 注意,物体未激活,调用协程,异常不可捕捉
            Debug.LogError($"must can't catch error, {e}");
        }
    }
    
    public void CallInvoke()
    {
        Invoke(nameof(Internal_Called_From_Invoke), 3);
    }
    
    public void Internal_Called_From_Invoke()
    {
        Debug.Log(
            $"{nameof(Internal_Called_From_Invoke)}"
                  + $", 父物体激活状态: {(_parentNode.gameObject.activeSelf ? "true" : "false")}"
                  + $", 当前物体激活状态: {(gameObject.activeSelf ? "true" : "false")}"
            );
              
    }

    IEnumerator Internal_Called_From_Coroutine()
    {
        yield return new WaitForSeconds(3);
        
        Debug.Log(
                  $"{nameof(Internal_Called_From_Coroutine)}" 
                  + $", 父物体激活状态: {(_parentNode.gameObject.activeSelf ? "true" : "false")}"
                  + $", 当前物体激活状态: {(gameObject.activeSelf ? "true" : "false")}"
            );
    }
}

执行截图

  1. 父物体激活,脚本所在的物体未激活的情况:
    在这里插入图片描述2. 父物体和脚本所在的物体都未激活的情况:
    在这里插入图片描述3. 在父物体和子物体的都激活的情况,调用invoke 和 Coroutine,然后马上关闭子物体的激活状态:
    在这里插入图片描述
Logo

这里是一个专注于游戏开发的社区,我们致力于为广大游戏爱好者提供一个良好的学习和交流平台。我们的专区包含了各大流行引擎的技术博文,涵盖了从入门到进阶的各个阶段,无论你是初学者还是资深开发者,都能在这里找到适合自己的内容。除此之外,我们还会不定期举办游戏开发相关的活动,让大家更好地交流互动。加入我们,一起探索游戏开发的奥秘吧!

更多推荐