Unity中的輸入


任何游戲都應該提供給用戶交互的方式,可以想象一個沒有任何交互的游戲是什么樣的。如果沒有輸入系統帶來的,用戶與游戲的交互那么游戲將不再是游戲,因為玩家將不能進行任何操作,那還怎么玩呢?Unity作為一個號稱跨平台性能最好的游戲引擎,那么它給我們提供了哪些輸入呢?為了能夠更好的整理Unity的輸入系統,暫時將其分為移動平台的輸入和傳統的輸入。

移動平台的輸入

在手機和pad上主要的輸入方式就是:觸摸,重力加速器,虛擬鍵盤等。Unity將這些操作都封裝到了UnityEngine.Input和UnityEngine.TouchScreenKeyboard這兩個類里。

觸摸

觸摸相關的函數

在UnityEngine.Input類中為我們提供了觸摸相關的函數,以及在UnityEngine命名空間中涉及到的類,相關函數和類如下表:

函數表:

函數名 作用
multiTouchEnabled 是否啟用多點觸摸
simulateMouseWithTouches 啟用/禁用使用觸碰仿真鼠標的操作
touchCount 在此幀中的觸摸數量
touches 在上一幀中的觸摸點(Touch)信息
touchSupported 標示當前運行此程序的設備是否支持觸摸
GetTouch 根據觸摸點的索引獲取觸摸點的信息

類表:

類名 作用
Touch 觸摸點信息
TouchPhase 觸摸點的狀態信息

觸摸的一個示例

此示例主要實現如下三個功能:

  1. 顯示觸摸點的屬性信息
  2. 顯示點擊到的物體
  3. 測試仿真鼠標

示例代碼,如下:

public class TouchInputTest : MonoBehaviour {

    public Camera m_mainCamera = null;    
    private bool m_isRatating = false;
    private GameObject m_objRatation = null;
    private float m_nSpeedRatation = 30.0f;
    private float m_nTotalAngle = 0;
    private const int nMaxSelectedSize = 5;
    private string[] m_strSelectedGameObject = new string [nMaxSelectedSize]{"", "", "", "", ""};
    // Use this for initialization
    void Start () 
    {

    }

    // Update is called once per frame
    void Update () 
    {
        //將是否支持觸碰
        if (Input.touchSupported)
        {        
            print("Number of touches:" + Input.touchCount);
            print("Length of touches:" + Input.touches.Length);
            print("---------------------------------------------");
            for (int i = 0; i < Input.touches.Length; ++i )
            {
                Touch tch = Input.touches[i];
                //打印觸摸點的信息
                print("Index:" + tch.fingerId);
                print("State:" + tch.phase.ToString());
                print("Positon:" + tch.position);
                print("TapCount:" + tch.tapCount);
                print("deltaPosition:" + tch.deltaPosition);
                print("deltaTime:" + tch.deltaTime);

                //通過射線拾取物體
                if (m_mainCamera != null)
                {
                    Ray ray = m_mainCamera.ScreenPointToRay(tch.position);
                    RaycastHit rayHitInfo;
                    Physics.Raycast(ray, out rayHitInfo);
                    if (rayHitInfo.transform)
                    {
                        if (0 == i)
                            m_objRatation = rayHitInfo.transform.gameObject;
                        m_strSelectedGameObject[i] = rayHitInfo.transform.name;
                    }
                    else
                    {
                        m_strSelectedGameObject[i] = "";
                    }
                }
                else
                {
                    print("Main camera is null.");
                }
            }

            for (int i = Input.touches.Length; i < nMaxSelectedSize; ++i)
            {
                m_strSelectedGameObject[i] = "";
            }


            //檢測是否支持使用觸摸仿真鼠標操作。1個手指操作為左鍵,2個手指操作代表右鍵,3:個手指代表中鍵
            //這你通過兩個手指單機,來模仿鼠標右鍵單擊,單兩個手指單擊時,選中的物體沿Y軸旋轉360度。
            if (Input.simulateMouseWithTouches)
            {               
                if (Input.GetMouseButton(1) && !m_isRatating)
                {
                    m_isRatating = true;
                }
            }
        }
        else
        {
            print("touch is not supported.");
            return;
        }

        if (m_isRatating)
        {
            float yRotation = m_nSpeedRatation * Time.deltaTime;
            if (m_nTotalAngle >= 360)
            {
                m_isRatating = false;
                m_nTotalAngle = 0;
            }
            m_nTotalAngle += yRotation;
            m_objRatation.transform.Rotate(0, yRotation, 0);
        }
    }

