2016年12月25日 星期日

Day 26: 觸控、Camera Aspect Ratio

這個手機遊戲做了25天,都還不能實際以觸控的方式移動角色……今天終於要改變這一點啦!


到很久很久以前寫的PlayerMovement.cs,改一下程式碼:

public class PlayerMovement : MonoBehaviour 

{
    //-舊程式碼-

    public float movementSpeed;

    public float minPosX;

    public float maxPosX;
    //-舊程式碼-


    //記錄螢幕中間的X軸

    private float midScreenPosX;


    
    void Start()

    {

        //初始螢幕中間X軸

        midScreenPosX = Screen.width / 2f;

    }



    void Update () 

    {

        float movement = 0f;



        //-舊程式碼- (鍵盤控制移動)

        movement = Input.GetAxis ("Horizontal") * movementSpeed * Time.deltaTime;

        //-舊程式碼-



        //觸控移動角色

        if (Input.touchCount > 0) {  //玩家正在觸控裝置

            Touch touch = Input.GetTouch (0); //取得玩家第一個觸控點

            //檢查觸控點的位置在螢幕的左方還是右方,並計算出移動值

            movement = (touch.position.x < midScreenPosX ? -1f : 1f) * movementSpeed * Time.deltaTime;

        }



        //-舊程式碼-

        Vector3 newPos = new Vector3 (Mathf.Clamp(transform.position.x + movement, minPosX, maxPosX), transform.position.y, transform.position.z);
        transform.position = newPos;
        //-舊程式碼-

    }

}

首先,我宣告了一個儲存螢幕X軸中線的變數,因為我要讓玩家觸控左半邊螢幕時主角向左移動、觸控右半邊螢幕時主角向右移動。

Start()函數,我以Screen.width取得玩家裝置的螢幕寬度,除以2(也就是中間線),指定給midScreenPosX

觸控的重頭戲在Update()函數中。Input.touchCount會回傳目前玩家在裝置上的總觸控數,Input.touchCount > 0表示玩家至少有一根手指頭放在螢幕上。Input.GetTouch(int index)則用來取得玩家的觸控點,index值表示觸控點的索引值。例如,玩家把食指放在螢幕上不放開,接著又把中指放在螢幕上,Input.touchCount就會回傳2(兩個觸控點),Input.GetTouch(0)會回傳食指的觸控點,Input.GetTouch(1)會回傳中指的觸控點。

在此我只在乎玩家第一個在螢幕上的觸控點,也就是Input.GetTouch(0)Touch類別的position成員可取得觸控點的位置座標。我檢查touch.position.x < midScreenPosX (觸控點的X座標是否小於螢幕的中間線),如果成立,則把最終的移動數值乘一個-1f(向左移)。不成立則乘不影響數值的1f

回到Unity Editor,但是……該如何測試觸控呢?首先,準備好iPhone或Android手機,到App Store/Play Store下載Unity Remote 5,點開,會看到以下畫面:



跟著指示到上方選單選Edit→Project Settings→Editor,接著在Inspector欄中的Unity Remote標題下,把Device選為要測試的裝置。


進入Play Mode,Unity Editor就會把遊戲畫面自動投影在手機上了,Unity Remote 5在手機上的畫值會非常差,但這軟體主要是用來測試觸控的,所以不必太在意。


觸控手機螢幕的左邊和右邊,主角就會跟著左右移動了。

然而,還有一個問題需要解決。如果手機的螢幕不符合9:16的長寬比,顯示出的畫面會被裁掉一些,或多出幾兩條藍色的邊邊。


要解決這點,必須在Main Camera上加上一段Script,讓它適應每個螢幕的長寬比。開一個名為「ScaleCameraInAspectRatio.cs」。

public class ScaleCameraInAspectRatio : MonoBehaviour 

{
    //長寬比,預設為9:16

    public float aspectRatio = 9f / 16f;


   
    void Start()

    {

        Camera cam = GetComponent< Camera > ();

        //裝置螢幕的長寬比

        float screenRatio = (float)Screen.width / (float)Screen.height;

        //裝置螢幕長寬比和目標長寬比的比值

        float scale = screenRatio / aspectRatio;

        
        //裝置螢幕長寬比大於目標長寬比(Main Camera高度應維持,寬度縮小)

        if (scale > 1f) {

            Rect pixRect = cam.pixelRect; //Main Camera的矩形

            //設定寬度

            pixRect.width = pixRect.height * aspectRatio;

            pixRect.y = 0f;

            //顯示寬度要在(過寬的)螢幕正中央,所以要除2

            pixRect.x = ((float)Screen.width - pixRect.width) / 2f;

            //設定新的Main Camera矩形

            cam.pixelRect = pixRect;

        }

        //裝置螢幕長寬比小於目標長寬比(Main Camera寬度應維持,長度縮小)
        else {

            Rect pixRect = cam.pixelRect;

            //設定高度

            pixRect.height = pixRect.width / aspectRatio;

            pixRect.x = 0f;

            //顯示高度要在(過高的)螢幕正中央,所以要除2

            pixRect.y = ((float)Screen.height - pixRect.height) / 2f;

            //設定新的Main Camera矩形

            cam.pixelRect = pixRect;

        }

    }

}

這段程式碼有點複雜,主要為了在過寬或過高的螢幕正常顯示,所以必須把Main Camera的長/高設定為和裝置螢幕一樣,再根據目標長寬比調整Main Camera的高/長。

把這段Script加在Main Camera上,並在場景中多加一個Camera,這是為了要讓遊戲在螢幕長寬比不是9:16的裝置上,在螢幕兩側以黑邊蓋住。

把新加Camera的Clear Flags設為Solid Color,Background設為黑色,Projection設為Orthographic,並把Depth設為-2(才能顯示在Main Camera後面)。最後,把Audio Listener Component取消掉,以免場景上同時擁有兩個Audio Listener。


進入Play Mode,現在不論裝置螢幕為何種比例,遊戲都能正常顯示了。


待續。

沒有留言 :

張貼留言