天天看點

Unity-使用者輸入互動詳解Unity-使用者輸入互動詳解1.簡介2. 虛拟輸入軸(Virtual axes)3. 在PC端輸入4. 在移動端輸入

Unity-使用者輸入互動詳解

1.簡介

輸入操作是遊戲的基礎操作之一。

Unity支援的操作方式:

  • 滑鼠、鍵盤,小鍵盤(PC)
  • 搖桿(主機)
  • 觸屏操作、重力傳感器、手勢(移動平台)
  • VR,AR
  • 麥克風,攝像頭

2. 虛拟輸入軸(Virtual axes)

虛拟控制軸将不同的輸入裝置(比如鍵盤或搖杆的按鍵)都歸納到一個統一的虛拟控制系統中。

(比如鍵盤的w、S鍵以及搖桿搖杆的上下運動預設都統一映射到豎直(Verica)輸入軸上)

這樣就屏蔽了不同裝置之間的差異,讓開發者可以用一套非常簡單的輸入邏輯,同時相容多種輸入裝置。

使用 輸入管理器(Input Manager) 可以檢視、修改或增删虛拟軸。

現代的遊戲中往往允許玩家在遊戲中自定義按鍵,是以使用Unity的輸入管理器就更為重要要了。

通過一層虛拟軸間接操作,可以避免在代碼中直接寫死操作按鈕,而且還能通過動态修改虛拟軸的設定來改變鍵位的功能。

關于虛拟輸入軸,還有一些需要知道的内容:

  1. 腳本可以直接通過虛拟軸的名稱讀取那個軸的輸入狀态。
  2. 建立Unity工程時,預設建立了以下虛拟軸:
    • 橫向輸入和縱向輸入被映射在鍵盤的W、A、S、 D鍵以及方向鍵上
    • Fire1、 Fire2、 Fire3這三個按鈕映射到了滑鼠的左、中、右鍵以及鍵盤的Ctrl. AIt等鍵位上
    • 滑鼠移動可以模拟搖杆輸入(和滑鼠光标在螢幕上的位置無關),且被映射在專門的滑鼠偏移軸上
    • 其他常用虛拟軸,例如跳躍(Jump) 、确認(Submit) 和取消(Cancel)

## 2.1 添加和編輯虛拟輸入軸

要添加新的虛拟輸入軸,隻需要單擊主菜單的Edit > Projet Setings > Input 選項,單擊路街檢視視窗中會顯示一個輸入管理器,在裡面就可以修改或添加虛拟軸了。

注意:

虛拟軸具有正、負兩個方向。英文記作Positive和Negative.。

某些相反的動作可以隻用一個軸來表示。

比如,如果搖杆向上為正,那麼向下就是同一個軸的負方向。

每個虛拟軸可以映射兩個按鍵,第二個按鍵作為備用,功能一樣,備用的英文為Alterative。

2.2 虛拟輸入軸屬性表

下表是虛拟輸入軸的屬性表:

屬性 功能
Name 軸的名字。在腳本中用這個名字來通路這個軸
Descriptive Name 描述性資訊,在某些視窗中顯示出來以友善檢視(正方向)
Descriptive Negative Name 描述性資訊,在某些視窗中顯示出來以友善檢視(負方向)
Ncgative Button 該軸的負方向,用于綁定某個按鍵
Positive Button 該軸的正方向,用于綁定某個按鍵
Alt Negative Button 該軸的負方向,用于綁定某個備用按鍵
Alt Positive Button 該軸的正方向,用于綁定某個備用按鍵
Gravity 軸回中的力度
Dead 軸的死區
Sensitivity 敏感度
Snap 保持式按鍵。比如按住下方向鍵,則一直保持下的狀态,直到再次按上方向鍵
Invert 如果勾選,則交換正負方向
Type 控制該虛拟軸的類型, 比如搖桿、鍵盤是兩種不同的類型
Axis 很多搖桿的輸入不是按鈕式的,這時就不能配置到Button裡面,而是要配置到這裡。可以了解為實際的操作軸
Joy Num 當有多個控制器時,要填寫控制器的編号

