(010)Unity3d 有关Invoke和 Coroutine 的执行条件的误解

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,然后马上关闭子物体的激活状态:
    在这里插入图片描述
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值