使用组件控制游戏对象

在 Unity 编辑器中,你可以使用检视视图修改组件的属性。例如,改变游戏对象的变换组件的位置值,将会导致游戏对象的位置发生变化。类似地,修改渲染器材质的颜色或刚体的质量,将会对象的外观或行为产生相应的影响。大多数情况下,脚本也可以修改组件属性,从而操纵游戏对象。不同的是,脚本可以随时间改变属性的值,或响应用户的输入。通过在正确的时间修改、创建和销毁对象,可以实现任何类型的游戏。

访问组件

最简单也最常见的情况是,脚本需要访问游戏对象上绑定的其他组件。正如简介部分所述,组件实际上是某个类的实例,所以第一步是拿到要访问的组件实例的引用。这一步通过 GetComponent 函数完成。通常,你需要把组件实例分配给一个变量。在 C# 中使用下面的语法完成:

  1. void Start () {
  2. Rigidbody rb = GetComponent<Rigidbody>();
  3. }

在 UnityScript 中,语法稍有不同:

  1. function Start () {
  2. var rb = GetComponent.<Rigidbody>();
  3. }

一旦有了组件实例的引用,就可以像在检视视图 Inspector 中一样,设置它的属性值:

  1. void Start () {
  2. Rigidbody rb = GetComponent<Rigidbody>();
  3. // Change the mass of the object's Rigidbody.
  4. rb.mass = 10f;
  5. }

一个额外特性是,脚本可以调用组件实例的函数,这在检视视图中是不可能的:

  1. void Start () {
  2. Rigidbody rb = GetComponent<Rigidbody>();
  3. // Add a force to the Rigidbody.
  4. rb.AddForce(Vector3.up * 10f);
  5. }

还需要注意到,同一个游戏对象没有理由不能绑定多个自定义脚本。如果需要从一个脚本访问另一个脚本,可以像平常一样使用 GetComponent,只需要用脚本类的名字(或文件名)指定所需的组件类型。

如果尝试检索一个实际上尚未添加到游戏对象的组件,GetComponent 函数将返回 null;如果尝试在一个 null 对象上改变任意值,会在运行时抛出一个空指针错误。

访问其他对象

尽管脚本有时是孤立地运行,但是脚本跟踪其他对象的状态也很常见。例如,一个追击的敌人可能需要知道被追击玩家的位置。Unity 提供了许多不同的方式来检索其他对象,每种方式对应特定的情况。

用变量连接对象

查找关联对象的最直接方式是,为脚本添加一个公共的游戏对象变量:

  1. public class Enemy : MonoBehaviour {
  2. public GameObject player;
  3. // Other variables and functions...
  4. }

这个变量将像其他变量一样显示在检视视图 Inspector 中。

使用组件控制游戏对象 - 图1

现在,可以从场景视图或层级视图拖动一个对象到这个变量上进行分配。然后,就可以访问这个对象的 GetComponent 函数和组件变量。因此,你可以使用下面的代码:

  1. public class Enemy : MonoBehaviour {
  2. public GameObject player;
  3. void Start() {
  4. // Start the enemy ten units behind the player character.
  5. transform.position = player.transform.position - Vector3.forward * 10f;
  6. }
  7. }

另外,如果在脚本中声明了某个组件类型的公共变量,你可以拖动绑定了该组件的任意对象到该变量上。这时将直接访问组件,而不是游戏对象。

  1. public Transform playerTransform;

当处理永久链接的独立对象时,用变量连接对象是最合适的方式。你可以用一个数组变量来连接多个同类型的对象,但是这种连接必须在 Unity 编辑器中建立,而不是在运行时。不过,在运行时定位对象也很方便,Unity 提供了两种基本方式来实现这点。

查找子对象

有时,一个游戏场景将使用多个相同类型的对象,例如敌人、路径和障碍物。可能需要一个特定脚本来跟踪、监督它们,或者还需要对它们进行响应(例如,用一个寻路脚本维护所有的路径)。虽然使用变量连接这些对象是一种可行的方式,但是如果每个新行路径都需要拖拽到某个脚本的变量上,将使设计过程变得非常乏味。同样,如果一个路径被删除,那么移除变量对无效对象的引用就会变成麻烦。在这样的情况下,通常最好是把它们都作为子对象放到一个父对象中,用一个对象集合来管理它们。子对象可以通过父对象的变换组件 Transform 来检索(因为所有游戏对象都隐含一个变换组件):

  1. using UnityEngine;
  2. public class WaypointManager : MonoBehaviour {
  3. public Transform[] waypoints;
  4. void Start() {
  5. waypoints = new Transform[transform.childCount];
  6. int i = 0;
  7. foreach (Transform t in transform) {
  8. waypoints[i++] = t;
  9. }
  10. }
  11. }

你还可以使用 Transform.Find 函数查找特定名称的子对象:

  1. transform.Find("Gun");

在游戏过程中,如果父对象的子对象可以被添加和删除,这种方式可能很有用。一个很好的例子是,一把武器可以被捡起和放下。

按照名称或标签查找对象

只要场景中的游戏对象具有某些标识信息,那么,总是可以定位任意位置的游戏对象。可以用 GameObject.Find 函数按照名称检索单个对象:

  1. GameObject player;
  2. void Start() {
  3. player = GameObject.Find("MainHeroCharacter");
  4. }

也可以使用 GameObject.FindWithTag 和 GameObject.FindGameObjectsWithTag 函数按照标签来定位对象或对象集合:

  1. GameObject player;
  2. GameObject[] enemies;
  3. void Start() {
  4. player = GameObject.FindWithTag("Player");
  5. enemies = GameObject.FindGameObjectsWithTag("Enemy");
  6. }