目录
一、实例化
Object.Instantiate
该函数以与 Editor 中的“Duplicate”命令类似的方式创建对象的副本。如果要克隆的是 GameObject,也可以选择指定其位置和旋转(否则,默认为原始 GameObject 的位置和旋转)。如果克隆的是 Component,也将克隆其附加到的 GameObject,此时也可指定可选的位置和旋转。在许多项目中都是非常使用的函数,值得好好分析学习。
准备工作,定义好GameObject类变量、父物体及按钮事件,方便后续观察:
[SerializeField]
private GameObject instanPrefabs;
public Text transPostionText; //当前transform位置显示
public Transform spawn; //作为父物体
/// <summary>
/// 实例化物体
/// </summary>
public void OnClickBtnInstantiateObj() {
...
transPostionText.text = instanPrefabs.transform.position.ToString();
}
图0-1 准备工作
图0-2 注意当前坐标和位置
图0-3 设置预制体
①Instantiate(Object original)
简单生成
第一种写法可以默认生成在作为预制体的position位置上,不需要额外设置,若不是预制体也会以当前位置生成。参考如下代码:
public void OnClickBtnInstantiateObj() {
GameObject currentPrefabs = Instantiate(instanPrefabs); //默认生成在作为预制体的position
transPostionText.text = currentPrefabs.transform.position.ToString();
}
效果如下:
图1-1 第一种生成
可以看到第一种生成方式与最开始的预制物位置是完全一样的(toString()对double和float类型都是四舍五入)
②Instantiate(Object original, Transform parent)
作为子物体生成
public void OnClickBtnInstantiateObj() {
GameObject currentPrefabs = Instantiate(instanPrefabs, spawn); //transform.position数值不变,但变成相对于父物体的
transPostionText.text = currentPrefabs.transform.position.ToString();
}
图2-1 第二种生成
可以看到第二种生成方式当前坐标就发生了改变,虽然物体本身localPosition还是一样但却是相对于父物体值。
③Instantiate(Object original, Transform parent, bool instantiateInWorldSpace)
在自身当前世界坐标作为子物体生成。参考如下代码:
public void OnClickBtnInstantiateObj() {
GameObject currentPrefabs = Instantiate(instanPrefabs, spawn, true); //最后的bool为是否作为世界坐标生成
transPostionText.text = currentPrefabs.transform.position.ToString();
}
图3-1 第三种生成
同上看到物体是已经变成Spawn的子物体了,同时因为第三个参数-是否作为世界坐标生成定义了true所以物体位置也是预制体位置。
④Instantiate(Object original, Vector3 position, Quaternion rotation)
在定义的v3postion坐标上以rotation角度生成。参考如下代码:
public void OnClickBtnInstantiateObj() {
GameObject currentPrefabs = Instantiate(instanPrefabs, new Vector3(0,0,0), Quaternion.identity); //在0,0,0点生
transPostionText.text = currentPrefabs.transform.position.ToString();
}
图4-1 第四种生成
第四种直接定义了0,0,0的V3坐标,同时旋转设置为自身,即不变。
⑤Instantiate(Object original, Vector3 position, Quaternion rotation, Transform parent)
在定义的v3postion坐标上以rotation角度作为子物体生成(为世界坐标)。参考如下代码:
public void OnClickBtnInstantiateObj() {
GameObject currentPrefabs = Instantiate(instanPrefabs, new Vector3(0, 0, 0), Quaternion.identity, spawn); //依然为世界坐标的0,0,0,但变为spwan子物体
transPostionText.text = currentPrefabs.transform.position.ToString();
}
图5-1 第五种生成
以上就是实例化的非泛型五种重载方式,而提到泛型,相比很多人要么完全没听过,要么一知半解,我也是一样,通过两天的学习总结出下面要讲的泛型部分,仅代表个人理解。
二、泛型
①泛型理解
泛型总称:泛型程序设计(generic programming)是程序设计语言的一种风格或范式。泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型。也就是说你想要定义一个变量,但你以后似乎会以多种参数类型的形式去使用它,那么这个时候泛型就显得非常灵活。参考如下代码:
/// <summary>
/// 泛型例举
/// </summary>
private void ShowDataOfObj() {
Building<string> buildingName = new Building<string>();
buildingName.info = "School";
Debug.Log("建筑名:" + buildingName.info);
Building<int> buildingHeight = new Building<int>();
buildingHeight.info = 30;
Debug.Log("建筑高度:" + buildingHeight.info);
Player<GameObject> player = new Player<GameObject>();
player.name = "Lee";
player.HP = 100f;
Debug.Log("Name:" + player.name + " HP:" + player.HP);
}
/// <summary>
/// Building泛型类
/// </summary>
/// <typeparam name="T"></typeparam>
public class Building<T>
{
public T info; //建筑属性
}
/// <summary>
/// Player泛型类
/// </summary>
/// <typeparam name="T"></typeparam>
public class Player<T>
{
public T thisObj;
public string name;
public float HP;
}
我在这里定义了两个泛型类:Building和Player,其中T即为不确定待指明的类型,当Building被定义为string类的时候,其中的info因为定义的时候也是T泛型所以也变成了string。而Player中也是同理,除了用这种同步定义的方式,也可以在泛型类中定义有类型的变量。
②泛型使用
泛型深究各种用法还是有些过于繁琐和复杂了,所以我决定就以最常用的泛型来举例。List<T>和GetComponent<T> 参考如下代码:
List<string> textList = new List<string>(); //list泛型类作为string定义变量
void Start()
{
textList.Add("1234\n");
textList.Add("5678");
textA.text = textList[0] + textList[1];
GetAndAddComponent<CanvasGroup>(this.gameObject);//检查有无CanvasGroup组件,无则加
}
/// <summary>
/// 检查是否又组件,无则加
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
public T GetAndAddComponent<T>(GameObject obj) where T : Component {
if (!obj.GetComponent<T>()) {
obj.AddComponent<T>();
}
return obj.GetComponent<T>();
}
图2-1 泛型使用
三、延迟调用
①协程理解
我们不管协程真正在各类应用上的解释,就简单的把它理解成一个小的程序接口,如果程序读入用户需要开启协程,那么会优先执行协程内的内容,而延迟调用的核心就是协程中的yield return new WaitForSeconds()的函数,通过该函数可以实现延缓一定时间调用协程内容,从而实现延迟调用。如下图,其中协程最后会在⑤与⑥间反复,直到跳出for循环执行⑦:
图1-1 个人对执行顺序的理解
②协程使用
/// <summary>
/// 开始协程按钮
/// </summary>
public void OnClickBtnStartCo() {
Debug.Log("Button Done");
StartCoroutine(Co_Instantiate()); //开始协程
Debug.Log("Instantiate First Done");
}
/// <summary>
/// 延迟调用
/// </summary>
/// <returns></returns>
IEnumerator Co_Instantiate() {
Debug.Log("Coroutine Begin");
for (int i = 0; i < instanGroup.Length; i++) {
Instantiate(instanGroup[i]);
yield return new WaitForSeconds(waitTime);
Debug.Log("Yield return Done");
}
Debug.Log("Coroutine End");
}
图2-1 Log打印顺序
好今天我的总结就到这里,这一部分我个人也算是比较生疏的,讲起来一些表述和理解还真讲不好,也算是很尽力的在表达我的个人理解了,希望大家多多指导,相互分享看法。
如果觉得对你有帮助的话不如给个点赞加关注,如果有问题也欢迎评论或私聊我解决哦。