Unity脚本执行顺序和Start()函数

5

Unity的文档中有这样一句话:

默认情况下,不同脚本的Awake、OnEnable和Update函数会按照脚本加载的顺序调用(这是任意的)。

所以我有两个问题:

  1. 在这个上下文中,“任意”是什么意思?是随机的吗?
  2. 这是否也包括Start()函数与Awake()函数一起调用,或者Start()函数是否有自己特殊的行为,即使项目设置已经改变了脚本执行顺序也不会遵循它?

我一直想知道Unity如何在运行时“决定”其行为,特别是因为它似乎有时可以工作,但其他时间却会导致崩溃或其他问题,但文档并没有详细说明,我也找不到其他信息。


1
你可以在这些方法中设置一些调试输出并运行你的游戏脚本,这样Awake会打印出一些内容,而Start则会打印出其他内容,然后你可以阅读日志以澄清哪个先发生。 - Martin
http://answers.unity3d.com/questions/217941/onenable-awake-start-order.html - Everts
我不确定四年半之前的一个漏洞是否与这个问题相关。 - DisturbedNeo
请参考以下链接中的问题和答案:https://dev59.com/JpXfa4cB1Zd3GeqPfno4 - Thomas Hilbert
2个回答

4

那个陈述有点令人困惑。

Awake、OnEnable和Update将始终按顺序调用。

1.在这种情况下,“任意”是什么意思?它是随机的吗?

是的,它是随机的。但是,它不是指Awake、OnEnable和Update函数,而是指脚本。脚本是随机选择执行的。

2.这是否也包括Start()与Awake()一起,或者Start()是否有自己的特殊行为,即使该顺序已在项目设置中被更改,也不遵循脚本执行顺序?

答案1也应该回答问题2。 这不影响回调函数,如Start()、Awake()或OnEnable()。

我一直想知道Unity在运行时如何“决定”其行为,特别是因为它似乎有时会工作,但其他时间会导致崩溃或出现几乎没有解释的错误。

是的,这是真的。这也曾经发生在我身上。当您有许多脚本的大型项目时,这更容易发生。脚本是随机调用的。有时,您可能会出现空异常错误,因为GetComponent无法正常工作。这就是为什么制作了脚本执行顺序设置,以便您始终可以设置脚本执行的顺序。

我解决此类问题的方法是在协程函数中执行GetComponent。之后,我检查它是否为空。如果为空,请等待一帧,然后再尝试GetComponent

同样,这适用于脚本执行顺序而不是回调函数被调用的顺序。


2
澄清一下:默认情况下,例如您不同脚本中所有“Start”函数的执行顺序是随机的。有时会先执行“Script A”的“Start”,有时会先执行“Script B”的“Start”,但是所有“Awake”函数都将在第一个“Start”函数之前执行。 - Gunnar B.
@Disturbed,你能详细阐述一下随机顺序很愚蠢的想法吗?希望引擎读取你的思维是愚蠢的部分。 - Everts
我想知道的是,在这种情况下,“arbitrary”是否实际上意味着“random”,还是Unity对“arbitrary”的定义是“无论默认设置是什么”,区别在于每次运行应用程序时顺序是否相同。另一件我想知道的事情是,对于执行顺序的目的,Start()是否被视为事件函数,与Awake()和Update()相同,或者它是否不受此类排序的影响,并且无论设置如何都是任意的,因为文档并不是非常明确。 - DisturbedNeo
1
这很愚蠢,因为它不一致。如果某些东西由于我做或没做的事情而导致崩溃100%的时间,我可以忍受它。但是当某些东西由于脚本顺序是随机选择而在1%的时间内崩溃时,即使进行调试也很难复制。我只是觉得应该有一些一致的默认设置,即使该顺序很差,每次运行应用程序时顺序都相同。 - DisturbedNeo
我明白你的意思。我曾经遇到过这个问题,后来偶然发现了“脚本执行顺序设置”。至少,你有一种方法可以解决它,所以如果你注意到你的代码有时会抛出空异常,请使用“脚本执行顺序设置”。另一种解决方法是像我在答案中提到的那样,使用协程来进行GetComponent请求。 - Programmer
显示剩余7条评论

1

问题1

根据https://docs.unity3d.com/Manual/class-ScriptExecution.html,您可以手动设置脚本加载的顺序。如果您没有设置顺序,Unity可能会使用一些预定义的顺序(随机、字母表或其他)。

问题2

Awake()总是在Start()之前运行,并在脚本加载时调用https://docs.unity3d.com/ScriptReference/MonoBehaviour.Awake.html

要按特定顺序加载脚本,需要使用脚本执行顺序。为了确保以特定顺序运行每个对象的Start()函数,您需要创建一个“Manager”对象,以按您希望的顺序实例化对象。


1
显然,如果您不设置任何内容,顺序就是随机的。我知道Awake()在Start()之前运行,我只是想知道Start()是否受脚本执行顺序的影响,因为文档暗示它不受影响。 - DisturbedNeo
我不太理解这个问题。Start()会在对象启用脚本时立即运行,就在Update()之前运行。因此运行不同Start()的顺序是由您启用脚本的顺序确定的。 - Aidin
确切地说,这很令人困惑。文档称脚本的执行顺序为“Awake、OnEnable和Update函数”,但并未提及Start()函数。因此,在场景首次启动后,所有Awake函数被调用后,Start()函数会发生什么呢?它们是按照相同的顺序被调用,还是它们的顺序是任意的,这将使它们与Awake函数的顺序不同呢? - DisturbedNeo
好的,对于场景中已经存在的对象我不确定。你能否在不同的Start()函数中记录一些内容,看它是否看起来是随机的呢? 这就是为什么我写了一个保证顺序的方法,需要使用某种“管理器”对象,在按下播放时实例化你的对象。 - Aidin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接