首先要明确的是MonoBehaviour是每个脚本的基类.每个Javascript脚本自动继承MonoBehaviour.使用C#或Boo时,需要显式继承MonoBehaviour.
 
 
 
 

Unity是不支持多线程的,也就是说我们必须要在主线程中操作它,可是Unity可以同时创建很多脚本,并且可以分别绑定在不同的游戏对象身上,他们各自都在执行自己的生命周期感觉像是多线程,并行执行脚本的,它是如何执行的呢?

我们做一个小小的实验来验证它。如下图所示,在Hierarchy视图中创建三个游戏对象,在Project视图中创建三条脚本,然后按照顺序将脚本绑定在对应的游戏对象身上。

三条脚本的代码完全一样,只是做了一点名称上的区分,代码写的比较丑我们只是作为测试!!

 
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
26
27
28
29
30
31
using UnityEngine;
using System.Collections;
 
public class Script0 : MonoBehaviour
{
 
void Awake ()
{
Debug.Log("Script0 ========= Awake");
}
 
bool isUpdate = false;
void Update ()
{
if(!isUpdate)
{
Debug.Log("Script0 ========= Update");
isUpdate = true;
}
}
 
bool isLateUpdate = false;
void LateUpdate()
{
if(!isLateUpdate)
{
Debug.Log("Script0 ========= LateUpdate");
isLateUpdate = true;
}
}
}

 播放游戏,看看他们的执行顺序。如下图所示,Awake、Update、LateUpdate、无论播放游戏多少次,他们执行的顺序是完全一样的。

接着我们在做一个测试,把Script0的Update方法注释掉!!

 
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
26
27
28
29
30
31
using UnityEngine;
using System.Collections;
 
public class Script0 : MonoBehaviour
{
 
void Awake ()
{
Debug.Log("Script0 ========= Awake");
}
 
// bool isUpdate = false;
// void Update ()
// {
// if(!isUpdate)
// {
// Debug.Log("Script0 ========= Update");
// isUpdate = true;
// }
// }
 
bool isLateUpdate = false;
void LateUpdate()
{
if(!isLateUpdate)
{
Debug.Log("Script0 ========= LateUpdate");
isLateUpdate = true;
}
}
}

 播放游戏,在看看它的结果。脚本的执行顺序和以前完全一样,Script0即使删除掉了Update方法,但是它也不会直接执行LateUpdate方法,而是等待Script1和Script2的Update方法都执行完毕以后,在去执行所有的LateUpdate方法。

通过这两个例子我们就可以清楚的断定Unity后台是如何执行脚本的了。每个脚本的Awake、Update、LateUpdate、FixedUpdate等等,方法在后台都有一个总汇。

后台的Awake()

{

       脚本0中的Awake();

       脚本1中的Awake();

       脚本2中的Awake();

}

       后台的方法 Awake、Update、LateUpdate、FixedUpdate等等都是按照顺序,等所有子脚本中的Awake执行完毕后在去执行 Start 、Update、LateUpdate等等。所以这里也就解释了Unity没有多线程的概念。

后台的Update()

{

       脚本0中的Update();

       脚本1中的Update();

       脚本2中的Update();

}

Unity还提供的一组协同任务的方法,其实它的原理和上面的完全一样,它们都是假的多线程。说了一圈我们又回到了Unity脚本的执行顺序上来?我们在看两条脚本!

在脚本2的Awake方法中创建一个立方体对象。

 
1
2
3
4
5
6
7
8
9
10
using UnityEngine;
using System.Collections;
 
public class Script2 : MonoBehaviour
{
void Awake ()
{
GameObject.CreatePrimitive(PrimitiveType.Cube);
}
}

在脚本0的Awake方法中去获取这个立方体对象 

 
1
2
3
4
5
6
7
8
9
10
11
12
13
using UnityEngine;
using System.Collections;
 
public class Script0 : MonoBehaviour
{
 
void Awake ()
{
GameObject go = GameObject.Find("Cube");
Debug.Log(go.name);
}
 
}

          如果脚本的执行顺序是 先执行Script2 然后在执行Script0那么Script0中的Awake就可以获取到该立方体对象,可是如果脚本的执行顺序是先Script0然后在Script2,那么Script0肯定会报空指针错误的。

          那么实际项目中的脚本会非常非常多,他们的先后顺序我们谁也不知道。所以我的建议一般在Awake方法中创建游戏对象或在Resources.Load(Prefab) 对象。在Start方法中去获取游戏对象,或者游戏组件,这样就可以确保万无一失了。

     如果说你非要控制脚本的执行先后顺序,也不是完全不行!Unity可以设置脚本执行的顺序。如下图所示,选择任意脚本在Inspector视图中点击Execution Order..按钮。

