2016年12月17日 星期六

Day 18: 少林功夫好 II

又到眾所期待的少林功夫時間了。

所有裝備都完成了,獨缺少林功夫頭巾還沒任何實際的功能。好戲總要留到後頭,今天我將把少林功夫頭巾完成。


在Day 13,我已使少林功夫頭巾可隨機變成「鐵頭功」或「金鋼腿」。現在,到少林功夫頭巾的Prefab增加一個Box Collider 2D Component,並拖到Scene上確認該Collider 2D可以完全覆蓋主角的Collider 2D。


打開ShouLinKungFuIsGood.cs,加入幾行程式碼。


public class ShouLinKungFuIsGood : MonoBehaviour

{

    public SpriteRenderer sr;


    public Sprite invincible; //鐵頭功sprite

    public Sprite useless;  //金鋼腿sprite


    //剩餘可以阻擋(子彈or敵人)的次數

    private int blockingTimesLeft;
 
    //可以阻擋的次數

    private const int TotalBlockingTimes = 10;

    //頭巾的最低透明度(被子彈or敵人打到會減低透明度...也就是變得更透明)

    private const float MinAlphaVal = 0.5f;



    void Start()

    {

        if (Random.value >= .5f) {  //鐵頭功

            sr.sprite = invincible;

            //把剩餘阻擋次數設為可阻擋的次數

            blockingTimesLeft = TotalBlockingTimes;

            //把主角的Collider 2D取消(讓主角不會受到傷害)

            GameObject.FindGameObjectWithTag ("Player").GetComponent< Collider2d > ().enabled = false;


        } else {                   //金鋼腿

            sr.sprite = useless;

            //讓Collider 2D Component失效

            GetComponent< Collider2d > ().enabled = false;

        }

    }



    void OnTriggerEnter2D(Collider2D col)

    {
        //Collider 2D碰到敵人或敵人子彈

        if (col.gameObject.tag == "Enemy" || col.gameObject.tag == "Enemy Bullet") {
            //移除敵人或敵人子彈

            Destroy (col.gameObject);


            //減少阻擋次數

            blockingTimesLeft--;


            //阻擋次數剩0次

            if (blockingTimesLeft == 0) {
                //回復主角的Collider 2D

                GameObject.FindGameObjectWithTag ("Player").GetComponent< Collider2d > ().enabled = true;

                //刪除少林功夫好

                Destroy (gameObject);

            }  else {
                //根據剩餘阻擋次數設定頭巾的透明度

                sr.color = new Color (sr.color.r, sr.color.g, sr.color.b, MinAlphaVal + (1f - MinAlphaVal) * (float)blockingTimesLeft / (float)TotalBlockingTimes);

            }

        }

    }


}


我為這段程式碼增加了一個名為blockingTimesLeft的私有變數,用來代表鐵頭功還可以挨幾次傷害。下面兩個常數,TotalBlockingTimesMinAlphaVal代表鐵頭功總共可以挨幾次傷害,以及頭巾的最小透明度。在遊戲中,每挨一下傷害,頭巾就會變得更透明,用以告知玩家頭巾快要消失了。設定最小透明度可以防止頭巾還沒消失時就變得太過透明而幾乎不可見。
進入Start函數,先來講解較為簡單的else{}(隨機到金鋼腿)。因為金鋼腿沒有任何用處,所以只要把Collider 2D關掉就行了。而在Script中關掉Component的方式是先從GetComponent<>()獲取該Component,然後把.enabled設為false。這等同於在Inspector欄中把Component左上角的勾勾取消掉。

接著回頭看比較複雜的鐵頭功。我先把可以挨子彈的次數設好,再以GameObject.FindGameObjectWithTag(“Player”).GetComponent<Collider2D>().enabled = false把主角的Collider 2D Component取消掉,讓主角不會受到任何傷害(之後我會以主角的Collider 2D偵測傷害)。GameObject.FindGameObjectWithTag()是Unity Scripting裡非常好用的函數。只要傳入想取得的Game Object的Tag,Unity就會回傳該Game Object。然而使用這個函數的缺點是,當場景上Game Object過多的話,將會花許多時間找尋目標Game Object。好在這個遊戲的場景不會同時出現太多Game Object,用一下GameObject.FindGameObjectWithTag()也無妨。

因為我把金鋼腿的Collider 2D取消了,所以只有在鐵頭功下OnTriggerEnter2D()函數才可能被呼叫。在OnTriggerEnter2D()裡,若碰撞的Collider 2D為敵人或敵人子彈,就把它移除,並減少鐵頭功可以挨子彈的次數。

如果可以挨子彈的次數降為零(blockingTimesLeft == 0),則回復主角的Collider 2D,讓它會再度受到敵人或敵人子彈的傷害,並把鐵頭功的Game Object移除掉。如果可挨子彈數不為零,則會進入else{},設定頭巾sprite的透明度。new Color(float r, float g, float b, float a)的參數分別代表紅、綠、藍與Alpha值(透明度)。頭巾的紅、綠、藍值不需更動,所以直接把現在的紅、綠、藍值傳進去,而Alpha值則傳入MinAlphaVal + (1f - MinAlphaVal) * (float)blockTimesLeft / (float)TotalBlockingTimes,是以插值法計算出MinAlphaVal~1f之間的值。

進入Play Mode測試,一個嚴重的問題出現了:戴上「鐵頭功」頭巾時無法再撿取其他的掉落裝備。


這是因為當「鐵頭功」啟用時,主角的Collider 2D是被關閉的(記得GameObject.FindGameObjectWithTag(“Player”).GetComponent<Collider2D>().enabled = false這句落落長的程式碼)。要修正這個Bug,只需在FallingWeapon.cs中OnTriggerEnter2D函數多加一個else if()判斷式:

else if (col.gameObject.tag == "Shou Lin") {

    Destroy (col.gameObject); //刪除「鐵頭功」頭巾


    GameObject player = GameObject.FindGameObjectWithTag (“Player");

    //回復主角的Collider 2D

    player.GetComponent< Collider2d > ().enabled = true;


    //產生裝備

    GameObject weapon = (Instantiate (weaponPrefab, new Vector3 (player.transform.position.x, player.transform.position.y, -0.1f), Quaternion.identity) as GameObject);


    //將裝備的父物件設為主角

    weapon.transform.parent = player.transform;


    currEquippedWeapon = weapon;  //記錄裝備為當前配戴裝備,以供之後刪除


    Destroy (gameObject);  //刪除掉落裝備自身


}

這段程式碼其實和先前if判斷式內容差不多。不同的是,現在col.gameObject是「鐵頭功」的Game Object,而不是主角的Game Object,所以必須從GameObject.FindGameObjectWithTag(“Player”)來獲取主角Game Object。此外,還得把主角Game Object的Collider 2D復原。畢竟「鐵頭功」被新的裝備取代,主角應再度能受到傷害與正常接取裝備。

回到Unity Editor,把少林功夫頭巾Prefab的Tag改為”Shou Lin”。如此一來,當掉落裝備碰觸到「鐵頭功」的頭巾,也能替換裝備了。

再進入Play Mode測試一下,在配戴鐵頭功頭巾時也能正常替換裝備了!


待續。

沒有留言 :

張貼留言