Unity中的输入

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

移动平台的输入

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

触摸

触摸相关的函数

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

函数表:

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

类表:

类名 作用
Touch 触摸点信息
TouchPhase 触摸点的状态信息

触摸的一个示例

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

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

示例代码,如下:

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,谈起的是否为:FalseGetButtonDown|获取指定虚拟按钮是否按下,当按下那一刻为TrueGetButtonUp|获取指定虚拟按钮是否抬起,当抬起那一刻为True
虚拟轴或按钮的示例
此示例主要实现2功能:
实现一个Cube在场景中前后左右的走动,通过获取“Horizontal”和“Vertical”两个虚拟轴来控制
实现一个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.htmlUnity官方文档2:http://docs.unity3d.com/ScriptReference/Input.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,376评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,126评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,966评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,432评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,519评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,792评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,933评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,701评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,143评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,488评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,626评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,292评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,896评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,742评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,324评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,494评论 2 348

推荐阅读更多精彩内容