文章目录

  • 6.1 组件的容器——GameObject
  • 6.2 创建物体
  • 6.2.1 创建空物体——Create Empty
  • 6.2.2 创建几何体物体
  • 6.2.3 用代码动态创建物体
  • 6.3 GameObject常用方法
  • 6.3.1 添加组件,AddComponent
  • 6.3.2 获取组件,GetComponent
  • 6.3.3 通过标签查找物体,FindWithTag
  • 6.3.4 通过名字查找物体,Find
  • 6.4.5 实例化游戏对象,Instantiate
  • 6.4.6 销毁游戏对象,Destroy


简介:我是一名Unity游戏开发工程师,皮皮是我养的猫,会讲人话,它接到了喵星的特殊任务:学习编程,学习Unity游戏开发。

于是,发生了一系列有趣的故事。

unity 获取本机IP unity获取游戏对象_Unity

6.1 组件的容器——GameObject

皮皮:“铲屎官,我有一个问题没想明白,为什么之前我们每次都是把脚本挂到Main Camera上,是只有Main Camera才能运行脚本吗?”

我:“当然不是呀,只是因为空工程中,场景里就只有一个Main Camera和一个Directional Light,为了测试脚本,就随便挂到Main Camera上了。事实上,我们也可以把脚本挂到Directional Light上测试之前的脚本,当然,我们还可以自己创建GameObject。”

unity 获取本机IP unity获取游戏对象_组件_02


皮皮:“什么是GameObject呀。”

我:“GameObject就是游戏对象的意思,在Unity中,所有实体都是游戏对象,比如摄像机Main Camera、直射光Directional Light,它们其实都是GameObject,你可以把GameObject理解为一个容器,不同能力的组件装在这个容器里,容器便具有了相应的能力,比如挂了Camera组件的GameObject,它便具备了摄像机的能力,挂了Light组件的GameObject,它便具备了灯光的能力。”

皮皮:“原来如喵,我懂了。那怎么创建GameObject呢?”

我:“来,看我变魔术。”

6.2 创建物体
6.2.1 创建空物体——Create Empty

Hierarchy视图中右键点击菜单Create Empty,即可创建一个空物体。

unity 获取本机IP unity获取游戏对象_Unity_03


默认空物体的名字为GameObject

unity 获取本机IP unity获取游戏对象_unity 获取本机IP_04


我们可以对它进行重命名,选中物体后,在Inspector最上方的输入栏中即可重新输入物体的名字,输入后按回车即可生效,比如我这里将物体重命名为EmptyGameObject

unity 获取本机IP unity获取游戏对象_组件_05

皮皮:“为什么这个EmptyGameObjectGame视图中看不见?”
我:“问得好,但我先不回答你这个问题,我们先来创建一个看得见的GameObject。”

6.2.2 创建几何体物体

Hierarchy视图中右键点击菜单3D Object - Cube

unity 获取本机IP unity获取游戏对象_GameObject_06


此时场景中出现了一个正方体Cube

unity 获取本机IP unity获取游戏对象_GameObject_07


这回,我们看见了,一个看得见的GameObject

unity 获取本机IP unity获取游戏对象_Unity_08


我:“老皮,你自己观察观察,这个Cube和我们刚刚创建的空物体EmptyGameObject有什么不同?”

皮皮:“我发现了,Cube身上比EmptyGameObject多了好几个组件。一定是这些组件让Cube具有被看得见的能力。”

unity 获取本机IP unity获取游戏对象_学Unity的猫_09


我:“如喵可教也,一点即通。那你再观察观察,是什么让它的外形是正方体,而不是一个球体或者别的呢?”

皮皮用鼠标点来点去,点开了Mesh的选择框。

unity 获取本机IP unity获取游戏对象_unity 获取本机IP_10


皮皮:“原来秘密藏在这里呀。”

我:“不错不错,Mesh就是网格的意思,你可以理解为骨架,我们可以选择别的Mesh,比如球体Sphere,这样它的外形就变成一个球啦。”

unity 获取本机IP unity获取游戏对象_unity 获取本机IP_11

6.2.3 用代码动态创建物体

我:“刚刚我们都是手动创建物体的,有时候我们需要用代码动态创建物体。”
皮皮:“看到代码就犯困。”
我:“不要忘记你们喵星人的使命。其实很简单,一行代码就可以实现。”

创建一个脚本CreateGameObjectTest

unity 获取本机IP unity获取游戏对象_GameObject_12


代码如下:

using UnityEngine;

/// <summary>
/// 测试使用代码动态创建物体
/// </summary>
public class CreateGameObjectTest : MonoBehaviour
{
    void Start()
    {
        // 创建一个名字为EmptyGo的空物体
        var go = new GameObject("EmptyGo");
    }
}

CreateGameObjectTest脚本挂到Main Camera上,运行Unity,可以看到动态创建出了一个EmptyGo物体了。

unity 获取本机IP unity获取游戏对象_Unity_13


皮皮:“你上面是用代码动态创建一个空物体,那如果我想动态创建几何体呢?”

我:“Unity已经帮我们封装好接口了,使用GameObject.CreatePrimitive接口。”

例:

// 代码动态创建正方体
var go = GameObject.CreatePrimitive(PrimitiveType.Cube);

其中PrimitiveType是枚举类型,传对应的枚举值即可创建不同的几何体。

public enum PrimitiveType
{
	// 球体
    Sphere = 0,
    // 胶囊体
    Capsule = 1,
    // 圆柱体
    Cylinder = 2,
    /// 正方体
    Cube = 3,
    // 由很多个三角形组成的平面
    Plane = 4,
    // 由两个三角形组成的平面
    Quad = 5
}