上表中的Gravity、Dead 等屬性需要解釋一下。

2.2.1 Gravity

現代遊戲的方向輸入和早期遊戲的方向輸入不太一樣。

早期遊戲中,上、中、下都是離散的狀态,可以直接用1、0、-1來表示。

而現代遊戲輸入往往具有中間狀态,比如0、0.35、 0.5、0.7、1, 是帶有多級梯度的。

比如輕推搖杆代表走路,推到底就是跑步。

是以現代遊戲的輸入預設都是采用多梯度的模式。

雖然鍵盤沒有多級輸入的功能,但Unity依然會模拟這個功能,也就是說當你按住W鍵時,這個軸的值會以很快的速度逐漸從0增加到1。

是以,上表中Gravity和Sensitivity的含義就不難了解了,它們影響着虛拟軸從1到0、從0到1的速度以及敏感度。

具體調試方法這裡不再介紹,建議使用預設值

2.2.2 Dead

還有死區需要單獨說明。

由于實體搖桿、搖杆會有一些誤差,比如,搖桿放着不動時,某些搖桿的輸出值可能會在0.05 和0.08之間浮動。這個誤差有必要在程式中排除。

是以Unity設計了死區的功能,在該值範圍内的抖動被忽略為0,這樣就可以過濾掉輸入裝置的誤差。

2.3 在腳本中處理輸入

讀取輸入軸的方法很簡單,代碼如下:

float value = Input.GetAxis ("Horizontal");

得到的值的範圍為-1~1,預設位置為0。

這個讀取虛拟軸的方法與具體控制器是鍵盤還是搖桿無關。

如果用滑鼠控制虛拟軸,就有可能由于移動過快導緻值超出-1~1的範圍。

注意:

可以建立多個相同名字的虛拟軸。

Unity 可以同時管理多個同名的軸,最終結果以變化最大的軸為準。

這樣做的原因是很多遊戲可以同時用多種裝置進行操作。

比如PC遊戲可以用鍵盤、滑鼠或搖桿進行操作,手機遊戲可以用重力感應器或搖桿進行操作。

這種設計有助于使用者在多種操作裝置之間切換,且在腳本中不用去關心這一點。

2.4 按鍵名稱

要映射按鍵到軸上,需要在正方向輸入框或者負方向輸入框中輸入正确的按鍵名稱。

按鍵名稱的規則和例子如下。

  • 正常按鍵: A、B、…
  • 數字鍵: 1、2、…
  • 方向鍵: Up、 Down、 Left、 Right…
  • 小鍵盤鍵: [1]、 [2]、 [3]、 [+]、 [equals]…
  • 修飾鍵: Right+Shift、 Lef+Shift、Right+Ctrl、Left+Ctrl、Right+Alt、Left+Alt、Right+Cmd、Left+Cmd…
  • 滑鼠按鈕: mouse 0、mouse 1、mouse2 …
  • 搖桿按鈕(不指定具體的搖桿序号) : joystick button 0、joystick button 1…
  • 搖桿按鈕(指定具體的搖桿序号): joystick 1 button 0、joystick 1 button 1…
  • 特殊鍵: Backspace、 Tab、 Retur、 Escape、 Space、 Delete、 Enter、 Insert、 Home、Page Up…
  • 功能鍵: FI、F2、…
    可以使用KeyCode枚舉類型來指定案件,與用字元串的效果一緻

3. 在PC端輸入

unity為開發者提供了input庫,來支援鍵盤事件,滑鼠事件以及觸摸事件。

3.1 鍵盤事件

一般的PC鍵盤有104個不同的按鍵,在程式中通過監聽這些按鍵事件,進而進一步執行邏輯操作。

如:射擊遊戲中,W表示前進,S表示後退,A表示左移,D表示右移。

