引言:在游戏设计中,需要用到的物体都可以用编辑器放在场景中。但很多时候,无法事先创建所有需要的物体,如子弹、刷新的怪物之类。这些要么是根据玩家操作而随时创建,要么是根据游戏玩法在特定时刻创建,都无法事先确定它们在什么时候出现。
而用脚本动态创建物体,即在游戏进行中创建物体,是一项基本技能,本文将详细讲解实现这一功能的基本方法
一、预制
预制就是一个物体的模版,在游戏开发中,一般将物体设为预制,详细见这篇文章:Unity入门
二、创建物体
利用预制创建物体,需要使用实例化方法Instantiate()。它需哟一个预制体的引用作为模版返回值总是新创建的那个物体的引用。如果预制体以GameObject类型传入,那么返回的结果也是GameObject类型。
在实际使用时,有时候要具体制定新建物体的位置、朝向和父物体,因此Intantiate()方法也有多重重载形式,区别在于参数不同。这里展示三种重载形式
重载形式 |
参数1 |
参数2 |
参数3 |
参数4 |
仅指定父物体 |
预制 |
父物体的Transform类型,null表示没有父物体,置于场景根节点 |
|
|
指定位置和朝向 |
预制 |
空间位置,世界坐标系,Vector3类型 |
朝向,Quaternion类型 |
|
指定位置、朝向和父物体 |
预制 |
空间位置,世界坐标系,Vector3类型 |
朝向,Quaternion类型 |
父物体的Transform类型,null表示没有父物体,置于场景根节点 |
预制体也可以用组件表示。由于组件可以代表所挂载的组件,因此如果以某个预制体上的组件作为模版,Instantiate方法依然会把该物体创造出来,同时返回新物体上同名的组件。这虽然保持了功能不变,但稍一不获取组件的操作。
下面举一个用脚本创建物体的例子
using UnityEngine; public class TestInstantiate : MonoBehaviour { public GameObject prefab;//设置为public,以便在编辑器中赋值 void Start() { GameObject objA=Instantiate(prefab,null);//在场景根结点创建物体 GameObject objB=Instantiate(prefab,transform);//创建一个物体,作为当前脚本所在物体的子物体 GameObject objC=Instantiate(prefab,new Vecrtor3(3,0,3),Quaternion.identity);//创建一个物体,确定位置和朝向 } }
用脚本创建物体在一些需要摆放精准图形的时候也会用到,下面是用脚本创建10个物体摆放成一个环形的例子
using UnityEngine; public class TestInstantiate : MonoBehaviour { public GameObject prefab; void Start() { for(int i=0;i<10;i++) { Vector3 pos=new Vector3(Mathf.Cos(i*(2*Mathf.PI)/10),0,Mathf.Sin(i*(2*Mathf.PI)/10);//用到了sin和cos在x-y坐标系中的定义 pos=pos*5;//半径=5 Instantiate(prefab,pos,Quaternion.identity); } } }
三、创建组件
通常使用GameObject.AddComponent()方法,以下代码先获取Cube物体,再给它添加Rigidbody组件
using UnityEngine; public class TestInstantiate : MonoBehaviour { void Start() { GameObject go=GameObject.Find("Cube"); go.AddComponent<Rigidbody>(); } }
四、销毁物体或组件
使用Destroy()方法可以销毁物体或组件,这里就不展开例子了。
但在这里有一个要点要注意:在执行Destroy操作后,并不会立即销毁该物体,而是稍后放在合适的时机去销毁。这样就保证了在那一帧里,对该物体的操作不会产生错误。
在个别情况下如果需要立即销毁,Unity提供了DestroyImmediate()方法。
五、定时创建和销毁物体
游戏中延迟创建物体和延迟销毁物体是常见的需求。
延迟创建一般用于等待动画结束和定时刷新怪物等。延迟销毁物体则用于定时让子弹、尸体消失等情况。
延迟需要准确定时,如在未来的第几秒执行。这里举例用简易的Invoke方法。该方法有两个参数,第一个参数是以字符串表示的方法名称,第二个参数表示延迟的事件,单位为秒。
Invoke方法可以延迟调用一个方法,但要求该方法没有参数也没有返回值
下面例子为用Invoke方法编写一个每隔0.5秒生成一个物体的动态效果
Using UnityEngine; public class TestInvoke : MonoBehaviour { public Gameobject prefab; int counter=0; void Start() { Invoke("CreatePrefab",0.5f); } void CreatPrefab() { Vector3 POs=new Vector3(Mathf.Cos(counter*(2*Mathf.PI)/10),0,Mathf.Sin(counter*(2*Mathf.PI)/10)); pos*=5; Instantiate(prefab,pos,Quaternion.identity); counter++; if(counter<10) { Invoke("CreatePrefab",0.5f); } } }
延迟销毁也可以用Invoke实现,但由于延迟销毁需求更加厂家,因此Unity为Destroy方法增添了延时的功能,Destroy的第二个参数用于制定销毁延迟的事件,如:
Destroy(cube,0.5f);