皮皮:“看出来了,它只能创建一些简单的几何体形状,如果我想创建一个很复杂的几何体呢?”
我:“那就要建模软件在外部制作好然后再导入Unity中,包装成预设,然后通过预设实例化的方式来啦。”
皮皮:“太酷了,我要学建模。”
我:“你就是小学课本里那只钓鱼的猫,看见蝴蝶就去抓,结果鱼没钓到,蝴蝶也没抓到。你要耐下性子,后面有时间我再教你建模。”
皮皮:“铲屎官怎么啥都会!”
我:“艺多不压身,功到自然成。”

6.3 GameObject常用方法

GameObject是我们在Unity中最常打交道的一个类,所以我们需要熟悉它的接口和属性。

6.3.1 添加组件,AddComponent

GameObject可以理解为是组件的容器,通过AddComponent接口,可以动态给GameObject添加组件。

public Component AddComponent(Type componentType);
public T AddComponent<T>() where T : Component;

例:

// 添加BoxCollider组件
BoxCollider boxCollider = gameObject.AddComponent<BoxCollider>();

皮皮:“这个小写g开头的gameObject又是哪里来的呀?”
我:“在MonoBehaviour(包括子类)脚本中,小写g开头的gameObject表示组件所挂的物体本身。”

6.3.2 获取组件,GetComponent

相应的,我们可以通过GetComponent来获取GameObject上的组件。

public Component GetComponent(string type);
public T GetComponent<T>();
public Component GetComponent(Type type);

参数为string类型的GetComponent接口尽量少用,因为它用到了反射,第一是反射执行效率低,第二是字符串容易写错。
例:

// 获取BoxCollider组件,如果没有,则返回null
BoxCollider boxCollider = gameObject.GetComponent<BoxCollider>();

这个接口是从自身节点获取某个组件,找到一个则立即返回。
除此之外,还有如下一些接口:

接口

说明

GetComponentInChildren

从子节点获取某个组件,找到一个则立即返回

GetComponentsInChildren

从子节点获取某个组件,返回一个组件数组

GetComponentInParent

从父节点获取某个组件,找到一个则立即返回

GetComponentsInParent

从父节点获取某个组件,返回一个组件数组

GetComponents

从自身节点获取某个组件,返回一个组件数组

例:

// 从子节点获取BoxCollider组件,有多少个就返回多少个,参数true表示即使子节点不激活也照样查找
BoxCollider[] boxColliderArray = gameObject.GetComponentsInChildren<BoxCollider>(true);
6.3.3 通过标签查找物体,FindWithTag

物体是可以打标签的,选中物体,在Inspector窗口中的Tag属性下拉框中即可设置。

unity 获取本机IP unity获取游戏对象_学Unity的猫_14


要新增Tag可以点击Add Tag...

unity 获取本机IP unity获取游戏对象_组件_15


Tags框中点击+号,即可添加Tag,如下,添加了一个MyTag

unity 获取本机IP unity获取游戏对象_unity 获取本机IP_16


将物体的Tag设置为MyTag

unity 获取本机IP unity获取游戏对象_学Unity的猫_17


FindWithTag接口,通过标签在场景中查找物体,找到一个则立刻返回。

// 通过标签查找物体
public static GameObject FindWithTag(string tag);

例:

GameObject target = GameObject.FindWithTag("MyTag");

如果有多个物体具有相同的Tag,我们想查找所有物体,则要用另一个接口:

public static GameObject[] FindGameObjectsWithTag(string tag);

皮皮:“我怎么通过代码获取物体的Tag呢?”
我:“GameObject提供了tag属性。”

// 获取物体的tag
string tag = gameObject.tag;

皮皮:“那我们可以通过tag属性设置物体的Tag吗?”
我:“可以的。不过前提是设置的Tag需要存在,不能设置一个不存在的Tag,否则会报错的。”

// 设置物体的tag
gameObject.tag = "MyTag";

我:“还有,虽然GameObject提供了这个tag属性,但也不要泛滥使用,只有少数必要的情况才会使用Tag,具体后面实战项目我再演示吧。”

6.3.4 通过名字查找物体,Find

通过名字在场景中查找物体,找到一个则立刻返回,所以如果有多个物体具有相同的名字,这个时候就不大好区分了。

public static GameObject Find(string name);

该方法建议少用,因为场景中同名的物体概率还是比较大的。
另外,我们可以通过name属性获取当前物体的名字,如下:

// 获取当前游戏对象的名字
string name = gameObject.name;

皮皮:“也可以通过name属性修改物体的名字,对吗?”
我:“聪明。”

// 设置物体的名字
gameObject.name = "NewName";
6.4.5 实例化游戏对象,Instantiate

这个接口应该不陌生了,实例化可以理解为一次深拷贝,或者叫克隆。

public static Object Instantiate(Object original);

这个接口是Object类的,因为GameObject是继承Object,所以就有这个接口了。

6.4.6 销毁游戏对象,Destroy

在拍戏的时候,演员的角色剧情演完之后就杀青了,游戏对象也类似,它完成了它的任务后,就要被销毁或者对象池回收。
这个接口是Object类的,因为GameObject是继承Object,所以就有这个接口了。

public static void Destroy(Object obj);

皮皮:“什么是对象池,怎么回收游戏对象?”
我:“好奇猫,后面再教你,你先学好今天的内容。”


《学Unity的猫》——第七章:Transform的魔力,超越光速的移动