Version: Unity 6.0 (6000.0)
语言 : 中文
Input Manager
Unity 中的 IME

移动设备输入

| | |—| | 重要提示:本页介绍输入管理器系统的一部分,这是旧版功能,不建议用于新项目。对于新项目中的移动设备输入,应使用 Input System Package |


在移动设备上,Input 类提供对触摸屏、加速度计和地理/位置输入的访问。

通过移动键盘可以访问移动设备上的键盘。

多点触控屏幕

iPhone、iPad 和 iPod Touch 设备最多可跟踪五根手指同时触摸屏幕。可通过访问 Input.touches 属性数组来检索在最后一帧期间触摸屏幕的每根手指的状态。

Android 设备对其跟踪的手指数量没有统一限制。相反,此限制因设备而异,可能是旧设备上的双手指触摸到某些新设备上的五指触摸。

每根手指的触摸由 Input.Touch 数据结构表示:

属性: 描述:
fingerId 触摸的唯一索引。
position 触摸的屏幕位置。
deltaPosition 自上一帧以来的屏幕位置变化。
deltaTime 自上次状态变化以来经过的时间。
tapCount iPhone/iPad 屏幕能够区分用户的快速手指点击。此计数器将记录用户在不将手指移到侧面的情况下点击屏幕的次数。Android 设备不计算点击次数,此字段始终为 1。
phase 描述触摸状态,可帮助您确定用户是刚开始触摸屏幕、刚移动手指还是刚抬起手指。
Began 手指刚触摸了屏幕。
Moved 手指在屏幕上进行了移动。
Stationary 手指正在触摸屏幕但自上一帧以来尚未移动。
Ended 从屏幕上抬起了手指。这是触摸的最后一个阶段。
Canceled 由于某种情况,例如用户将设备放在他们的脸部或同时执行超过五次触摸,系统取消了对触摸的跟踪。这是触摸的最后一个阶段。

以下是一个示例脚本,只要用户点击屏幕,就会发出一条射线:

using UnityEngine;

public class TouchInput : MonoBehaviour
{
    GameObject particle;

    void Update()
    {
        foreach(Touch touch in Input.touches)
        {
            if (touch.phase == TouchPhase.Began)
            {
                // Construct a ray from the current touch coordinates
                Ray ray = Camera.main.ScreenPointToRay(touch.position);
                if (Physics.Raycast(ray))
                {
                    // Create a particle if hit
                    Instantiate(particle, transform.position, transform.rotation);
                }
            }
        }
    }
}

鼠标模拟 除了原生触摸支持,Unity iOS/Android 还提供鼠标模拟功能。可使用标准 Input 类中的鼠标功能。请注意,根据设计,iOS/Android 设备支持多指触摸。使用鼠标功能时仅支持单指触摸。此外,移动设备上的手指触摸可从一个区域移动到另一个区域,而它们之间没有移动。移动设备上的鼠标模拟将提供移动,因此与触摸输入相比非常不同。建议在早期开发期间使用鼠标模拟,但要尽快使用触摸输入。

加速度计

随着移动设备的移动,内置的加速度计会报告沿三维空间中的三个主轴的线性加速度变化。硬件将沿每个轴的加速度直接报告为重力值。值 1.0 表示沿给定轴约 +1g 的荷载,而值 –1.0 表示 –1g。如果将设备竖直握住(主屏幕按钮位于底部)举到您正前方,则右侧为正 X 轴,上方为正 Y 轴,指向您的方向为正 Z 轴。

可通过访问 Input.acceleration 属性来检索加速度计值。

以下是使用加速度计移动对象的示例脚本:

using UnityEngine;

public class Accelerometer : MonoBehaviour
{
    float speed = 10.0f;

    void Update()
    {
        Vector3 dir = Vector3.zero;
        // we assume that the device is held parallel to the ground
        // and the Home button is in the right hand

        // remap the device acceleration axis to game coordinates:
        // 1) XY plane of the device is mapped onto XZ plane
        // 2) rotated 90 degrees around Y axis

        dir.x = -Input.acceleration.y;
        dir.z = Input.acceleration.x;

        // clamp acceleration vector to the unit sphere
        if (dir.sqrMagnitude > 1)
            dir.Normalize();

        // Make it move 10 meters per second instead of 10 meters per frame...
        dir *= Time.deltaTime;

        // Move object
        transform.Translate(dir * speed);
    }
}

低通滤波器 加速度计读数可能不稳定且噪声很大。对信号应用低通滤波可以使其平滑并消除高频噪声。

以下脚本显示了如何将低通滤波应用于加速度计读数:

using UnityEngine;

public class LowPassFilterExample : MonoBehaviour
{
    float accelerometerUpdateInterval = 1.0f / 60.0f;
    float lowPassKernelWidthInSeconds = 1.0f;

    private float lowPassFilterFactor;
    private Vector3 lowPassValue = Vector3.zero;

    void Start()
    {
        lowPassFilterFactor = accelerometerUpdateInterval / lowPassKernelWidthInSeconds;
        lowPassValue = Input.acceleration;
    }

    private void Update()
    {
        lowPassValue = LowPassFilterAccelerometer(lowPassValue);
    }

    Vector3 LowPassFilterAccelerometer(Vector3 prevValue)
    {
        Vector3 newValue = Vector3.Lerp(prevValue, Input.acceleration, lowPassFilterFactor);
        return newValue;
    }
}

LowPassKernelWidthInSeconds 的值越大,滤波值向当前输入样本收敛的速度越慢(反之亦然)。

在读取加速度计的读数时,我希望尽可能精确。我该怎么办?读取 Input.acceleration 变量不等于对硬件进行采样。简而言之,Unity 以 60Hz 的频率对硬件进行采样并将结果存储到变量中。实际情况有点复杂:如果 CPU 负载很大,加速度计采样不会以一致的时间间隔发生。结果,系统可能在一帧期间报告 2 个样本,然后在下一帧期间报告 1 个样本。

您可以访问加速度计在帧内执行的所有测量。以下代码将展示在最后一帧内收集的所有加速度计事件的简单平均值:

public class AccelerationEvents : MonoBehaviour
{ 
    void Update()
    {
        GetAccelerometerValue();
    }

    Vector3 GetAccelerometerValue()
    {
        Vector3 acc = Vector3.zero;
        float period = 0.0f;

        foreach(AccelerationEvent evnt in Input.accelerationEvents)
        {
            acc += evnt.acceleration * evnt.deltaTime;
            period += evnt.deltaTime;
        }
        if (period > 0)
        {
            acc *= 1.0f / period;
        }
        return acc;
    }
}
Input Manager
Unity 中的 IME