此时您应当能够从基本层面上了解预设 (Prefabs) 的概念。它们是预定义游戏对象 (GameObjects) 和组件 (Components) 的集合,可在游戏中重复使用。如果您不了解预设 (Prefab),建议您阅读预设 (Prefabs) 页面,了解更多基本介绍。
在运行时想要实例化复杂的游戏对象 (GameObjects),可以方便使用预设 (Prefabs)。实例化预设 (Prefabs) 的另一种选择是使用代码从头开始创建游戏对象 (GameObjects)。相比替代方法,实例化预设 (Prefabs) 有多个优势:
为说明预设 (Prefabs) 的强大,让我们来看看可用得上预设的一些基本情况:
该示例说明与使用代码创建对象相比,使用预设 (Prefab) 的优势。
首先,使用代码创建一堵砖墙:
// JavaScript function Start () { for (var y = 0; y < 5; y++) { for (var x = 0; x < 5; x++) { var cube = GameObject.CreatePrimitive(PrimitiveType.Cube); cube.AddComponent(Rigidbody); cube.transform.position = Vector3 (x, y, 0); } } } // C# public class Instantiation :MonoBehaviour { void Start() { for (int y = 0; y < 5; y++) { for (int x = 0; x < 5; x++) { GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube); cube.AddComponent<Rigidbody>(); cube.transform.position = new Vector3(x, y, 0); } } } }
进入播放模式 (Play Mode) 后,如果执行该代码,您将看到程序创建整堵砖墙。有两行与每块砖的功能相关:CreatePrimitive() 行和 AddComponent() 行。现在没有那么糟糕,只是每块砖没有纹理。想在砖上执行的每个附加操作,例如更改纹理、摩擦力或刚体质量,都是额外行。
如果创建预设 (Prefab) 并预先设置好,您将使用一行代码创建和设置每块砖。在决定想要进行修改时,这样可以减少维护和更改大量代码。只需要修改预设 (Prefab) 即可,无需修改代码。
如果针对每块砖使用预设 (Prefab),以下则是创建墙所需的代码。
// JavaScript var brick :Transform; function Start () { for (var y = 0; y < 5; y++) { for (var x = 0; x < 5; x++) { Instantiate(brick, Vector3 (x, y, 0), Quaternion.identity); } } } // C# public Transform brick; void Start() { for (int y = 0; y < 5; y++) { for (int x = 0; x < 5; x++) { Instantiate(brick, new Vector3(x, y, 0), Quaternion.identity); } } }
代码不仅非常干净,而且可重复使用。没有什么规范规定,我们要实例化一个立方体,或者它必须包含刚体。所有这一切都在预设 (Prefab) 中定义,且可以在编辑器 (Editor) 中快速创建。
现在我们只需在编辑器 (Editor) 中创建预设 (Prefab)。方法如下:
我们已经创建砖预设 (Brick Prefab),现在需将其附加到脚本的砖变量上。选择包含脚本的空游戏对象 (GameObject)。请注意,检视器 (Inspector) 中将出现一个新变量,名为“砖”。
现在从工程视图 (Project View) 将“砖 (Brick)” 预设 (Prefab) 拖到检视器 (Inspector) 中的砖变量上。按下“播放 (Play)”,将会看到使用预设创建的墙。
这是工作流模式,可在 Unity 中重复使用。在刚开始,您可能想知道为什么如此方便,因为脚本创建立方体只需 2 行代码。
但是由于现在使用预设 (Prefab),您可以在数秒之内调整预设。想要更改所有实例的质量?只需在预设 (Prefab) 中调整一次刚体 (Rigidbody)。想为所有实例使用不同的材质 (Material)?只需将材质 (Material) 拖到预设 (Prefab) 上一次。想要更改摩擦力?在预设 (Prefab) 碰撞器中使用不同的物理材质 (Physic Material)。想为所有立方体添加一个粒子系统 (Particle System)?向预设 (Prefab) 添加一次子对象。
以下是预设 (Prefabs) 适合该应用场景的方式:
尽管有可能完全用代码创建一个火箭游戏对象 (GameObject),手动添加组件 (Components) 并设置属性,实例化预设 (Prefab) 要简单得多。不管火箭预设 (Prefab) 多么复杂,可以只用一行代码实例化火箭。实例化预设 (Prefab) 后,还可以修改实例化的对象的任何属性(例如设置火箭刚体 (Rigidbody) 的速度)。
除了使用方便之外,随后还可以更新预设。因此,创建火箭之后,无需立即给它添加粒子 (Particle) 拖尾,可在以后添加。将拖尾作为子游戏对象 (GameObject) 添加到预设 (Prefab) 后,所有实例化的火箭将拥有粒子拖尾。最后,可以在检视器 (Inspector) 中快速调节火箭预设 (Prefab) 的属性,使得微调游戏变得更简单。
该脚本演示如何使用 Instantiate() 函数发射火箭。
// JavaScript // Require the rocket to be a rigidbody. // This way we the user can not assign a prefab without rigidbody var rocket :Rigidbody; var speed = 10.0; function FireRocket () { var rocketClone :Rigidbody = Instantiate(rocket, transform.position, transform.rotation); rocketClone.velocity = transform.forward * speed; // You can also acccess other components / scripts of the clone rocketClone.GetComponent(MyRocketScript).DoSomething(); } // Calls the fire method when holding down ctrl or mouse function Update () { if (Input.GetButtonDown("Fire1")) { FireRocket(); } } // C# // Require the rocket to be a rigidbody. // This way we the user can not assign a prefab without rigidbody public Rigidbody rocket; public float speed = 10f; void FireRocket () { Rigidbody rocketClone = (Rigidbody) Instantiate(rocket, transform.position, transform.rotation); rocketClone.velocity = transform.forward * speed; // You can also acccess other components / scripts of the clone rocketClone.GetComponent<MyRocketScript>().DoSomething(); } // Calls the fire method when holding down ctrl or mouse void Update () { if (Input.GetButtonDown("Fire1")) { FireRocket(); } }
假设您有一个完全绑定的敌人角色且已死亡。可播放一段角色死亡动画,然后禁用通常控制敌人逻辑的所有脚本。您可能需要小心删除一些脚本,然后添加一些自定义逻辑,以确保不再继续攻击该死亡的敌人角色,并执行一些其他清理工作。
更好的做法是立即删除整个角色,并使用实例化的破坏预设将其替换。这就为您提供 很大的灵活性。您可以将不同的材质用于死亡角色,附加完全不同的脚本,创建包含碎成多块的对象的预设 (Prefab) 以模拟消灭的敌人,或只实例化包含该版本角色的预设。
通过单个调用 Instantiate() 就可实现所有这些操作,只需将其挂载到正确的预设即可。
需记住的是,用来实例化 (Instantiate()) 的破坏物可由完全不同的对象(而非原始对象)构成。例如,如果有架飞机,则要准备两个版本的模型。其中一个版本,飞机包含带有网格渲染器 (Mesh Renderer) 的单个游戏对象和飞机物理学的脚本。只在一个游戏对象 (GameObject) 保留该模型,游戏将运行得更快,因为使用较少三角形就可以制作模型,包含的对象减少,因此渲染比使用很多小部件的模型更快。此外,当飞机良好飞行时,也没有理由将其分成单独的部件。
要创建一个破坏的飞机预设 (Prefab),一般步骤如下:
// JavaScript var wreck :GameObject; // As an example, we turn the game object into a wreck after 3 seconds automatically function Start () { yield WaitForSeconds(3); KillSelf(); } // Calls the fire method when holding down ctrl or mouse function KillSelf () { // Instantiate the wreck game object at the same position we are at var wreckClone = Instantiate(wreck, transform.position, transform.rotation); // Sometimes we need to carry over some variables from this object // to the wreck wreckClone.GetComponent(MyScript).someVariable = GetComponent(MyScript).someVariable; // Kill ourselves Destroy(gameObject); // C# public GameObject wreck; // As an example, we turn the game object into a wreck after 3 seconds automatically IEnumerator Start() { yield return new WaitForSeconds(3); KillSelf(); } // Calls the fire method when holding down ctrl or mouse void KillSelf () { // Instantiate the wreck game object at the same position we are at GameObject wreckClone = (GameObject) Instantiate(wreck, transform.position, transform.rotation); // Sometimes we need to carry over some variables from this object // to the wreck wreckClone.GetComponent<MyScript>().someVariable = GetComponent<MyScript>().someVariable; // Kill ourselves Destroy(gameObject); } }
第一人称射击游戏 (First Person Shooter) 教程介绍了如何使用布娃娃版替换角色,并且四肢也同步动画的最后状态。可在教程页面找到该教程。
假如您想将一组对象放入一个网格或圆形图形,通常可通过以下方式完成:
所以相反,使用预设 (Prefab) 进行实例化 (Instantiate())!我们相信,您已经明白预设 (Prefabs) 在这些应用场景中非常有用的原因。以下是这些应用场景所需的代码:
// JavaScript // Instantiates a prefab in a circle var prefab :GameObject; var numberOfObjects = 20; var radius = 5; function Start () { for (var i = 0; i < numberOfObjects; i++) { var angle = i * Mathf.PI * 2 / numberOfObjects; var pos = Vector3 (Mathf.Cos(angle), 0, Mathf.Sin(angle)) * radius; Instantiate(prefab, pos, Quaternion.identity); } } // C# // Instantiates a prefab in a circle public GameObject prefab; public int numberOfObjects = 20; public float radius = 5f; void Start() { for (int i = 0; i < numberOfObjects; i++) { float angle = i * Mathf.PI * 2 / numberOfObjects; Vector3 pos = new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)) * radius; Instantiate(prefab, pos, Quaternion.identity); } }
// JavaScript // Instantiates a prefab in a grid var prefab :GameObject; var gridX = 5; var gridY = 5; var spacing = 2.0; function Start () { for (var y = 0; y < gridY; y++) { for (var x=0;x<gridX;x++) { var pos = Vector3 (x, 0, y) * spacing; Instantiate(prefab, pos, Quaternion.identity); } } } // C# // Instantiates a prefab in a grid public GameObject prefab; public float gridX = 5f; public float gridY = 5f; public float spacing = 2f; void Start() { for (int y = 0; y < gridY; y++) { for (int x = 0; x < gridX; x++) { Vector3 pos = new Vector3(x, 0, y) * spacing; Instantiate(prefab, pos, Quaternion.identity); } } }
Page last updated: 2013-06-20