[Unity]設定遊戲手把與取得輸入

參考資料:Input
                    Input Manager

測試手把 :PS Analog gamepad
Script語言:C#
Unity 版本:3.4

Unity提供了3種輸入裝置可以使用,鍵盤、滑鼠、以及遊戲手把。
此篇紀錄在取得遊戲手把輸入時,所遇到的問題以及解決方案。

首先,要先開啟Unity提供的Input Manager(Edit->Project Setting->Input Manager),就可以看到Unity所提供預設的按鈕事件。這邊也可以自訂自己想要用的按鈕,只需要更改size欄位的數值即可,Unity就會利用最後一組按鈕做為參考值,複製一份新的按鈕設定。官方稱這些設定為虛擬軸(Virtual Axes)或是虛擬按鈕(Virtual Button)。


Unity提供預設兩組水平輸入以及垂直輸入,一組是提供給鍵盤訊息使用,另一組是設定給遊戲手把使用。不過這兩個輸入是使用相同的名稱。這邊推測,是要讓寫script的時候,不需要根據裝置而另外寫輸入判斷或是數值取得。如果是這樣設計的話,那算是還蠻方便的功能。


為了測試Unity是否能正確接收到遊戲手把的訊息,就寫了底下的測試程式來測試結果。
 using UnityEngine;  
 using System.Collections;  
   
 public class InputTest : MonoBehaviour {  
     protected float m_JoyX = 0.0f;  
     protected float m_JoyY = 0.0f;  
       
     // Use this for initialization  
     void Start () {  
       
     }  
       
     // Update is called once per frame  
     void Update ()   
     {          
         m_JoyX = Input.GetAxis("Horizontal");  
         m_JoyY = Input.GetAxis("Vertical");  
                 
         Debug.Log("Get Horizontal input from Joystick = " + m_JoyX.ToString());  
         Debug.Log("GetVertical input from Joystick = " + m_JoyY.ToString());  
     }  
 }  
   

測試結果:

測試結果還不錯,用手把或是鍵盤都可以接收到訊息。


不過這種作法有個缺點,就是Update()是每個frame都會更新一次,所以就會一直收到沒按下按鍵時的資料。
因此需要做一些判斷式來確定按鍵有按下時,才取得所需要的按鍵值。
所以更改後的程式碼如下:
   
 using UnityEngine;  
 using System.Collections;  
   
 public class InputTest : MonoBehaviour {  
     protected float m_JoyX = 0.0f;  
     protected float m_JoyY = 0.0f;  
       
     // Use this for initialization  
     void Start () {  
       
     }  
       
     // Update is called once per frame  
     void Update ()   
     {          
         m_JoyX = Input.GetAxis("Horizontal");  
         m_JoyY = Input.GetAxis("Vertical");  
           
         if( Input.GetButton("Horizontal") )  
         {  
             Debug.Log("Get Horizontal input from Joystick = " + m_JoyX.ToString());  
         }else if(Input.GetButton("Vertical")) {  
             Debug.Log("GetVertical input from Joystick = " + m_JoyY.ToString());  
         }  
           
         if( Input.GetKey(KeyCode.JoystickButton11) ){  
             print("Get Joystick Button 0");  
         }  
           
         //Debug.Log("Get Horizontal input from Joystick = " + m_JoyX.ToString());  
     }  
 }  
   

測試結果如下圖:

結果,手把訊息沒進來?!
之後試過很多方法,例如把按鍵名稱改成不同的名稱,也是一樣沒有接收到手把方向鍵按下的訊息。
這邊的測試就繞了很久,後來索性把手把方向鍵是否有輸入這件事情,改成判定軸向值是否有值(也就是不為0)。結果就可正常的在手把方向鍵按下時,才取得所要的數值。

原本不曉得是不是Unity的bug還是限制,畢竟這一塊的說明,官方文件沒有講得很清楚。而提供的按鍵訊息也只有上、下、左、右四個鍵盤按鍵而已。目前推測是,因為手把輸入的Type為Joystick Axis,然後軸並沒有所謂的按鈕觀念,所以這邊就無法用Input.GetButton()來取得是否有按下這個動作。


