zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    开源blog搬家工具
    嵌入式语言Lua
    ChangeMan Version Manager Workstation 8.1 command line quick check in/out
    Mssql合并列值(三个关系表合并)
    心得——学习中做笔记应该做到哪
    MFC Dialog 透明渐变
    【转】SSDT&Shadow Hook的实现,完整代码。可编译
    ssdt 表结构及hook的一般理解
    <转>ssdt hook 源码
    【转】_declspec(naked) 使用
  • 原文地址:https://www.cnblogs.com/qilezaitu/p/5017001.html
Copyright © 2011-2022 走看看