Unity中的输入

任何游戏都应该提供给用户交互的方式,能够想象一个没有任何交互的游戏是什么样的。若是没有输入系统带来的,用户与游戏的交互那么游戏将再也不是游戏,由于玩家将不能进行任何操做,那还怎么玩呢?Unity做为一个号称跨平台性能最好的游戏引擎,那么它给咱们提供了哪些输入呢?为了可以更好的整理Unity的输入系统,暂时将其分为移动平台的输入和传统的输入。ide

移动平台的输入

在手机和pad上主要的输入方式就是:触摸,重力加速器,虚拟键盘等。Unity将这些操做都封装到了UnityEngine.Input和UnityEngine.TouchScreenKeyboard这两个类里。函数

触摸

触摸相关的函数

在UnityEngine.Input类中为咱们提供了触摸相关的函数,以及在UnityEngine命名空间中涉及到的类,相关函数和类以下表:性能

函数表:
|函数名 |做用
----|-----
multiTouchEnabled| 是否启用多点触摸
simulateMouseWithTouches| 启用/禁用使用触碰仿真鼠标的操做
touchCount| 在此帧中的触摸数量
touches|在上一帧中的触摸点(Touch)信息
touchSupported| 标示当前运行此程序的设备是否支持触摸
GetTouch|根据触摸点的索引获取触摸点的信息
类表:
类名 |做用
---|--
Touch| 触摸点信息
TouchPhase| 触摸点的状态信息测试

触摸的一个示例

此示例主要实现以下三个功能:this

  1. 显示触摸点的属性信息
  2. 显示点击到的物体
  3. 测试仿真鼠标

示例代码,以下:3d

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。code

在Unity中访问重力加速器的信息

重力加速器的信息被放在了UnityEngine.Input中。具体函数或字段见下表:orm

函数名 做用
acceleration 存放当前3个轴上感应到的加速度
accelerationEvents 在上一帧期间Unity引擎采集到的全部重力加速器信息(每一个方向上的加速度和时间增量)
accelerationEventCount 在上一帧期间Unity引擎采集到的全部重力加速度的次数

重力加速器示例

本示例就一个功能,咱们在场景中放一个Cube,当手机向指定方向偏转时,Cube就向指定方向移动。示例代码以下:htm

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

相关文章
相关标签/搜索