改判定軸向是否有值後,的確解決上述的問題,但與鍵盤要同時共用的時候,卻又出了問題
就是因為手把跟鍵盤是使用相同的虛擬按鈕名稱,所以取得的軸向資料有時並不是手把輸入的,反而會是鍵盤輸入的。


因此目前為了解決這問題,就是把手把輸入跟鍵盤輸入的虛擬按鈕名稱改成不一樣,這樣就可以確定輸入的資料是確切的來自於鍵盤還是手把。雖然在實作遊戲的時候會很不方便(因為要另外把手把輸入拆出來判斷),但是如果透過繼承跟多型,是可以讓實作遊戲變方便。至於如何繼承跟多型的部分就之後另外開個主題紀錄了(因為目前還在測試中XD)。

最後可以同時使用鍵盤與遊戲手把輸入,但也不會互相影響的方式如下:
或是在Input Manager內使用相同的熱鍵名稱也行。之前測試不過可能是有設定沒弄好。 2011/08/31
 using UnityEngine;  
 using System.Collections;  
   
 public class InputTest : MonoBehaviour {  
     protected float m_JoyX = 0.0f;  
     protected float m_JoyY = 0.0f;  
       
     // Use this for initialization  
     void Start () {  
       
     }  
       
     // Update is called once per frame  
     void Update ()   
     {  
         m_JoyX = Input.GetAxis("Horizontal_Joy");  
         m_JoyY = Input.GetAxis("Vertical_Joy");  
           
         if( Input.GetButton("Horizontal") )  
         {  
             print("Get Horizontal input from keyboard = " + Input.GetAxis("Horizontal").ToString());  
         }else if( Input.GetButton("Vertical") ){  
             print("Get Vertical input from keyboard = " + Input.GetAxis("Vertical").ToString());  
         }else if( Input.GetButton("Horizontal_Joy") ){//m_JoyX != 0.0f ){  
             Debug.Log("GetHorizontal input from Joystick = " + m_JoyX.ToString());  
         }else if( m_JoyY != 0.0f ){  
             Debug.Log("GetVertical input from Joystick = " + m_JoyY.ToString());  
         }  
           
         if( Input.GetKey(KeyCode.JoystickButton11) ){  
             print("Get Joystick Button 0");  
         }  
     }  
 }  

測試結果如下:

輸出結果也就很符合目前的需求嚕。

不過此時Joystick Y軸上為負值,所以有需要用Y軸上為正值時,需把Inverse選項打勾,就可以了。


PS.1.官方有註明鍵盤跟手把的軸向值介於-1到1。滑鼠部分則不一定在此區間。
PS.2.在測試過程中發現,把Dead設為0.00001以下時,在手把方向鍵未按下時,Input.GetAxis()取得到的座標值其實是不為零的。
         因此如果使用別的手把時,發現官方的預設值無法讓未按下方向鍵時取得的值為零的情況下,只要把Dead參數改大就好。反之如果按下按鍵後,收到的值為零,就把Dead參數改小(大於0,小於1)就可以了。
         官方對於Dead的說明為,當收到的按鍵數值低於Dead的值的時候,就會強制設為0。

4 comments:

  1. 請問一下
    上面第一篇的script您是放在哪裡呢?
    是放在car裡面 啟動之後consloe就會自動跳出訊息嗎?

    ReplyDelete
  2. 不好意思,您指的上一篇的意思是?
    我沒記錯得話,是把script掛在要接收事件的物件上。

    如您提到的car物件要接收鍵盤事件,就把寫好的script加到car物件上就可以了。

    ReplyDelete
  3. 大大您好 方便提問問題嗎

    ReplyDelete
    Replies
    1. 可以..請說。不好意思,現在才看到。

      Delete

Build docker image from multiple build contexts

Build docker image from multiple build contexts ...