Unity AR/VR开发:实战高手训练营
上QQ阅读APP看书,第一时间看更新

3.3 Unity的脚本系统

Unity的脚本系统在开发过程中十分重要,哪怕是最简单的游戏项目都需要使用脚本对用户的操作进行反馈。脚本可以用于场景中几乎所有的事件触发、游戏对象的移动和玩家的交互。本节将介绍关于Unity脚本创建、使用和命名等的内容。

3.3.1 创建脚本

在Unity中,创建脚本的方式通常有两种。

第一种方式:在Project面板中单击右键,依次选择Create→C# Script命令,如图3-6所示。

000

图3-6 在Unity中创建C#脚本

第二种方式:在顶部菜单依次选择Assets→Create→C# Script命令,如图3-7所示。

000

图3-7 在Unity中创建C#脚本

除此之外,我们还可以在Inspector视图中通过Add Component方式直接创建C#脚本。

【示例3-7】创建新脚本

在Unity中,使用上述任意一种方法创建一个名为FirstTest的脚本文件。双击该脚本文件,默认会通过Visual Studio打开,如图3-8所示。

000

图3-8 Visual Studio编辑器界面

新创建的C#脚本如代码清单3-8所示。

代码清单3-8 新创建的C#脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class FirstTest : MonoBehaviour {
 
    // 初始化方法
    void Start () {
        
    }
    
    // 在游戏的每一帧调用 
    void Update () {
        
    }
}

在以上代码中,public class FirstTest : MonoBehaviour表示该脚本名为FirstTest,继承自MonoBehaviour。只有继承自Monobehaviour的脚本,才能够使用Unity提供的API。

脚本中默认提供了Start和Update两个方法。这两个方法都是Unity生命周期的一部分,为private类型。Unity生命周期相关的方法在运行时由Unity自己调用。

其中,Start方法会在脚本第一次激活的时候调用,而Update方法在每一帧画面中都会被调用。

3.3.2 事件函数

Unity中的脚本和一般计算机程序的运行方式略有不同。一般的计算机程序会在某个循环内持续执行,直到完成任务。而Unity会通过调用事件内部事先声明的函数,把控制权交给某个脚本。每当某个函数执行完自己的任务后,控制权就会交回给Unity。这些函数被称为事件函数。当Unity响应游戏中的事件时,事件函数会被调用。

Unity使用了特定的命名机制,以识别响应特定事件的函数。以下列出了Unity中最常见也是最重要的一些事件函数。

1. 更新事件函数

在Unity中创建脚本时,脚本中会默认添加更新事件函数。

游戏在某种程度上可以看作一个动画,其中的每一帧图像都是事先设置好的。在游戏中,在渲染每一帧画面之前都需要改变游戏对象的位置、状态和行为。而Update函数的作用正是执行此类任务。例如:

void Update() {
    float distance = speed * Time.deltaTime * Input.GetAxis("Horizontal");
    transform.Translate(Vector3.right * speed);
}

和帧的渲染类似,物理引擎也需要断断续续更新。FixedUpdate事件函数会在每次物理更新前调用。例如:

void FixedUpdate() {
    Vector3 force = transform.forward * driveForce * Input.GetAxis("Vertical");
    rigidbody.AddForce(force);
}

除了Update和FixedUpdate函数,还有一个LateUpdate函数,感兴趣的读者可以查询官方文档了解其作用。

2. 初始化事件函数

每个新创建的脚本中都有一个Start函数,其作用是在游戏的第一帧更新前被调用。

当某个游戏场景开启的时候,会调用Awake、OnEnable、OnLevelWasLoaded等函数。

3. 界面事件函数

Unity中有一个OnGUI系统用来渲染并响应GUI控件。不过在UGUI系统推出后,GUI系统的使用频度和作用相对小了。以下代码在屏幕中显示一个Game Over的标签:

void OnGUI() {
    GUI.Label(labelRect, "Game Over");
}

4. 物理事件函数

物理引擎通过特定的事件函数来判断碰撞、触发等事件,比如OnCollisonEnter、OnCollisonStay、OnCollisionExit分别在碰撞开始、持续与结束时被调用。如果碰撞体设置为触发器,则可以调用对应的OnTriggerEnter、OnTriggerStay、OnTriggerExit函数。例如:

void OnCollisionEnter(otherObj: Collision) {
    if (otherObj.tag == "Arrow") {
        ApplyDamage(10);
    }
}

Unity脚本中有非常多的事件函数,它们的执行顺序是Unity预先确定的。其执行顺序可以参考图3-9所示。

000

图3-9 Unity中的脚本生命周期

【示例3-8】测试事件函数的执行顺序

创建一个名为LifeCyleTest的Script脚本,测试事件函数执行顺序的实现代码如代码清单3-9所示。

代码清单3-9 测试事件函数的执行顺序

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LifeCycleTest : MonoBehaviour {
    void Awake () {
        Debug.Log("Awake");
    }
 
    void Start () {
        Debug.Log("Start");
    }
    
    void FixedUpdate(){
        Debug.Log("FixedUpdate");
    }
 
    void Update () {
        Debug.Log("Update");
    }
 
    void LateUpdate () {
        Debug.Log("LateUpdate");
    }
 
    void OnDestroy () {
        Debug.Log("Destroy");
    }
}

接下来在场景中新建一个空白游戏物体,并将上述脚本挂载到该对象上。

在运行场景之前,确保选中Console窗口的Collapse选项,如图3-10所示。

000

图3-10 选中Collapse选项

运行场景,Console面板会输出各个生命周期函数的执行次数,如图3-11所示。

000

图3-11 Console面板输出的结果

场景运行结束后,可以清楚看到最先执行的是Awake函数,随后是Start函数,这两个方法都执行了一次;接下来调用的是FixedUpdate函数。Update和LateUpdate函数,这三个函数的执行频率一样,都是在每帧图像更新时执行一次;最后在结束场景运行时,调用Destroy函数。

这些事件函数只是Unity生命周期的一部分,其他部分会在后续章节详细讲解。

Unity Events不仅包含脚本的生命周期函数,还包含一些由系统自动调用的函数,也就是回调函数。限于篇幅,此处不详细讲解回调的概念,读者只需要明白,这些函数是由Unity在适当的时候自行调用。