2016年12月19日 星期一

Day 20: 生命值—UI

遊遊核心機制已大致完成。現在最重要的是讓主角在碰觸敵人或敵人子彈時損失生命,以及顯示玩家的分數。

兩者我都會以Unity的UI系統完成。Unity的UI系統讓處理按鈕、選單、文字、卷軸、影像等常用的UI元件變得非常簡單。我會以Unity UI的影像(Image)顯示生命值,以文字(Text)顯示分數。

在Hierarchy欄點Create→UI→Canvas新增一個Canvas。Unity會自動建立兩個Game Object──Canvas和EventSystem。Canvas和EventSystem是使用Unity UI不可或缺的元件。UI物件必須顯示於Canvas上,而UI物件的觸發事件(Event)如按扭的點擊則由EventSystem來處理。

在Canvas的Inspector中,把Canvas Scaler (Script) Component的Scale Mode選為「Scale With Screen Size」,使UI隨螢幕大小縮放,以適應不同像素的螢幕。(預設的「Constant Pixel Size」無論在任何螢幕大小,都維持同樣的像素大小,所以就算遊戲在大螢幕運行,UI原件也不會放大)

先來處理主角的生命值。在Hierarchy欄為Canvas建立一個新的Game Object,命名為「Life Indicator」。UI元件不同於一般Game Object,它們沒有Transform Component,取而代之的是Rect Transform Component。Rect Transform Component簡單來說,代表UI Canvas中的一塊矩形範圍。Rect Transform看似簡單,卻擁有許多複雜的功能。例如,它可以設定Anchors(在Scene中顯示的四個小三角形),使該UI元件隨父元件(parent)的比例縮放。

為了使UI在不同螢幕都能維持正常比例,我習慣在Canvas底下再建立一個新的Game Object,名為「Aspect Ratio Fitter」。把剛剛建立的「Life Indicator」拖至「Aspect Ratio Fitter」,成為它的子元件。並在Inspector為「Aspect Ratio Fitter」建立一個Aspect Ratio Fitter (Script) Component。把Aspect Mode設為Fit In Parent,Aspect Ratio設為0.5625。Fit In Parent選項使該Game Object延展以適應parent,也就是Canvas(也就是螢幕大小)的最大範圍。Aspect Ratio欄可以設定該Game Object的長寬比,使該Game Object在不同長寬比的螢幕中都能維持固定的比例。因為我的遊戲主要做給手機(螢幕比例大多是9:16),所以設為9÷16=0.5625。


接著在Scene視窗中把「Life Indicator」四個代表Pivot的小三角形移到螢幕左上方,形成一個小長方形。


並把它的Rect Transform的Left, Top, Right, Bottom都設為0。這樣一來在任何螢幕大小,Life Indicator都會維持一定比例。(因為四個「Pivot在父物件的位置」到四個「物件矩形的角」的距離是固定的)


這個就是用來顯示生命值的範圍了。

在Hierarchy中為Life Indicator新建三個UI→Image,並在Inspector中的Image (Script) Component把Source Image改為愛心的圖案。並像剛剛調整Life Indicator的Pivot一樣,把愛心的Pivot調到要顯示愛心的位置的四個角,再到Inspector把Rect Transform的Left, Top, Right, Bottom都設為0。生命值的顯示位置就設定好了。


設定完成後,就可以來寫Script了。建立一個名為「LifeIndicator.cs」的C# Script。


public class LifeIndicator : MonoBehaviour

{
    //三個愛心的Image

    public GameObject[] lifeImages;


    //剩餘生命

    private int currentLife;



    void Start()

    {

        currentLife = lifeImages.Length;

    }



    public void DecreaseLife()

    {
        //減少生命值

        currentLife—;

        //讓愛心的圖案消失

        lifeImages [currentLife].SetActive (false);



        if (currentLife == 0) {

            print ("Game Over");

        }

    }

}

型態為Game Object陣列的lifeImages是用來儲存剛剛在Scene上建立的三個愛心。currentLife代表剩餘的生命值。currentLifeStart()函數中被初始化為lifeImages.Length,也就是愛心的總數(之後會在Inspector設定)。

public void DecreaseLife()是主角在受到傷害時會呼叫的函數。它會減少生命值,使一個愛心的圖案消失,並檢查生命值是否已到達0。這裡暫時以print(“Game Over”)取代顯示遊戲結束的視窗。

接著到Character.cs,在OnTriggerEnter2D(...){}if判斷式內加入下行程式碼:

GameObject.FindObjectOfType< LifeIndicator > ().DecreaseLife ();

GameObject.FindObjectOfType<>()GameObject.FindGameObjectWithTag()頗為相似,只是前者以型態來找尋物件,並回傳該型態的物件。後者以Game Object的Tag來尋找Game Object,且回傳型態是GameObject。

因為在Scene上只有一個LifeIndicator物件,所以可以用GameObject.FindObjectOfType<>()找到該物件,並直接呼叫DecreaseLife()來減少生命值。

回到Unity,為「Life Indicator」Game Object新增Life Indicator (Script) Component,把Life Images的Size設為3,並把三個愛心的Image分別拉入Element 0-2中。

進入Play Mode測試一下,現在主角被物件打到後不只會改變表情,生命值也會正常降低了。

待續。

1 則留言 :