In the Unity editor, you make changes to Component properties using the Inspector. So, for example, changes to the position values of the Transform Component will result in a change to the GameObject’s position. Similarly, you can change the color of a Renderer’s material or the mass of a Rigidbody with a corresponding effect on the appearance or behavior of the GameObject. For the most part, scripting is also about modifying Component properties to manipulate GameObjects. The difference, though, is that a script can vary a property’s value gradually over time or in response to input from the user. By changing, creating and destroying objects at the right time, any kind of gameplay can be implemented.
最简单和最常见的情况是脚本需要访问附加到同一游戏对象的其他组件。正如“简介”部分所述,组件实际上是类的实例,因此第一步是获取对需要使用的组件实例的引用。这是通过 GetComponent 函数来完成的。通常,希望将组件对象分配给变量,而此操作是使用以下语法以 C# 实现的:
void Start () {
Rigidbody rb = GetComponent<Rigidbody>();
}
在 UnityScript 中,语法略有不同:
function Start () {
var rb = GetComponent.<Rigidbody>();
}
获得对组件实例的引用后,可以像在 Inspector 中一样设置其属性的值:
void Start () {
Rigidbody rb = GetComponent<Rigidbody>();
// 改变对象的刚体质量。
rb.mass = 10f;
}
Inspector 中所没有的一项额外功能是可以在组件实例上调用函数:
void Start () {
Rigidbody rb = GetComponent<Rigidbody>();
// 向刚体添加作用力。
rb.AddForce(Vector3.up * 10f);
}
另外请注意,完全可以将多个自定义脚本附加到同一对象。如果需要从一个脚本访问另一个脚本,可以像往常一样使用 GetComponent,只需使用脚本类的名称(或文件名)来指定所需的组件类型。
如果尝试检索尚未实际添加到游戏对象的组件,则 GetComponent 将返回 null;如果尝试更改 null 对象上的任何值,将在运行时出现 null 引用错误。
虽然其他对象有时会孤立运行,但是脚本通常会跟踪这些对象。例如,追捕敌人可能需要知道玩家的位置。Unity 提供了许多不同方法来检索其他对象,每种方法都适合特定情况。
查找相关游戏对象的最直接方法是向脚本添加公共的游戏对象变量:
public class Enemy : MonoBehaviour {
public GameObject player;
// 其他变量和函数...
}
此变量在 Inspector 中可以像任何其他变量一样显示:
现在可以将对象从场景或 Hierarchy 面板拖到此变量上,对其进行分配。GetComponent 函数和组件访问变量与其他任何变量一样可用于此对象,因此可以使用如下代码:
public class Enemy : MonoBehaviour {
public GameObject player;
void Start() {
// 在玩家角色背后十个单位的位置生成敌人。
transform.position = player.transform.position - Vector3.forward * 10f;
}
}
此外,如果在脚本中声明组件类型的公共变量,则可以拖动已附加该组件的任何游戏对象。这将直接访问组件而不是游戏对象本身。
public Transform playerTransform;
在处理具有永久连接的单个对象时,将对象与变量链接在一起是最有用的方法。可以使用数组变量来链接同一类型的多个对象,但仍然必须在 Unity Editor 中(而不是在运行时)进行连接。在运行时定位对象通常很方便,因此 Unity 提供了两种基本方法来执行此操作,如下所述。
Sometimes, a game scene will make use of a number of objects of the same type, such as enemies, waypoints and obstacles. These may need to be tracked by a particular script that supervises or reacts to them (eg, all waypoints may need to be available to a pathfinding script). Using variables to link these objects is a possibility but it will make the design process tedious if each new waypoint has to be dragged to a variable on a script. Likewise, if a waypoint is deleted then it is a nuisance to have to remove the variable reference to the missing object. In cases like this, it is often better to manage a set of objects by making them all children of one parent object. The child objects can be retreived using the parent’s Transform Component (since all GameObjects implicitly have a Transform):
using UnityEngine;
public class WaypointManager : MonoBehaviour {
public Transform[] waypoints;
void Start() {
waypoints = new Transform[transform.childCount];
int i = 0;
foreach (Transform t in transform) {
waypoints[i++] = t;
}
}
}
还可以使用 Transform.Find 函数按名称查找特定子对象:
transform.Find("Gun");
当对象具有可以在游戏运行过程中添加和删除的子对象时,这种功能可能很有用。可以拾取和放下的武器就是这方面的一个很好的例子。
It is always possible to locate GameObjects anywhere in the scene hierarchy as long as you have some information to identify them. Individual objects can be retrieved by name using the GameObject.Find function:
GameObject player;
void Start() {
player = GameObject.Find("MainHeroCharacter");
}
还可以使用 GameObject.FindWithTag 和 GameObject.FindGameObjectsWithTag 函数按标签来查找对象或者对象集合:
GameObject player;
GameObject[] enemies;
void Start() {
player = GameObject.FindWithTag("Player");
enemies = GameObject.FindGameObjectsWithTag("Enemy");
}