Unity 中,有一个特别重要的知识点,生命周期函数。这些东西全部都是系统定义好的,运行时自动调用,但需要继承 MonoBehaviour 类才能使用。这个类是从 Unity 中创建脚本就自动继承了。
正是因为继承了 MonoBehaviour 这个类,Unity 才能依次调用我们的脚本代码,执行游戏逻辑。
常用生命周期函数
1> 什么是生命周期
在 Unity 中,脚本可以理解为附加在游戏对象上的,用于定义游戏对象行为的指令代码。一个脚本必须绑定在游戏对象上才能被调用,才能开始它的生命周期。比如一颗子弹,从按下鼠标左键被生成时,附属于此游戏对象的脚本开始了它的生命周期,直到触发某个逻辑而被销毁时,才结束它的生命周期。期间可能依次调用了 Awake,Start,OnDestroy 等周期函数,也可能一直循环执行了 Update,FixedUpdate 等函数,而着一条或多条的执行线就是贯穿此脚本的生命周期。
2> Reset() + 示例
这个函数会在用户首次添加该组件时或单击 Reset 按钮时被调用,且只在编辑器生效。可应用于大批量生成修改编辑器节点,这么说大家可能不明白,举个例子。
假如我们有一个地图,需要添加大量的树(这里用圆柱代替),这些树需要组成特定图案,且以一定规则命名,这个时候笔刷就无法胜任工作了,或许程序运行时可通过代码动态修改,但是一旦程序运行结束,这些树又要被销毁了,且还很消耗程序运行资源。这个时候,通过 Reset 函数,可直接在编辑器阶段完成此需求。
在编辑器创建一个空节点"Reset",将脚本"Reset_Test.cs"赋予此空节点,代码和运行结果如下
需要注意的是,所有初始化操作都应在 Reset 中完成,因为它仅调用 Reset 函数,不会调用 Start 等函数,因为这是在编辑器中操作,程序还没运行 :
public int row = 3;
public int col = 9;
private void Reset()
{
GameObject t = null;
GameObject tree = GameObject.Find("Cylinder");
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
Vector3 position = new Vector3(i * 2, 0, j * 2);
t = Instantiate(tree, position, Quaternion.identity);
t.transform.SetParent(transform, false);
t.gameObject.name = "tree:" + i + "," + j;
}
}
}
3> 常用周期函数简单介绍 :
Unity脚本从唤醒到销毁有着一套比较完整的生命周期,系统自带的几个重要的方法如下 :
Awake -> Start -> FixedUpdate -> Update -> LateUpdate -> OnGUI -> Resourt -> OnDisable -> OnDestroy
Awake() : 此函数在脚本实例被载入时调用,仅被调用一次
OnEnable() : 当脚本被启用时调用一次,当游戏对象被禁用时,仅监听响应此函数
Start() : 在 Awake 之后和 Update 之前被调用,仅被调用一次
FixedUpdate() : 物理更新函数,循环执行,每物理帧 0.02 秒执行一次(不受 FPS 帧率影响,时间可更改),所有和物理相关的更新都应在此函数处理
Update() : 更新函数,每帧执行一次,受 FPS 帧率影响
LateUpdate() : 稍后更新函数,在所有 Update 执行完后调用,帧间隔时间和 Update 一样
OnGUI() : 在渲染和处理 GUI 事件时被调用,每帧都执行
OnDisable() : 当脚本被禁用时调用一次,当脚本反复被禁用或启用,则反复调用 OnDisable 和 OnEable
OnDestroy() : 当脚本被销毁时被调用,只会在被激活的物体上调用。当脚本所挂载的游戏物体被销毁时执行
Editor 编辑器
1> void Reset()
调用Reset是在用户点击检视面板的Reset按钮或者首次添加该组件时被调用。此函数只在编辑模式下被调用,Reset最常用于在检视面板中给定一个最常用的默认值
public GameObject target;
void Reset()
{
target = GameObject.FindWithTag("Player");
}
2> OnValidate
每当设置脚本的属性时都会调用OnValidate,包括反序列化对象时,这可能发生在不同的时间,例如在编辑器中打开场景时和域重新加载后
Initialization 初始化
1> void Awake()
当一个脚本实例被载入时Awake被调用。Awake用于在游戏开始之前初始化变量或游戏状态。在脚本整个生命周期内它仅被调用一次Awake在所有对象被初始化之后调用,所以可以安全的与其他对象或用GameObject.FindWithTag这类的函数搜索它们。每个游戏物体上的 Awake 以随机的顺序被调用。Awake 像构造函数一样只被调用一次。 Awake 总是在 Start 之前被调用。
2> void OnEnable()
当对象变为可用或激活状态时此函数被调用,OnEnable 不能用于协同程序。
using UnityEngine;
using System.Collections;
public class OnEnabledTest : MonoBehaviour
{
void OnEnable()
{
print("This script was enable");
}
}
3> void Start()
Start 仅在Update 函数第一次被调用前调用,在 behaviour 的生命周期中只被调用一次,它和 Awake的不同是 Start只在脚本实例被启用时调用。可以按需调整延迟初始化代码。
Awake 总是在Start 之前执行,允许你协调初始化顺序,在游戏运行过程中实例化对象时,不能强制执行此调用,初始化目标变量,目标是私有的并且不能在检视面板中编辑。
using UnityEngine;
using System.Collections;
public class StartTest : MonoBehaviour
{
private GameObject target;
void Start()
{
target = GameObject.