1. 程式人生 > >【Unity3D】利用預設、例項化Instantiate和協程完成生成器

【Unity3D】利用預設、例項化Instantiate和協程完成生成器

生成器這東西在遊戲中很常見,不如我們要隨機產生敵人,就需要用到這東西。說白了,我就是需要一個東西在我的要求下,產生大量的物件。在Unity3D直接就提供介面能夠輕鬆完成這一些,我開始還以為生成器是用Unity3D的粒子系統Particle System做的,其實不是,本身就有預設和例項化Instantiate幫你輕鬆完成一起。當然,生成也要遵守Unity3D的基本法則啊,不能說生成就生成,需要定時生成。定時生成,不應該在Update()函式中用匯編語言那種輪詢掛起的方式時刻在判斷的方式,Unity3D提供協程概念幫你完成定時任務。下面就用一個簡單的例子來說明這一切吧。


如上圖,只要我輕鬆點選滑鼠右鍵一下,就會有大量的立方體Cube落下來,要是這是金幣、玩具或者巧克力多爽啊!然後我再點滑鼠右鍵之下就會停止落下,就像關閉閥門一樣。同時,這裡生成立方體不是暴力了,每0.2s一個而已,不然顯示卡要爆,尤其我這種渣i3集顯。

那麼上述程式如何做呢?

一、場景佈置

1、2D部分沒什麼好說的,請自行參照《【Unity3D】公告欄與開始介面的佈置》(點選開啟連結)與《【Unity3D】UGUI自適應螢幕與錨點》(點選開啟連結)佈置好一個Text同時做一個自適應螢幕。


2、3D部分如下圖所示。立方體和平面請自行賦予黑色純色材質,材質使用不懂可以參考《【Unity3D】物體、材質的設定、物體位移與旋轉》(點選開啟連結)。


3、之後我們要給立方體Cube附上如下的指令碼Cube.cs,非常簡單。其實本來不寫也行,只是對於那些飛出視野外的立方體還是自覺銷燬吧,不然遊戲一直計算它瘋狂落下,飛流直下三千尺,疑似銀河落九天的立方體,在接近y負無窮的位置還在被CPU計算著座標,簡直CPU要炸。不會新增指令碼可以參考《【Unity3D】Helloworld》(

點選開啟連結)。

using UnityEngine;
using System.Collections;

public class Cube : MonoBehaviour
{

    // Use this for initialization
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if (gameObject.transform.position.y < -2)//一旦掉出Plane
        {
            GameObject.Destroy(gameObject);//摧毀物件
        }
    }

}
4、設定預設,這是佈置場景關鍵的一步。如下圖,和你設定材質一樣,在Assets設定一個Prefab。


之後直接將Cube拖進這個Prefab,這東西就是一個預設,意為:這東西以後將被複制多次,而Prefab中的就是模板。

此步必須在我們完全設定好Cube,包括賦予好指令碼,才能施行。


二、指令碼編寫

之後我們將為空物體GameObject賦予如下的Create.cs指令碼。

using UnityEngine;
using System.Collections;

public class Create : MonoBehaviour
{

    private IEnumerator coroutine;
    private bool isStart = false;//用於控制生成器是否進行的flag
    public GameObject CreateObject;//設定物體形式引數

    void Start()
    {
        coroutine = WaitAndPrint(0.2f);//WaitAndPrint函式將0.2s執行一次
    }

    void Update()
    {
        if (Input.GetMouseButtonDown(1))//如果按下滑鼠右鍵
        {
            if (!isStart)//沒開始
            {
                StartCoroutine(coroutine);//則開啟這個生成器唄
                isStart = true;
            }
            else
            {
                StopCoroutine(coroutine);//否則銷燬
                isStart = false;
                coroutine = WaitAndPrint(0.2f);//當然,銷燬之後要留種,為下次再開啟作準備              
            }
        }
    }

    private IEnumerator WaitAndPrint(float waitTime)//協程coroutine的存在,配合下面的yield return回撥,這段程式碼將被0.2s執行一次
    {
        while (true)
        {
            GameObject.Instantiate(CreateObject, gameObject.transform.position, gameObject.transform.rotation);//其實就這一段程式碼
            //CreateObject是被生成的物體,第二第三個引數分別指生成的位置與方向,這裡就是穿過來的位置的當前位置和方向了
            yield return new WaitForSeconds(waitTime);
        }
    }

}
然後在編輯器設定這個指令碼的CreateObject就是指那個Prefab,如圖:


至此,釋出,整個工程做完。下面重點說說,上面指令碼的意思,也就是本文的重點。

1、GameObject中的形式引數CreateObject就是指預設Prefab,也就是Prefab被傳進去這指令碼Create.cs以變數CreateObject的存在。這個傳值,可以參看《【Unity3D】同場景物體傳值與Vector》(點選開啟連結),這裡不再贅述了。

2、上面指令碼,複製物體,來來去去就是一行GameObject.Instantiate(CreateObject, gameObject.transform.position, gameObject.transform.rotation);。

GameObject.Instantiate()方法能將一個預設Prefab複製一次,這在Unity3D被稱作預設例項化Instantiate。

所以這些專有名詞就是用來唬人的,其實一點都不難。

3、上面指令碼,利用到Unity3D的協程,也就是Coroutine完成了一個類似Java定時器Timer的功能。《【Java】定時器、執行緒與匿名內部類》(點選開啟連結)。


對照API和這個實現功能的指令碼,估計大家已經明白得差不多了。

這裡用到了一個C#一個貌似沒什麼卵用,但又複雜的概念IEnumerator。其實根本就不用管他,照抄就是。整段函式和JavaScript中的setInterval,具體見《【JavaScript】一個同步於本地時間的動態時間》(點選開啟連結)非常相似,或者更應該說是settimeout,只要我們指明的了函式名,和時間間隔,它就會老老實實地自動執行了。