2016年12月11日 星期日

Day 12: 發射子彈

今天要使裝備發射昨天完成的子彈。


新增一個名為「SpawnBullet.cs」的C# Script。


public class SpawnBullet : MonoBehaviour 
{

    public GameObject bulletPrefab;  //子彈Prefab

    public float interval;  //兩發子彈之間的時間

    public bool followMovement;  //子彈是否隨角色移動而移動



    void Start()

    {

        StartCoroutine (SpawnCoroutine ());

    }



    IEnumerator SpawnCoroutine()

    {
        while (true) {

            //產生子彈

            GameObject bullet = (Instantiate (bulletPrefab, new Vector3(transform.position.x, transform.position.y, 0.1f), Quaternion.identity) as GameObject);


            //如果要隨主角移動,把子彈設為裝備的子物件

            if (followMovement)

                bullet.transform.parent = transform;

            //等候下一發子彈的時間

            yield return new WaitForSeconds (interval);
        }

    }

}

bulletPrefabinterval分別用來儲存子彈的Prefab以及兩次發射之間的時間。followMovement讓我可以在Inspector選擇子彈是否隨主角移動而移動。死亡之帽、竹蜻蜓、皮卡耳、雷達的子彈不會隨主角移動而移動,但綠帽、爆炸頭會。

SpawnCoroutine中,我以Instantiate生產新的子彈。把Z軸設為0.1f是為了讓子彈出現在裝備後面(影響較大的只有「綠帽」這個裝備,要使綠光在綠帽後面)。接著我判斷是否要讓子彈followMovement,如果是,則把它的parent設為裝備。因為裝備是主角的子物件,所以如果把子彈設為裝備的子物件,主角移物時裝備會跟著移動,子彈也會跟著裝備移動。最後,我以yield return new WaitForSeconds(interval)來等待下一發子彈的發射時間。


回到Unity Editor,在Hierarchy欄把上次做的四種子彈拖到Project欄,成為Prefab。再到四種裝備的Prefab新增Spawn Bullet (Script) Component,把子彈的Prefab拖到Bullet Prefab欄,設好Interval。進入Play Mode測試,子彈射擊的座標不太正確,所以我用Day 8的方式,把位置不對的子彈包在一個空的Game Object裡,使之成為新的子彈Prefab,再調整內部實際子彈的位置。



接著來處理綠帽和爆炸頭。這兩種子彈的做法其實和之前的子彈差不多。將它們的Sprite拖至Scene,用新的Game Object包裝以調整座標,再拉到Project成為Prefab。


我想要讓綠帽的綠光子彈有從半透明閃爍的效果,所以到Animation視窗新增動畫。點擊左方的Add Property→Sprite Renderer→Color可在時間軸上調整Color.a,也就是透明度。


在綠帽和爆炸頭的裝備Prefab上,一樣新增Spawn Bullet (Script) Component,把剛剛做好的綠光和爆炸頭子彈Prefab拉到Bullet Prefab欄,設好Interval。為了讓它們跟隨角色移動,把Follow Movement欄打勾。

進入Play Mode測試,現在綠光和爆炸頭子彈確實會跟著主角移動而移動,然而,發射出的子彈永遠不會消失,所以時間一久,主角便會被成千上萬的綠光罩頂。回去看先前做的所有子彈,一旦發射出去,便永遠存留在Hierarchy欄,不會消失。這和先前掉落裝備的問題一樣,物件離開螢幕卻沒有被真正移除。我要用一與掉落裝備不同的方式來處理這個問題,因為綠光和爆炸頭不會離開螢幕,所以不能用Collider來偵測它們何時該消失。


建立一個名為「DestroyAfterSeconds.cs」的C# Script。


public class DestroyAfterSeconds : MonoBehaviour

{
    //過幾秒後移除Game Object

    public float second;



    void Start()

    {
        //second秒後呼叫DestroyGameObject函數

        Invoke ("DestroyGameObject", second);

    }



    void DestroyGameObject()

    {

        Destroy (gameObject);

    }

}

這段程式碼相當簡單,second代表要移除Game Object的時間。Start函數中,我呼叫了Invoke()函數。Invoke(string methodName, float time)函數會在time秒後呼叫名為methodName的函數。所以這段程式碼中,它會在second秒後呼叫DestroyGameObject函數,而DestroyGameObject函數會呼叫Destroy(gameObject)把自身移除。

把Destroy After Seconds (Script) Component加到每個子彈上,並為它們設定要消失的時間。死亡之帽、竹蜻蜓、雷達、皮卡耳應把Second設定為所有子彈都離開螢幕的時間,避免子彈在螢幕上突然消失。而爆炸頭、綠帽應把Second設定為小於裝備Interval的時間,避免同時出現兩道綠光或爆炸頭子彈。

進入Play Mode測試一下,完美。


繪圖進度

終於把每個角色的側身像畫完了,耶!



待續。

1 則留言 :