找回密码
 立即注册
查看: 719|回复: 0

[笔记] Unity中GameObject API解析

[复制链接]
发表于 2020-12-23 12:58 | 显示全部楼层 |阅读模式
本文节选自洪流学堂公众号专栏《郑洪智的Unity2018课》,未经允许不可转载。
洪流学堂公众号回复专栏,查看更多专栏文章。
洪流学堂,让你快人几步。你好,我是郑洪智。
GameObject我们已经很了解了,它本身没有功能,它是组件的容器,很多时候我们需要在脚本中操作GameObject。今天我们就来看看如何实现这些需求。
GameObejct相关的文档位于:https://docs.unity3d.com/ScriptReference/GameObject.html
这一篇我们会采用问题+答案的形式,告诉你如何解决游戏中常见的需求。
如何在脚本中获取自身所在的GameObject?

我们知道脚本必须挂在一个GameObject上面才能执行,那么如何知道当前脚本所挂载的GameObject是哪一个呢?
这就需要用到gameObject属性了。
gameObject属性可以在所有继承MonoBehaviour的类中获取到,因为脚本必须要挂在到一个物体上才能执行,这个gameObject就是脚本挂到的物体。
  1. using UnityEngine;
  2. public class Test : MonoBehaviour
  3. {
  4.     void Start ()    {
  5.         Debug.Log(gameObject.name, gameObject);
  6.     }
  7. }
复制代码
上面的代码就会打印出脚本所挂物体的名字。
注意这里Debug.Log传入了两个参数,这是为什么呢?
遇到这种问题,我们首先查一下Unity的文档。
为什么要查Unity的文档呢?







从图中可以看到,将光标移到Debug上面时,显示Debug类是属于UnityEngine这个命名空间的,也就是Unity提供的API。


Debug.Log有两种形式:
  1. public static void Log(object message);public static void Log(object message, Object context);
复制代码
第二种形式中可以传入一个Object类型的参数,传入这个参数时,在Console中显示的log会与脚本所在的物体关联。点击Console中这条信息时,会在Hierarchy中高亮这一个物体。



Log关联GameObject.gif
如何通过物体名字查找物体?

GameObject类中有一个静态(static)方法Find,用于通过名字查找场景中的物体。
什么是静态方法
静态方法是标记为static的方法。静态方法独立于实例对象存在。即使没有类的实例,仍然可以通过类名.静态方法调用。静态方法中不能访问实例成员,可以访问其他静态成员
静态方法在定义时需要在返回值类型前面加上static修饰符,比如:
  1. static void Walk(){
  2.     Debug.Log("Walking");
  3. }
复制代码
访问时,可以直接通过类名.方法名调用。比如查找物体的方法就是GameObject.Find("cat")。
查找的名称字符串中可以包含“/”,比如GameObject.Find("animals/cat")就只会查到父物体名字为animals的cat物体。如果“/”字符在字符串中最开始的位置,那么会在根节点开始找,比如GameObject.Find("/animals/cat")就只会查到根节点为animals物体的子物体cat。
查找过后,一定要判断一下是否为空,因为Find有可能找不到你想找的物体。
特别注意1
这个方法的效率比较低,不要在Update中调用此方法,否则可能会造成游戏卡顿。一般的做法是,在Awake或Start方法中通过Find找到,然后保存到成员变量中。
比如:
  1. using UnityEngine;
  2. public class Test : MonoBehaviour
  3. {
  4.     private GameObject cat;
  5.     void Start ()    {
  6.         cat = GameObject.Find("cat");
  7.         if(cat != null)
  8.             Debug.Log("找到了cat物体", cat);
  9.     }
  10. }
复制代码
特别注意2
这个方法无法找到active为false的物体。
那么如何查找active为false的物体呢?
1、不要使用Find,直接在代码中通过public的变量关联物体。
2、不要设置物体的active为false,先在游戏最开始时通过代码找到物体,然后通过代码设为false
3、通过transform.Find,我们明天会讲到。
如何修改物体的active状态?