3.1.1 按下事件

在腳本中,用input.GetKeyDown( )方法将按鍵值作為參數,監聽此按鍵是否被按下。

按下傳回true,否者傳回false。

例如:

if (Input.GetKeyDown (KeyCode.W))  
            {  
                Debug.Log("您按下了W鍵");  
            }  
if (Input.GetKeyDown (KeyCode.Space))  
            {  
                Debug.Log("您按下了空格鍵");  
            }  
           

3.1.2 擡起事件

擡起事件完全依賴于按下事件,因為隻有按下才有擡起。

我們用Input.GetKeyUp( )方法監聽擡起事件

按鍵擡起後,傳回true,否則傳回false。

if (Input.GetKeyUp (KeyCode.W))  
            {  
                Debug.Log("您擡起了W鍵");  
            }  
           

3.1.3 長按事件

長按事件是監聽某一按鍵是否處于一直按下的狀态

通過**Input.GetKey( )**來判斷鍵盤中某一按鍵是否被一直按着。

if (Input.GetKey (KeyCode.A))  
            {  
                //記錄按下的幀數  
                keyFrame++;  
                Debug.Log("A連按:" + keyFrame+"幀");  
            }  
            if (Input.GetKeyUp (KeyCode.A))  
            {  
                //擡起後清空幀數  
                keyFrame=0;  
                Debug.Log("A按鍵擡起");  
            }     
           

3.1.4 任意鍵事件

在程式中還可以監聽按鍵中的任意按鍵是否被按下

常見于加載完遊戲後,按任意鍵進入。

if(Input.anyKeyDown)  
            {  
                Debug.Log("任意鍵被按下");  
            }  
           

3.1.4執行個體——組合按鍵

在經典的格鬥遊戲中,會有組合鍵發出牛逼的大招,而這個功能的事件思路其實不難:

在玩家按下某一鍵後,便開始時間記數,在某一時間内按出所需要的鍵便發出大招。