    void OnGUI()
    {
        if (GUILayout.RepeatButton("Enable/Disable MulitTouch(" + Input.multiTouchEnabled.ToString() + ")"))
        {
            Input.multiTouchEnabled = !Input.multiTouchEnabled;
        }
        if (GUILayout.RepeatButton("Enable/Disable simulateMouseWithTouches(" + Input.simulateMouseWithTouches.ToString() + ")"))
        {
            Input.simulateMouseWithTouches = !Input.simulateMouseWithTouches;
        }

        for (int i = 0; i < nMaxSelectedSize; ++i)
        {
            GUILayout.Label("Index(" + i + "):" + m_strSelectedGameObject[i].ToString());
        }
    }
}

重力加速器

當我們垂直正對手機(手機屏幕對着我們的臉)的時候,重力什么怎么樣呢?它有哪些方向,以及在每個方向上的加速度是多少呢?
現在的手機或者pad一般都能對三個方向的力進行采集,分別是X,Y和Z。X的正方向水平向左,Y的正方向垂直向上,Z的正方向面向自己。為了能更形象的說明這些問題,我簡單的畫了一個圖,下圖為我們垂直正對手機時候的重力加速圖:
這里寫圖片描述
上圖中的兩個圓都表示的是兩個3D球體的前視圖。由上圖看,當我們垂直正對手機時候,中間的藍色球體受到了來自地球-9.8米/秒的二次方加速度,那么這時候我們訪問Input.acceleration.y的時候,其值就是一個接近-9.8的值,其他軸上都趨近於0。

在Unity中訪問重力加速器的信息

重力加速器的信息被放在了UnityEngine.Input中。具體函數或字段見下表:

函數名 作用
acceleration 存放當前3個軸上感應到的加速度
accelerationEvents 在上一幀期間Unity引擎采集到的所有重力加速器信息(每個方向上的加速度和時間增量)
accelerationEventCount 在上一幀期間Unity引擎采集到的所有重力加速度的次數

重力加速器示例

本示例就一個功能,我們在場景中放一個Cube,當手機向指定方向偏轉時,Cube就向指定方向移動。示例代碼如下:

public class AccInputTest : MonoBehaviour {

    private float speed = 1.5f;
    //控制信息的打印時間
    private float fInterval = 1000;
    private float fCurTime = 0;
    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {
        Vector3 dir = Vector3.zero;

        //unity的X軸的正方向是向左的
        dir.x = -Input.acceleration.x;
        dir.y = Input.acceleration.y;
        dir.z = 0;

        if (fCurTime >= fInterval)
        {
            Debug.Log("X:" + Input.acceleration.x + "    Y:" + Input.acceleration.y + "    Z:" + Input.acceleration.z);
            fCurTime = 0;
        }

        dir *= Time.deltaTime;
        fCurTime += Time.deltaTime;

        transform.Translate (dir * speed);
    }
}

虛擬鍵盤

在游戲中我們點擊輸入框(NGUI或Unity自帶控件)都會自動彈出虛擬鍵盤,當然我們也可以手動的彈出虛擬鍵盤,下面主要介紹如何手動的彈出鍵盤。鍵盤的操作被Unity放在了UnityEngine.TouchScreenKeyboard中。鍵盤的操作非常簡單,下面以一個簡單的示例來說明如何打開一個虛擬鍵盤,以及獲取輸入的數據。在一個腳本里的OnGUI函數中輸入如下代碼:

void OnGUI()
    {
        TouchScreenKeyboard.hideInput = true;
        if (GUILayout.Button ("KeyBoard:ASCIICapable")) {
            keyboard = TouchScreenKeyboard.Open("", TouchScreenKeyboardType.ASCIICapable, false, false, false, false);
        }
        if (GUILayout.Button ("KeyBoard:Default")) {
            keyboard = TouchScreenKeyboard.Open("", TouchScreenKeyboardType.Default, false, false, false, false);
        }
        if (GUILayout.Button ("KeyBoard:EmailAddress")) {
            keyboard = TouchScreenKeyboard.Open("", TouchScreenKeyboardType.EmailAddress, false, false, false, false);
        }
        if (GUILayout.Button ("KeyBoard:NamePhonePad")) {
            keyboard = TouchScreenKeyboard.Open("", TouchScreenKeyboardType.NamePhonePad, false, false, false, false);
        }
        if (GUILayout.Button ("KeyBoard:NumberPad")) {
            keyboard = TouchScreenKeyboard.Open("", TouchScreenKeyboardType.NumberPad, false, false, false, false);
        }
        if (GUILayout.Button ("KeyBoard:NumbersAndPunctuation")) {
            keyboard = TouchScreenKeyboard.Open("", TouchScreenKeyboardType.NumbersAndPunctuation, false, false, false, false);
        }
        if (GUILayout.Button ("KeyBoard:PhonePad")) {
            keyboard = TouchScreenKeyboard.Open("", TouchScreenKeyboardType.PhonePad, false, false, false, false);
        }
        if (GUILayout.Button ("KeyBoard:URL")) {
            keyboard = TouchScreenKeyboard.Open("", TouchScreenKeyboardType.URL, false, false, false, false);
        }

        GUILayout.Label("");

        if (keyboard != null) {
            GUILayout.Label (keyboard.text);
        } else {
            GUILayout.Label ("keyboard is null.");
        }
    }

其他輸入

Ps:在移動平台的輸入中,Unity還為我們提供了諸如:位置,指南針,陀螺儀等設備的信息輸入。在這里就不在詳述了,詳情參見官方文檔

傳統的輸入

像鼠標,鍵盤,操作桿和手柄這樣的輸入設備。現在暫且將其定義為傳統的輸入設備,以便區分前面的移動平台的輸入。在Unity中還為我們抽象出來一個叫做虛擬軸或虛擬按鈕的概念出來,在下面將分別介紹這兩種(其實是一種,后者是由前者虛擬出來的)輸入方式。

鼠標,鍵盤,控制桿,手柄

由於操作桿和手柄沒有設備,就不做介紹了,它跟其他的操作是一樣的。

鍵盤

函數 作用
GetKey 獲取鍵盤指定鍵是否按下(只要按下就是True抬起就是False)
GetKeyDown 獲取鍵盤指定鍵是否按下(按下那一刻是True)
GetKeyUp 獲取鍵盤指定鍵是否按下(彈起那一刻是True)
anyKey 是否按住了“任意鍵”(只要按下就是True抬起就是False)
anyKeyDown 是按下了“任意鍵”(按下那一刻是True)

對應的按鍵枚舉參見KeyCode

鼠標

函數 作用
GetMouseButton 獲取鼠標指定鍵是否按下(只要按下就是True抬起就是False)
GetMouseButtonDown 獲取鼠標指定鍵是否按下(按下那一刻是True)
GetMouseButtonUp 獲取鼠標指定鍵是否彈起(彈起那一刻是True)

注:0對應於鼠標左鍵,1對應於與鼠標右鍵,2對應於鼠標中鍵。

雖然上面的函數能夠直接獲取到指定鍵是否按下,但是我們一般不會直接這么使用。使用Untiy提供的虛擬軸和按鍵能更靈活的控制我們的輸入。比如我可以將空格定義攻擊鍵,也可以隨時改變這個鍵。虛擬軸還有一個好處,就是我們可以同時接受多輸入,比如我可以接受鍵盤的空格作為攻擊,也可以使用操作桿或手柄上的一個鍵作為攻擊鍵,因為我們獲取的虛擬軸或按鈕都是一樣(“Fire1”)的。這里可能說的有點抽象,不好懂,下面我會通過一個例子來說明這些。

虛擬控制軸(Virtual Axes)

虛擬軸的編輯