修改物体的active状态是一个快速隐藏/显示物体的方法。物体的active是false时,物体上所有的组件都不会执行,相当于将物体隐藏了。
  1. gameObject.SetActive(false);
复制代码
特别注意
这个方法只会改变物体自身的active属性。如果该物体有子物体,那么子物体也会被隐藏,但是active属性不会变。如果该物体的父物体的active是false,即使将该物体的active设置为true,该物体也不会显示出来。
物体的active可以通过两个属性来判断:
activeInHierarchy 物体是否在Hierarchy中是激活状态。这个属性为true时,该物体及其所有父物体的active都为true。
activeSelf 物体自身的active属性是否为true,即使该物体的父物体的active可能为false。
如何通过tag查找物体?

除了通过物体的name查找物体,通过物体的tag也可以查找。Tag即在Inspector上设置的一个标签,如下图所示:




一个物体只能有一个Tag,但是一个Tag可以被多个物体使用。
通过tag查找有两个方法:
  1. public static GameObject FindWithTag(string tag);
复制代码
返回第一个查找到的标签为tag的active为true的物体,如果没有找到则返回null。
tag必须在TagManager中设置过,否则会抛出异常。异常内容是:UnityException: Tag: cat is not defined.含义是:标签:cat 没有定义。
  1. public static GameObject[] FindGameObjectsWithTag(string tag);
复制代码
由于一个Tag可以被多个物体使用,所以这个方法可以找到所有使用该标签的active为true的物体,并返回对应的数组。如果没有找到,会返回一个空数组(长度为0的数组)。
tag必须在TagManager中设置过,否则会抛出异常。异常内容是:UnityException: Tag: xxx is not defined.含义是:标签:xxx 没有定义。
如何用代码创建空物体?

有时候为了组织Hierarchy的结构,需要动态创建空物体作为文件夹使用。
创建空物体可以使用如下代码:
  1. GameObject go = new GameObject();
  2. go.name = "EmptyGameObject";
  3. GameObject dog = new GameObject("Puppy");
复制代码
new的时候可以传入一个字符串作为GameObject的名字。也可以不传,默认名字是New Game Object。也可以创建后再修改空物体的名字。
如何用代码创建内置几何体?

通过代码也很容易创建Unity中的几种默认几何体。
  1. public static GameObject CreatePrimitive(PrimitiveType type);
复制代码
其中PrimitiveType是一个枚举(enum)类型,包括的类型有:Sphere、Capsule、Cylinder、Cube、Plane、Quad。
具体的用法如下:
  1. GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
复制代码
上面的代码可以创建一个Cube,和通过菜单栏GameObject > 3D Object > Cube创建出来的Cube一致。
什么是枚举

枚举是一组命名整型常量。枚举类型是使用 enum 关键字声明的。
C# 枚举是值类型。换句话说,枚举包含自己的值,且不能继承或传递继承。
声明枚举的一般语法:
  1. enum <enum_name>
  2. {
  3.     enumeration list
  4. };
复制代码
其中,
enum_name 指定枚举的类型名称。
enumeration list 是一个用逗号分隔的标识符列表。
枚举列表中的每个符号代表一个整数值,一个比它前面的符号大的整数值。默认情况下,第一个枚举符号的值是 0.例如:
  1. enum Days { Sun, Mon, tue, Wed, thu, Fri, Sat };
复制代码
使用时,可以使用Days.Sun来表示星期日。
总结

本文讲解了和GameObject类相关的常见问题及API的用法。
但是由于GameObject类中还有一些不常用API,建议自行查阅GameObject文档获得更全面的了解:https://docs.unity3d.com/ScriptReference/GameObject.html
今日思考题

在Unity中通过代码尝试下讲到的和没讲到的API~
欢迎在留言区分享你的收获,和大家一起讨论。
别忘了分享给你学Unity的朋友,也许能够帮到他。
洪流学堂公众号回复专栏,查看更多专栏文章。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-22 23:49 , Processed in 0.091000 second(s), 27 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表