如下图所示,点击右下角的“+”将弹出下拉窗口,包括游戏中的所有脚本。添加脚本完毕后,Default Time下方数值越小的排在越前面脚本将率先执行,如果没有设置的脚本将按默认的顺序执行。

按照我的这个设置,程序将先执行Script0然后Script1最后Script2,欢迎一起讨论!!哇咔咔

 

46

It's rather complicated.

A simple test with 3.5.2 revealed, most concurrent functions (well, at least the ones I tested: Awake, Start, OnEnable, FixedUpdate/Update/LateUpdate) abide by the execution order defined for the scripts. The execution order of OnLevelWasLoaded is not affected by that, and therefore cannot be influenced by the user. This could be considered a bug.

The order of the four methods of a script related to initialization is always:

  • Awake()

  • OnEnable()

  • OnLevelWasLoaded() // (only on scene changes)

  • Start()

However, if your script was disabled in the first place(via Script.enabled=false), this order changes to:

  • OnLevelWasLoaded() // is now called first, before Awake()! (only on scene changes)

  • Awake()

  • [OnEnable()/Start() are not executed until the script is actually enabled]

In addition, note that Awake() and OnEnable() calls are connected/interleaved. Meaning, assuming a particular, user-defined execution order A and B with A*<*B,

  • each individual script of type A will execute its Awake(), immediately! followed by its OnEnabled()

  • then all scripts of type B will do the same

  • then all OnLevelWasLoaded() will be executed, in a (presumably) fixed but unpredictable order (assuming this scene was freshly loaded - otherwise this step is skipped completely)

  • then all Start() will be executed, in the order A,B

In particular, this means that OnEnable() of type A will be executed before Awake() of type B, while OnEnable() of type B will be executed after Awake() of type A. This overview explains it more clearly:

  • Awake() of Type A, instance 1

  • OnEnable() of Type A, instance 1

  • Awake() of Type A, instance 2 // order of instances cannot be influenced

  • OnEnable() of Type A, instance 2 // order of instances cannot be influenced

  • Awake() of Type B

  • OnEnable() of Type B

  • OnLevelWasLoaded() of Type ? // order cannot be influenced

  • OnLevelWasLoaded() of Type ? // order cannot be influenced

  • Start() of Type A

  • Start() of Type B

EDIT: Hm, this is a total mess. If DontDestroyOnLoad() is activated for such a script, this will get even more complicated, and the order changes yet again to:

  • [Awake() is never called again, only the very first time]

  • OnEnable()

  • OnLevelWasLoaded() // as opposed to being called before OnEnable(), when DontDestroyOnLoad() is notactivated

  • [Start() is never called again, only the very first time]

EDIT2: In addition, when DontDestroyOnLoad() is active, the user-defined execution order is no longer abided by!, neither by OnEnable(), nor by OnDestroyOnLoad().

EDIT3: WAH! I'm gonna stop testing now, this is a neverending story... As @Noisecrime noticed, there is actually another bug, where user-defined execution order is overriden if the script has an OnEnable() function!

Script A has OnEnable, Script B has not:

  • Awake() of Type A

  • OnEnable() of Type A

  • Awake() of Type B

Script B has OnEnable, Script A has not:

  • Awake() of Type B

  • OnEnable() of Type B

  • Awake() of Type A // after Type B!

