【Unity】函数执行顺序


单独物体

单独物体同一脚本内

常用函数执行顺序如下图:

单独物体不同脚本内

空节点物体按先后顺序添加三个脚本SequenceASequenceBSequenceC

脚本内容格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using UnityEngine;

public class SequenceA : MonoBehaviour
{
private void Awake()
{
Debug.Log("A Awake");
}
private void OnEnable()
{
Debug.Log("A OnEnable");
}
private void Start()
{
Debug.Log("A Start");
}
private void OnDisable()
{
Debug.Log("A OnDisable");
}
private void OnDestroy()
{
Debug.Log("A OnDestroy");
}
}

输出:

C Awake –> C OnEnable –> B Awake –> B OnEnable –> A Awake –> A OnEnable –> C Start –> B Start –> A Start –> A OnDisable –> B OnDisable –> C OnDisable –> A OnDestory –> B OnDestory –> C OnDestory

小结:

  • AwakeOnEnable这两个函数基本上是绑定在一块的,要执行一起执行,其他的函数则按照基础函数周期顺序执行

  • AwakeOnEnableStart优先执行后挂接的脚本;OnDisableOnDestroy优先执行先挂接的脚本

  • 同一物体不同脚本的函数(例如AwakeStart)执行顺序只与挂接脚本时间的先后有关(后来先到),与脚本的层级关系无关

在正规项目中,为了控制脚本之间的执行顺序,一般会使用一个管理脚本来控制各个脚本之间的执行顺序。

使用脚本控制各个脚本执行顺序

创建空节点物体,其名称为Sequence,挂接如下脚本

1
2
3
4
5
6
7
8
9
10
11
12
using Unity.VisualScripting;
using UnityEngine;

public class Sequence : MonoBehaviour
{
private void Start()
{
transform.AddComponent<SequenceA>();
transform.AddComponent<SequenceB>();
transform.AddComponent<SequenceC>();
}
}

输出如下:

使用管理脚本控制脚本之间各个函数的执行顺序与直接挂接不一样:不同脚本的函数是完全按照基础顺序执行,没有后来先到的说法


多个物体

多个物体同一脚本

先后创建三个空节点,名称分别为:函数执行顺序01函数执行顺序02函数执行顺序03

三个物体都挂接SequenceA脚本,为了能区分log是哪个物体发出的,微调了一下脚本,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using UnityEngine;

public class SequenceA : MonoBehaviour
{
private void Awake()
{
Debug.Log($"{transform.name} A Awake");
}
private void OnEnable()
{
Debug.Log($"{transform.name} A OnEnable");
}
private void Start()
{
Debug.Log($"{transform.name} A Start");
}
private void OnDisable()
{
Debug.Log($"{transform.name} A OnDisable");
}
private void OnDestroy()
{
Debug.Log($"{transform.name} A OnDestroy");
}
}

输出:

小结:

  • AwakeOnEnable这两个函数基本上是绑定在一块的,要执行一起执行,其他的函数则按照基础函数周期顺序执行
  • AwakeOnEnableStart优先执行后挂接的脚本;OnDisableOnDestroy优先执行先挂接的脚本
  • 不同物体的同一脚本的函数执行顺序同样只与挂接脚本的时间先后有关,与物体创建的时间先后、物体层级、物体父子节点无关

使用脚本控制各个脚本执行顺序

创建一个空节点物体,挂接一个脚本,通过控制脚本的创建子物体和添加脚本的时机,来观察输出,判断函数执行顺序

实验组:

对照组一(改变物体的创造的先后顺序):

对照组二(改变物体添加脚本的先后顺序):

通过对照组一得出结论:OnDisableOnDestroy两个函数的执行先后顺序与该脚本所挂接物体创造的先后时间有关,先创建的物体优先执行

通过对照组二得出结论:AwakeOnEbableStart三个函数的执行先后顺序与脚本的添加时间有关,先添加的脚本先执行

总结

可以将函数大致分为两大类

  • OnDisableOnDestroy的执行顺序只与该脚本的创建时间有关,先创建的先执行。(无需考虑是否在同一物体、是使用脚本方法AddComponent创建还是使用Inspector创建)

    • 注:经过测试发现,如果是不同物体的不同脚本这两个函数的执行顺序不可控,完全随机(如α物体挂载A脚本,β物体挂载B脚本)。
  • AwakeOnEnableStart需要在两种情况下考虑

    • 使用Inspector创建:需要考虑挂载脚本的时间先后顺序,后挂载的脚本先执行(后来先到)
    • 使用AddComponent创建:先创建的脚本优先执行