using UnityEngine;  
    using System.Collections.Generic;  
    using System;  

    public class Script_07_05 : MonoBehaviour   
    {  
        //方向鍵上的貼圖  
        public Texture imageUp;  
        //方向鍵下的貼圖  
        public Texture imageDown;  
        //方向鍵左的貼圖  
        public Texture imageLeft;  
        //方向鍵右的貼圖  
        public Texture imageRight;  
        //按鍵成功的貼圖  
        public Texture imageSuccess; 
        
        //自定義方向鍵的儲存值  
        public const int KEY_UP = 0;  
        public const int KEY_DOWN = 1;  
        public const int KEY_LEFT = 2;  
        public const int KEY_RIGHT = 3;  
        public const int KEY_FIRT = 4;  
        
        //連續按鍵的事件限制  
        public const int FRAME_COUNT = 100;  

        //倉庫中儲存技能的數量  
        public const int SAMPLE_SIZE = 3;  

        //每組技能的按鍵數量  
        public const int SAMPLE_COUNT = 5;  

        //技能倉庫  
        int[,] Sample =   
        {  
            //下 + 前 + 下 + 前 + 拳  
            {KEY_DOWN,KEY_RIGHT,KEY_DOWN,KEY_RIGHT,KEY_FIRT},  
            //下 + 前 + 下 + 後 + 拳  
            {KEY_DOWN,KEY_RIGHT,KEY_DOWN,KEY_LEFT,KEY_FIRT},  
            //下 + 後 + 下 + 後 + 拳  
            {KEY_DOWN,KEY_LEFT,KEY_DOWN,KEY_LEFT,KEY_FIRT},  
        };  
        //記錄目前按下按鍵的鍵值  
        int  currentkeyCode =0;  
        //标志是否開啟監聽按鍵  
        bool startFrame = false;  
        //記錄目前開啟監聽到現在的時間  
        int  currentFrame = 0;  
        //儲存一段時間内玩家輸入的按鍵組合  
        List<int> playerSample;  
        //标志完成操作  
        bool isSuccess= false;  
        void Start()  
        {  
            //初始話按鍵組合連結清單  
            playerSample  = new List<int>();  
        }  
        void OnGUI()  
        {  
            //獲得按鍵組合連結清單中儲存按鍵的數量  
            int size = playerSample.Count;  
            //周遊該按鍵組合連結清單  
            for(int i = 0; i< size; i++)  
            {  
                //将按下按鍵對應的圖檔顯示在螢幕中  
                int key = playerSample[i];  
                Texture temp = null;  
                switch(key)  
                {  
                    case KEY_UP:  
                        temp = imageUp;  
                        break;  
                    case KEY_DOWN:
                        temp = imageDown;
                        break;
                    case KEY_LEFT:
                        temp = imageLeft;
                        break;
                    case KEY_RIGHT:
                        temp = imageRight;
                        break;
                }
                if(temp != null)  
                {
                    GUILayout.Label(temp);  
                }  
            }
            if(isSuccess)
            {
                //顯示成功貼圖
                GUILayout.Label(imageSuccess);
            }
            //預設提示資訊
            GUILayout.Label("連續組合按鍵1:下、前、下、前、拳");
            GUILayout.Label("連續組合按鍵2:下、前、下、後、拳");
            GUILayout.Label("連續組合按鍵2:下、後、下、後、拳");
        }
        void Update ()
        {
            //更新按鍵
            UpdateKey();
            if(Input.anyKeyDown)
            {
                if(isSuccess)
                {
                    //按鍵成功後重置
                    isSuccess = false;
                    Reset();
                }
                if(!startFrame)
                {
                    //啟動時間計數器
                    startFrame = true;
                }  
                //将按鍵值添加如連結清單中  
                playerSample.Add(currentkeyCode);  
                //周遊連結清單  
                int size = playerSample.Count;  
                if(size == SAMPLE_COUNT)  
                {  
                    for(int i = 0; i< SAMPLE_SIZE; i++)  
                    {  
                        int SuccessCount = 0;  
                        for(int j = 0; j< SAMPLE_COUNT; j++)  
                        {  
                            int temp = playerSample[j];  
                            if(temp== Sample[i,j])
                            {  
                                SuccessCount++;  
                            }  
                        }  
//玩家按下的組合按鍵與倉庫中的按鍵組合相同表示釋放技能成功
                        if(SuccessCount ==SAMPLE_COUNT)  
                        {  
                            isSuccess = true;  
                            break;  
                        }  
                    }  
                }  
            }  
            if(startFrame)  
            {  
                //計數器++  
                currentFrame++;  
            }  
            if(currentFrame >= FRAME_COUNT)  
            { 
                //計數器逾時  
                if(!isSuccess)  
                {  
                    Reset();  
                }  
            }  
        }  
         void Reset ()  
         {  
            //重置按鍵相關資訊  
            currentFrame = 0;  
            startFrame = false;  
            playerSample.Clear();  
         }  
        void UpdateKey() 
        {  
            //擷取目前鍵盤的按鍵資訊  
            if (Input.GetKeyDown (KeyCode.W))  
            {  
                currentkeyCode = KEY_UP;  
            }  
            if (Input.GetKeyDown (KeyCode.S))  
            {  
                currentkeyCode = KEY_DOWN;  
            }  
            if (Input.GetKeyDown (KeyCode.A))  
            {  
                currentkeyCode = KEY_LEFT;  
            }  
            if (Input.GetKeyDown (KeyCode.D))  
            {  
                currentkeyCode = KEY_RIGHT;  
            }  
            if (Input.GetKeyDown (KeyCode.Space))  
            {  
               currentkeyCode = KEY_FIRT;  
            }  
        }  
    }  
           

3.2 滑鼠事件

和鍵盤事件一樣,滑鼠一般隻有3個按鍵,左鍵、右鍵和中鍵。