Unity3d中默认函数调用顺序(MonoBehaviour)的更多相关文章

  1. Unity3D中默认函数的执行顺序

    直接用一张图来说明各个默认函数的执行顺序: FixedUpdate以固定的物理时间间隔被调用,不受游戏帧率影响.一个游戏帧可能会调用多次FixedUpdate.比如处理Rigidbody的时候最好用F ...

  2. Unity3D中事件函数的运行顺序

    Unity3D中脚本的生命周期是依照预先定义好的事件函数的运行流程来演化的,详细流程例如以下: Editor模式下Reset: 当脚本第一次被挂到GameObject上或用户点击Resetbutton ...

  3. Unity3D中关于场景销毁时事件调用顺序的一点记录

    先说一下我遇到的问题,我弄了一个对象池管理多个对象,对象池绑定在一个GameObject上,每个对象在OnBecameInvisible时会进行回收(即移出屏幕就回收),但是当场景切换或停止运行程序时 ...

  4. 【转】Unity3D中脚本的执行顺序和编译顺序

    支持原文,原文请戳: Unity3D中脚本的执行顺序和编译顺序 在Unity中可以同时创建很多脚本,并且可以分别绑定到不同的游戏对象上,它们各自都在自己的生命周期中运行.与脚本有关的也就是编译和执行啦 ...

  5. Unity3D中的Coroutine详解

    Unity中的coroutine是通过yield expression;来实现的.官方脚本中到处会看到这样的代码. 疑问: yield是什么? Coroutine是什么? unity的coroutin ...

  6. 【Unity3D/C#】Unity3D中的Coroutine详解

    Unity中的coroutine是通过yield expression;来实现的.官方脚本中到处会看到这样的代码. 疑问: yield是什么? Coroutine是什么? unity的coroutin ...

  7. Unity3D中的Coroutine具体解释

    本文太乱,推荐frankjfwang的:全面解析Coroutine技术 Unity中的coroutine是通过yield expression;来实现的.官方脚本中到处会看到这种代码. 疑问: yie ...

  8. Unity3D中C#和js方法相互调用

    通过查找资料,Unity3D中C#和js要相互调用彼此的方法,js文件必须放在"Standard Assets". "Pro Standard Assets" ...

  9. 【转】Unity3D中Layers和LayerMask解析

    http://blog.csdn.net/yupu56/article/details/50441151 Unity中是用int32来表示32个Layer层.int32表示二进制一共有32位(0-31 ...

随机推荐

  1. MyEclipse 2014安装properties文件插件

    安装步骤 1.下载PropertiesEditor插件 http://propedit.sourceforge.jp/index_en.html2.解压出features.plugins文件3.在My ...

  2. Spring的缺点有哪些--Ext扩展

    http://www.iteye.com/topic/1131284 1.JavaTear2014 --   发表时间:2013-07-17   最后修改:2013-07-17  Spring应用比较 ...

  3. java操作csv文档通用工具类

    https://blog.csdn.net/rodge_rom/article/details/78898015 另: 参考该博主的关于FTP, EXCEL, WORD, 等工具类文章...

  4. sqlite元数据

    sqlite数据库每个文件都是一个database,因此同一个文件内部不再划分database.sqlite没有提供像mysql那样的show tables;和desc 表名类似的语句.许多数据库的元 ...

  5. ios实例开发精品文章推荐(7.22)

    UIView 基本方法 UIView的一些基本方法理解:loadView.viewDidLoad.viewDidUnload.viewWillAppear,viewWillDisappear init ...

  6. IOS的动态性

    IOS的动态性主要来自以下方面的特性:动态类型,动态绑定,动态载入,SEL类型. 1.IOS的动态类型:(强类型)id可以在代码运行时判断对象的类型.使用id类型(又称强类型)可以在运行的时候使用任何 ...

  7. apache安装mod_ssl.so 出现 undefined symbol: ssl_cmd_SSLPassPhraseDialog错误解决

    很久很久以前,安装Apache的时候,根本没想过将来的某一天会使用到ssl,所以也就没有安装那个模块,结果今天需要用到的时候,却无从下手了. 由于在安装Apache的时候,mod_ssl.so这个文件 ...

  8. 树莓派进阶之路 (031) -字符问题(1) - GBK汉字编码表(转)

    转载:http://blog.sina.com.cn/s/blog_8184e033010109ug.html   基本简介 GB码,全称是GB2312-80<信息交换用汉字编码字符集基本集&g ...

  9. RSA加密异常

    在利用RSA进行数据加密时,出现如下异常: Exception bytes at com.sun.crypto.provider.RSACipher.a(DashoA13*..) at com.sun ...

  10. 实用的php购物车程序

    实用的php教程购物车程序以前有用过一个感觉不错,不过看了这个感觉也很好,所以介绍给需要的朋友参考一下. <?php//调用实例require_once 'cart.class.php';ses ...