您现在的位置是:首页 >其他 >Unity3d 有关Invoke和 Coroutine 的执行条件的误解网站首页其他
Unity3d 有关Invoke和 Coroutine 的执行条件的误解
简介Unity3d 有关Invoke和 Coroutine 的执行条件的误解
认识错误的点
之前一直以为在父物体未激活的状态下, invoke 和 Coroutine 都不会执行。这里面有一点误区。
正解
- 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")}"
);
}
}
执行截图
- 父物体激活,脚本所在的物体未激活的情况:
2. 父物体和脚本所在的物体都未激活的情况:
3. 在父物体和子物体的都激活的情况,调用invoke 和 Coroutine,然后马上关闭子物体的激活状态:
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。