对象和预制体

Unity引擎本身就是面向对象的,我们的场景,包括静态的地面、房子,还有动态的主角、怪物,都是游戏对象(GameObject),我们的游戏其实就是通过各种游戏对象搭建起来的。在Unity编辑器的Hierarchy视图中,其实就是罗列了当前场景中的所有游戏对象。

而预制体(Prefab)则可以看成是能够实例化游戏对象的模板,我们将预制体实例化并指定一些参数,就可以生成某一类游戏对象。

创建游戏对象

实际开发中,我们创建游戏对象主要分为三种方式:

  1. 直接在编辑器中创建、编辑游戏对象
  2. 使用预制体(prefab)创建对象
  3. 使用代码创建对象

第一种自然不必多说,我们这里介绍下预制体和使用代码创建游戏对象。

使用预制体创建对象

预制体(Prefab)可以理解为创建一个实例的模板,Unity编辑器中,我们将场景中的对象拖进Project工程资源视图,就可以创建一个预制体。

这里我们创建了一个名为Cube的预制体。

下面代码中,我们实现了按下Space键,就实例化一个Cube的功能:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AddCubes : MonoBehaviour
{
    public GameObject cubePrefab;

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            GameObject obj = Instantiate(cubePrefab);
            obj.name = "cube" + cnt++;
            // 获取obj上的组件,设置参数等操作
            // ...
        }
    }
}

代码中,我们调用了Instantiate()实现实例化一个预制体,它的返回值是新实例化的游戏对象。实例化一个对象后,我们紧接着为新对象设置了一个名字,便于管理。

Instantiate()还有若干重载,可以设定对象的初始位置、初始空间变换参数等功能,这里就不多说了。

注意:脚本变量cubePrefab需要在Unity编辑器中赋值。

使用代码手动创建对象

其实在早先的游戏开发中,虽然没有Unity这种强大的图形化游戏编辑器,但这并不影响我们游戏的逻辑层架构是组件化的,无非就是需要我们手动new游戏对象,手动初始化、挂载游戏组件,再手动摆放游戏对象的位置。如果你不打算使用Unity规定的这些开发工作流,而仅仅是将Unity当做一个图形渲染框架,也是完全可以的,只不过非常麻烦,这里就不多介绍了。

销毁游戏对象

类似Instantiate(),Unity也提供了Destroy(),用来销毁对象,也能够支持延迟销毁。

这个函数有两个很实用的重载:

Destroy(Object obj)
  • obj:要销毁的游戏对象
Destroy(Object obj, float t)
  • obj:要销毁的游戏对象
  • t:销毁的延迟时间

激活或隐藏对象

Unity编辑器的Inspector面板中,游戏对象前有一个勾选框,用来控制对象的激活或隐藏。

代码中,我们可以通过如下两个属性来获取一个游戏对象是否处于激活状态:

  • gameObject.activeInHierarchy:对象是否激活(受父节点对象影响)
  • gameObject.activeSelf:对象是否激活(不受父节点对象影响)

我们可以使用gameObject.SetActive()来设置游戏对象是否激活,这个函数实际上修改的是activeSelf

public void SetActive(bool value);

另外要注意一点的是,如果游戏对象一加载进来就是非active的,那么其上的脚本代码不会执行。

获取游戏对象上的组件

游戏对象的各种参数都是存储在组件(Component)上的,我们可以通过GetComponent<T>()函数来获取一个游戏对象上的组件。

下面例子代码中,获取了当前游戏对象上的Rigidbody刚体组件。

Rigidbody rb = this.GetComponent<Rigidbody>();

对于一些常用组件,比如Transform,Unity为我们直接将其设为了游戏对象的属性,我们直接引用就可以了,不需要再调用GetComponent<T>()

Transform trans = this.transform;

注意:GetComponent<T>()是一个比较消耗性能的操作,如非必要,尽量避免在Update()中每帧循环调用。

查找游戏对象

我们的游戏对象都有一个名字,这个名字不是没意义的,我们可以通过这个名字进行搜索。下面代码中,我们全局搜索了一个名为Cube的游戏对象:

GameObject obj = GameObject.Find("Cube");

当然,实际开发中更常用的方法是从某一根节点进行搜索。对于对象树结构,它是通过Transform组件来保存父子关系的,因此tranaform.Find()的返回值是子游戏对象的Transform。后面在介绍Transform组件时,我们再详细介绍这部分内容。

Transform trans = this.transform.Find("Cube");

注意:

  1. 如果有多个同名的游戏对象,Find()函数也会返回一个对象,但这就没有意义了,要尽量避免同一对象树层级下,对象重名的情况。
  2. 上述第一个方法无法查找到非active的对象,而第二个方法可以,但只能查找某个节点对象的子节点。

Tag 标签

Unity中,除了可以根据对象名搜索,也支持根据对象标签搜索。

Inspector面板中,我们可以为一类对象设定一个标签。下面代码中,我们通过标签搜索,返回持有该标签的所有对象。

GameObject[] objs =  GameObject.FindGameObjectsWithTag("monsters");
作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。