具體如下:

3.2.1 按下事件

Input.GetMouseButtonDown()

來判斷滑鼠哪個按鍵被按下:

  • 傳回值為0代表滑鼠左鍵被按下
  • 傳回值為1代表滑鼠右鍵被按下
  • 傳回值為2代表滑鼠中鍵被按下

3.2.2 擡起事件

Input.GetMouseButtonUp()

方法監聽滑鼠按鍵的擡起事件

3.2.3 長按事件

Input.GetMouseButton()

監聽滑鼠某個按鍵是否一直處于按下狀态

4. 在移動端輸入

對于移動裝置來說,Ioput類還提供了觸屏、加速度計以及通路地理位置的功能。

此外,移動裝置上還經常會用到虛拟鍵盤,即在螢幕上操作的鍵盤,Uity中也有相應的通路方法。

本小節專門讨論移動裝置特有的輸入方式。

4.1 多點觸摸

iPhone、iPad、安卓等裝置提供同時捕捉多個手指觸摸操作的功能,通常可以處理最多5根手指同時觸摸螢幕的情況。

通過通路Input.touches屬性,可以以數組的方式處理多個手指目前的位置等資訊。

安卓裝置上多點觸摸的規範相對靈活,不同的裝置能捕捉的多點觸摸操作的數量不盡相同。

  • 較老的裝置可能隻支援1到2個點同時觸摸
  • 新裝置可能會支援5個點同時觸摸

每一個手指的觸摸資訊以Input.Touch結構體來表示。

Input.Touch的屬性清單:

屬性 功能
fingerld 該觸摸的序号
position 觸摸在螢幕上的位置
dcllaPosition 目前觸摸位置和前一個觸摸位置的差距
doltaTime 最近兩次改變觸摸位置之間的操作時間的間隔
tapCount IPhone/Ipad裝置會記錄使用者短時間内單擊螢幕的次數,它表示使用者多次單擊操作且沒有将手拿開的次數。安卓裝置沒有這個功能,該值保持為1
phase 觸摸的階段。可以用它來判斷是剛開始觸摸、觸摸時移動,還是手指剛剛離開螢幕

phase的取值是個枚舉,枚舉值如下:

  • Began

    手指剛接觸到螢幕

  • Moved

    手指在螢幕上滑動

  • Stationary

    手指接觸到螢幕但還未滑動

  • Ended

    手指離開了螢幕。

    這個狀态代表着一次觸摸操作的結束

  • Cancceled

    系統取滑了這次觸屏操作。

    例如當使用者拿起手機進行通話,或者觸損點多于9個的時候,這次觸摸操作就會被取消。

    這個狀态也代表這次觸摸操作結束

4.2 模拟滑鼠操作

絕大部分移動裝置可以用觸屏模拟滑鼠操作。

比如使用Input.mousePosition屬性不僅可以獲得滑鼠光标的位置,也可以獲得移動裝置上觸摸的位置。

這個功能的原理不難了解,畢竟觸屏可以支援多點觸摸,而滑鼠則是單點操作,這個功能屬于向下相容。

在移動平台的遊戲的開發階段可以暫時用滑鼠操作代替觸屏操作,但是稍後應當修改為觸屏專用的方式,因為操作手感和功能會有很大差別。

4.3 加速度計

當移動裝置移動時,内置的加速度計會持續報告目前加速度的值,這個值是一個三維向量,因為物體的運動是任意方向的。

這個數值和重力加速度的表示方法類似:

  • 在某個軸方向上,1.0代表該軸具有+1.0g的加速度
  • 而負值則代表該軸具有相反方向的加速度。

正常豎直持手機(Home鍵在下方)時:

  • X軸的正方向朝右
  • Y軸的正方向朝上
  • Z軸的正方向從手機指向使用者

通過Input.aceleation屬性可以直接通路加速度計目前的數值。

繼續閱讀