2016年12月16日 星期五

Day 17: 子彈、敵人碰撞

完成裝備和敵人重生系統,終於可以來做遊戲的核心──子彈、敵人、玩家之間的碰撞了。


首先,把各物件間的碰撞結果列出來:



角的子彈有兩種,一種擊中便會消失,如皮卡耳、死亡之帽、竹蜻蜓、雷達,另一種擊中後仍可持續作用,如綠帽、爆炸頭、鐵頭功。

主角的子彈落打到敵人,會產生兩種動畫,分別為敵人的死亡動畫以及子彈的擊中動畫。我會把動畫另存於新的Prefab,並在兩者被Destroy時以Instantiate產生動畫。

馬上進入程式碼。先來寫主角發射的子彈的Script,「PlayerBulletHit.cs」:



public class PlayerBulletHit : MonoBehaviour 

{

    public GameObject hitAnimation = null; //子彈擊中動畫Prefab

    public bool destroySelf;  //是否為「擊中一次就消失」的子彈



    void OnTriggerEnter2D(Collider2D col)

    {

        if (col.gameObject.tag == "Enemy Bullet") {

            Destroy (col.gameObject);  //移除敵人


            
            if (destroySelf)

                Destroy (gameObject); //移除自身

        }  else if (col.gameObject.tag == "Enemy") {

            EnemyBeingHit enemyData = col.gameObject.GetComponent();

               
            //產生子彈擊中動畫

            if (hitAnimation != null)

                Instantiate (hitAnimation, enemyData.bulletAnimationPos.position, Quaternion.identity);

            col.gameObject.GetComponent ().BeingHit ();


            if (destroySelf)

                Destroy (gameObject);

        }

    }


}

再建立另一個「EnemyBeingHit.cs」,輸入以下程式碼:


public class EnemyBeingHit : MonoBehaviour 

{

    public GameObject dieAnimation = null;  //死亡動畫Prefab

    public Transform bulletAnimationPos; //產生子彈擊中動畫位置


    public void BeingHit()

    {

        if (dieAnimation != null)

            Instantiate (dieAnimation, transform.position, Quaternion.identity);



        Destroy (gameObject);

    }

}

先來看PlayerBulletHit.cs,它有兩個成員變數,第一個hitAnimation用來存「擊中敵人動畫」Game Object的Prefab,第二個destroySelf用來決定是否在擊中後會把自身移除。死亡之帽、竹蜻蜓、皮卡耳、雷達的子彈都只能擊中一次,所以之後要勾選Destroy Self。

若有其他Collider 2D進入子彈的Collider 2D,OnTriggerEnter2D會被呼叫。此函數內,以if判斷擁有該Collider 2D的Game Object的Tag,若為「Enemy Bullet」(敵方子彈),則移除敵方子彈,並根據Destroy Self來決定是否移除自己(子彈)。若Tag為「Enemy」(敵方),則指定型態為EnemyBeingHit的變數enemyDatacol.gameObject.GetComponent<EnemyBeingHit>()

GetComponent<>()是Unity Scripting常用的函數,可輕易在Script中取得Game Object的任一Component。例如,若一Game Object內有Rigidbody 2D Component,GetComponent<Rigidbody2D>()就可取得該Component。

這裡我以GetComponent<EnemyBeingHit>()取得之後會為敵人裝上的Enemy Being Hit (Script) Component。因為要讓子彈的擊中動畫出現在敵人正上方,所以讓每個敵人在Enemy Being Hit (Script) Component指定不同的動畫產生位置。之後呼叫EnemyBeingHitBeingHit()函數,讓敵人自行產生動畫及移除自身(因為每個敵人的死亡動畫不同,且子彈不知道自己擊中的敵人為何者,所以不能直接在PlayerBulletHit.cs中產生敵人死亡動畫)。

EnemyBeingHit.cs的BeingHit()函數和PlayerBulletHit.cs碰觸敵人的程式碼非常相似。先檢查是否擁有死亡動畫,若有,則產生該動畫的Game Object,並移除自己。


回到Unity,為所有主角的子彈新增Rigidbody 2D Component,並根據它們的形狀加上Circle Collider 2D, Box Collider 2D或Polygon Collider 2D Component。把Rigidbody 2D的Is Kinematic打勾,Collider 2D的Is Trigger打勾,再裝上剛寫好的Player Bullet Hit (Script) Component。把擊中動畫做成Prefab拉到Hit Animation欄,並設定好Destroy Self。





為所有敵人prefab加上Enemy Being Hit (Script)。一樣做好它們死亡動畫的Game Object Prefab,拉至Die Animation欄,並新建一個子Game Object作為它的Bullet Animation Pos。
(敵人死亡動畫和子彈擊中動畫的Game Object Prefab都必須加上Destroy After Seconds (Script) Component,並設定好時間,不然動畫會一直存留在Scene上)



最後,把所有敵人Prefab的Tag改成”Enemy”、所有敵人子彈的Prefab改成”Enemy Bullet”。進入Play Mode測試,現在除了玩家碰到敵人或敵人子彈不會受到傷害外,遊戲的核心機制已大致完成啦!


待續。

沒有留言 :

張貼留言