這里寫圖片描述
下面對每個參數簡單的說明,在看說明時對應下圖一起看。圖如下:
這里寫圖片描述

參數名 作用
Name 虛擬軸的名字(獲取虛擬軸時就需要傳入這個名字)
Descriptive Name 正方向上的控制鍵的描述信息
Descriptive Negative Name 反方向上的控制鍵的描述信息
Negative Button 主控制鍵反方向上對應的控制鍵
Positive Button 主控制鍵正方向上對應的控制鍵
Alt Negative Button 副控制鍵反方向上對應的控制鍵
Alt Positive Button 副控制鍵正方向上對應的控制鍵
Gravity 向中間值歸位時的速度
Dead 中間值的閾值,就是小於這個值則被定義為是中間值了
Sensitivity 向目標歸位時的速度
Snap 是否需要平滑,如果沒有的話那么就只有-1,0(中間值),1這三個值
Invert 將上面的正反方向顛倒
Type 使用那些輸入控制鍵,一般使用鼠標和鍵盤,如果你開發的是使用操作桿的那么就是操作桿作為輸入控制
Axis 抱歉不能理解
Joy Num 抱歉不能理解

相關函數

函數名 作用
GetAxis 獲取指定軸上當前采集的值,范圍為[-1,1]
GetAxixRaw 獲取指定軸上當前采集的值,這個函數獲取的是沒有平滑過渡的值,也就是只有-1,0,1這三個值
GetButton 獲取指定虛擬按鈕是否按下,當按下的是否為True,談起的是否為:False
GetButtonDown 獲取指定虛擬按鈕是否按下,當按下那一刻為True
GetButtonUp 獲取指定虛擬按鈕是否抬起,當抬起那一刻為True

虛擬軸或按鈕的示例

此示例主要實現2功能:

  1. 實現一個Cube在場景中前后左右的走動,通過獲取“Horizontal”和“Vertical”兩個虛擬軸來控制
  2. 實現一個Cube在場景中的旋轉,通過自定義的控制軸“Rotation”實現,“Rotation”我們通過鼠標右鍵和鍵盤的空格鍵來控制。
    示例代碼如下:
public class AxesTest : MonoBehaviour {

    private float m_nSpeed = 5.0f;
    private bool m_isRotating = false;
    private float m_nRotationSpeed = 30.0f;
    private float m_nCurRotationAngle = 0;
    private const float m_nMaxAngle = 360;

    // Update is called once per frame
    void Update () {
        if (Input.GetButtonDown("Rotation") && !m_isRotating)
        {
            m_isRotating = true;
        }

        if (m_isRotating)
        {
            float nRotation = Time.deltaTime * m_nRotationSpeed;
            transform.Rotate(0, nRotation, 0);
            m_nCurRotationAngle += nRotation;
        }

        if (m_nCurRotationAngle >= m_nMaxAngle)
        {
            m_nCurRotationAngle = 0;
            m_isRotating = false;
        }

        float nXDeltaDistance = Input.GetAxis("Horizontal") * m_nSpeed * Time.deltaTime;
        float nYDeltaDistance = Input.GetAxis("Vertical") * m_nSpeed * Time.deltaTime;        
        if (nXDeltaDistance.Equals(0) && nYDeltaDistance.Equals(0))
            return;

        print("X:" + Input.GetAxis("Horizontal").ToString() + "   Y:" + Input.GetAxis("Vertical").ToString());
        transform.Translate(-nXDeltaDistance, nYDeltaDistance, 0);

    }
}

總結

Unity將其主要的輸入都放到了UnityEngine.Input類中,內部檢查或采集到輸入信息就將其結果放入Input中的對應字段,用於表示輸入的狀態。輸入大致分為兩類,一個是移動平台的輸入,像觸摸,虛擬鍵盤,重力加速感應器,羅盤,陀螺儀,GPS(位置)等,另一類是傳統的輸入,像鍵盤,鼠標,操作桿和手柄等。

參考文獻

Unity官方文檔1:http://docs.unity3d.com/Manual/Input.html
Unity官方文檔2:http://docs.unity3d.com/ScriptReference/Input.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM