Instantiating Prefabs at runtime
预设物实时实例化
By this point you should understand the concept of Prefabs at a fundamental level. They are a collection of predefined GameObjects & Components that are re-usable throughout your game. If you don’t know what a Prefab is, we recommend you read the Prefabs page for a more basic introduction.
到此为止你需要在根本程度上明白预设物的概念.它们是预先确定的一组对象和组件,是可贯穿你的游戏重复利用的.
Prefabs come in very handy when you want to instantiate complicated GameObjects at runtime. The alternative to instantiating Prefabs is to create GameObjects from scratch using code. Instantiating Prefabs has many advantages over the alternative approach:
预设在你想实时实例复杂游戏对象是非常方便.或者使用代码来实例化预设物来创建游戏对象.实例化预设物有比其他方法有许多优势:
· You can instantiate a Prefab from one line of code, with complete functionality. Creating equivalent GameObjects from code takes an average of five lines of code, but likely more.
· 你可以从一行有完整功能的代码实例化一个预设物.从代码创建等价游戏对象平均要5行代码或更多.
· You can set up, test, and modify the Prefab quickly and easily in the Scene and Inspector.
· 你可以快速和容易地在场景和检视面板上创建,测试和更改预设物.
· You can change the Prefab being instanced without changing the code that instantiates it. A simple rocket might be altered into a super-charged rocket, and no code changes are required.
· 你可以更改被实例的预设而无需更改实例它的代码.一个简单火箭可能被改为超负荷火箭,而不需更改代码.
Common Scenarios
一般情形
To illustrate the strength of Prefabs, let’s consider some basic situations where they would come in handy:
例举预设物要点,让我们细数它们便利的基本情形:
1.Building a wall out of a single “brick” Prefab by creating it several times in different positions.
2.A rocket launcher instantiates a flying rocket Prefab when fired. The Prefab contains a Mesh,Rigidbody, Collider, and a child GameObject with its own trail Particle System.
3.A robot exploding to many pieces. The complete, operational robot is destroyed and replaced with a wrecked robot Prefab. This Prefab would consist of the robot split into many parts, all set up with Rigidbodies and Particle Systems of their own. This technique allows you to blow up a robot into many pieces, with just one line of code, replacing one object with a Prefab.
1.从一个简单的砖块预设物通过在不同位置多次创建而建成一堵墙.
2.一个火箭发射器当发射时实例一个飞行的火箭.预设物包含网格,刚体,碰撞器和尾部带有粒子系统的子对象.
3.一个机器人爆炸为许多碎片.完整的可操作机器人被销毁而替换为机器人残骸预设物.预设物将机器人组成部分拆分为多个部分,并都提供刚体和粒子系统.此技巧允许你爆炸一个机器人为多个碎片只需一行代码,使用一个预设物替换一个对象.
Building a wall
建造一堵墙
This explanation will illustrate the advantages of using a Prefab vs creating objects from code.
First, lets build a brick wall from code:
这里举例解释使用一个预设物对比从代码创建对象的优势.首先,让我们冲代码创建一堵砖墙:
// 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);
}
}
}
}
1.To use the above script we simply save the script and drag it onto an empty GameObject.
2.Create an empty GameObject with GameObject->Create Empty.
1.我们可以方便的保存上面的脚本并拖拽到一个空物体上.
2.使用游戏对象>创建空对象,创建一个游戏对象.
If you execute that code, you will see an entire brick wall is created when you enter Play mode. There are two lines relevant to the functionality of each individual brick: the CreatePrimitive line, and the AddComponent line. Not so bad right now, but each of our bricks is un-textured. Every additional action to want to perform on the brick, like changing the texture, the friction, or the Rigidbody mass, is an extra line.
如果你执行代码,当你在按下播放模式时你将看到一堵完整的砖墙.这是两行与每个单独砖块相关的函数:CreatePrimitive行和AddComponent行.现在还不坏,但我们每个砖块都是没纹理的.每个想要表现砖块的附加功能,像纹理,摩擦力或刚体质量都是一个额外的行.
If you create a Prefab and perform all your setup before-hand, you use one line of code to perform the creation and setup of each brick. This relieves you from maintaining and changing a lot of code when you decide you want to make changes. With a Prefab, you just make your changes and Play. No code alterations required.
如果你创建一个预设物并事先执行所以设置,你使用一行代码即可执行每个砖块的创建和设置.当你想做出改变时这将节约你维护和更改大量代码的时间.使用预设物,你只需更改和播放,不必更改代码.
If you’re using a Prefab for each individual brick, this is the code you need to create the wall.
如果你使用一个预设物到每个单独砖块,你只需给创建墙写代码.
// 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);
}
}
}
This is not only very clean but also very reusable. There is nothing saying we are instantiating a cube or that it must contain a rigidbody. All of this is defined in the Prefab and can be quickly created in the Editor.
这不仅利于整洁也利于再利用.不要说我们实例化一个立方体或者它必须包含一个刚体.所有这些都在预设物上定义且可以快速的在编辑器内创建.
Now we only need to create the Prefab, which we do in the Editor. Here’s how:
现在我们只需在编辑器内创建预设物,如下:
a) Choose GameObject > 3D Object > Cube
b) Choose Component > Physics > Rigidbody
c) Choose Assets > Create > Prefab
d) In the Project View, change the name of your new Prefab to “Brick”
e) Drag the cube you created in the Hierarchy onto the “Brick” Prefab in the Project View
f) With the Prefab created, you can safely delete the Cube from the Hierarchy (Delete on Windows,Command-Backspace on Mac)
选择游戏对象>3D对象>立方体
选择组件>物理学>刚体
选择资源>创建>预设物
在项目视图,改变你新建预设物名称为”砖块”
拖拽你创建在层级上的立方体到项目视图的”砖块”预设物上
随着预设物创建,你可以在层级上安全删除立方体
We’ve created our Brick Prefab, so now we have to attach it to the brick variable in our script. When you select the empty GameObject that contains the script, the Brick variable will be visible in the inspector.
我们已经创建了我们的砖块预设物,所以现在我们附加砖块变量到我们的脚本上.当你选定包含脚本的空游戏对象,砖块变量将显示在检视面板上.
Now drag the “Brick” Prefab from the Project View onto the brick variable in the Inspector. Press Play and you’ll see the wall built using the Prefab.
现在从项目视图拖拽”砖块”预设物到检视面板的砖块变量上.按播放,你将看到使用此预设物建造的墙.
This is a workflow pattern that can be used over and over again in Unity. In the beginning you might wonder why this is so much better, because the script creating the cube from code is only 2 lines longer.
这是一个工作流模式,可在Unity中反复使用.开始你会怀疑它为什么如此好,因为此脚本从立方体创建立方体只需两行.
But because you are using a Prefab now, you can adjust the Prefab in seconds. Want to change the mass of all those instances? Adjust the Rigidbody in the Prefab only once. Want to use a differentMaterial for all the instances? Drag the Material onto the Prefab only once. Want to change friction? Use a different Physic Material in the Prefab’s collider. Want to add a Particle System to all those boxes? Add a child to the Prefab only once.
但因为你使用预设物,你可以再次更改预设物.想更改大部分实例?使用一个不同的物理材质到预设物的碰撞器上.想添加一个粒子系统到所有方块?只需一次添加一个子对象到预设物.
Instantiating rockets & explosions
实例化火箭和爆炸
Here’s how Prefabs fit into this scenario:
这是预设物为何适合这种情形:
g) A rocket launcher instantiates a rocket Prefab when the user presses fire. The Prefab contains a mesh, Rigidbody, Collider, and a child GameObject that contains a trail particle system.
当用户按下发射一个火箭发射器实例一个火箭预设物.预设物包含一个网格,一个碰撞器和一个尾部包含粒子系统的子游戏对象.
h) The rocket impacts and instantiates an explosion Prefab. The explosion Prefab contains a Particle System, a light that fades out over time, and a script that applies damage to surrounding GameObjects.
火箭冲击并实例一个爆炸预设物.爆炸预设物包含一个粒子系统,一个全程时间渲染灯光和用于损坏周围游戏对象的脚本.
While it would be possible to build a rocket GameObject completely from code, adding Components manually and setting properties, it is far easier to instantiate a Prefab. You can instantiate the rocket in just one line of code, no matter how complex the rocket’s Prefab is. After instantiating the Prefab you can also modify any properties of the instantiated object (e.g. you can set the velocity of the rocket’s Rigidbody).
虽然可以通过代码建造一个完整的火箭游戏对象,手动添加组件并设置参数,但实例化一个预设物更方便.你可以只需一行代码实例化火箭,无论火箭的预设物如何复杂.实例化预设物之后,你也可以改变任何实例对象的属性(例如,你可以设置火箭刚体的速度).
Aside from being easier to use, you can update the prefab later on. So if you are building a rocket, you don’t immediately have to add a Particle trail to it. You can do that later. As soon as you add the trail as a child GameObject to the Prefab, all your instantiated rockets will have particle trails. And lastly, you can quickly tweak the properties of the rocket Prefab in the Inspector, making it far easier to fine-tune your game.
撇开更容易使用,你可以随后更新预设物.所以如果你创建一个火箭,你不需立即给它添加一个粒子尾部.你可以稍后再做.同时你添加尾部为一个子对象到预设物,所有你实例出的火箭将有粒子尾部.最后,你可以在检视面板上快速改变火箭预设物的属性,如此做更容易调整你的游戏.
This script shows how to launch a rocket using the Instantiate() function.
这个脚本显示如何使用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
//到按住ctrl键或鼠标,调用开火方法
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();
}
}
Replacing a character with a ragdoll or wreck
使用布娃娃或残骸替换一个角色
Let’s say you have a fully rigged enemy character and he dies. You could simply play a death animation on the character and disable all scripts that usually handle the enemy logic. You probably have to take care of removing several scripts, adding some custom logic to make sure that no one will continue attacking the dead enemy anymore, and other cleanup tasks.
让我们说说完全操控敌人角色和死亡.你可以简单给角色播放一个死亡动画并禁止所有平时控制敌人逻辑的脚本.你可能需要小心移除几个脚本,添加一些自定义逻辑以确定没人将继续攻击死亡的敌人,和其他清理工作.
A far better approach is to immediately delete the entire character and replace it with an instantiated wrecked prefab. This gives you a lot of flexibility. You could use a different material for the dead character, attach completely different scripts, spawn a Prefab containing the object broken into many pieces to simulate a shattered enemy, or simply instantiate a Prefab containing a version of the character.
一个更好的方法是立即删除完整角色并替换为一个残骸预设物的实例.这给你许多灵活性.你可以使用一个不同的材质给死亡角色,附加完整而不同的脚本,生成一个预设物包含着对象破坏为许多碎片来模仿一个破碎的敌人,或简单的实例一个预设物包含着一个角色的版本.
Any of these options can be achieved with a single call to Instantiate(), you just have to hook it up to the right prefab and you’re set!
任何这些选项都可使用一个简单调用Instantiate()获得,你只需给它你要设置的正确的预设物.
The important part to remember is that the wreck which you Instantiate() can be made of completely different objects than the original. For example, if you have an airplane, you would model two versions. One where the plane consists of a single GameObject with Mesh Renderer and scripts for airplane physics. By keeping the model in just one GameObject, your game will run faster since you will be able to make the model with less triangles and since it consists of fewer objects it will render faster than using many small parts. Also while your plane is happily flying around there is no reason to have it in separate parts.
最要记得的是你实例的残骸可用完全不同于原始对象的对象制作.例如,如果你有一个飞机,你将塑造两个版本.一个飞机由单个包含网格渲染和用于飞机物理学的脚本的游戏对象组成.由于保持模型为仅一个游戏对象,你的游戏将运行得更快因为你将可以使模型需要更少三角形和因为条由更少对象组成它将比使用许多小部分渲染得更快.而且当你的飞机飞行时没理由把它分为几个部分.
To build a wrecked airplane Prefab, the typical steps are:
建造一个飞机残骸预设物,典型的步骤是:
1.Model your airplane with lots of different parts in your favorite modeler
2.Create an empty Scene
3.Drag the model into the empty Scene
4.Add Rigidbodies to all parts, by selecting all the parts and choosing Component->Physics->Rigidbody
5.Add Box Colliders to all parts by selecting all the parts and choosing Component->Physics->Box Collider
6.For an extra special effect, add a smoke-like Particle System as a child GameObject to each of the parts
7.Now you have an airplane with multiple exploded parts, they fall to the ground by physics and will create a Particle trail due to the attached particle system. Hit Play to preview how your model reacts and do any necessary tweaks.
8.Choose Assets->Create Prefab
9.Drag the root GameObject containing all the airplane parts into the Prefab
1.用大量不同零件按你最爱的模型塑造你的飞机.
2.创建一个空场景
3.拖拽模型到空场景
4.添加刚体到所有零件,通过选定所有零件并选择组件>物理学>刚体
5.添加碰撞器盒子到所有零件,通过选定所有零件并选择组件>物理学>碰撞器盒子
6.一个额外特效,添加一个冒烟状粒子系统作为一个子游戏对象给每个零件
7.现在你有一个带有多重爆炸部分的飞机,它们因物理学作用掉落地面并创建一个粒子尾部用于附加粒子系统.点击播放浏览你的模型如何反应和做些必要的调整.
8.选择资源>创建预设
9.拖拽源游戏对象包含所以飞机零件到预设物上.
The following example shows how these steps are modelled in code.
下面例子演示了这些步骤如何通过代码仿制.
// 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);
}
}
Placing a bunch of objects in a specific pattern
放置一堆对象到一个特定模式
Lets say you want to place a bunch of objects in a grid or circle pattern. Traditionally this would be done by either:
要说你想放置一堆对象到网格或圆模式,习惯上将通过此两者之一做到:
1. Building an object completely from code. This is tedious! Entering values from a script is both slow, unintuitive and not worth the hassle.
2. Make the fully rigged object, duplicate it and place it multiple times in the scene. This is tedious, and placing objects accurately in a grid is hard.
1.完全从代码建造一个对象.这是乏味的!从脚本输入值也同样慢,不直观和不值得找麻烦.
2.制作好对象,复制它并放置它多次到场景内.这是多余的,并且放置对象精确到一个网格很难.
So use Instantiate() with a Prefab instead! We think you get the idea of why Prefabs are so useful in these scenarios. Here’s the code necessary for these scenarios:
所以使用Instantiate()函数和预设物替代!我们认为你会了解为什么预设物在这些情形如此有用.这是这些情形必需的代码:
// 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);
}
}
}