Version: 2019.4
言語: 日本語
Input Manager
モバイルキーボード

モバイルデバイスの入力

モバイルデバイスでは、Input クラスはタッチスクリーン、加速度センサー、地理的/位置入力へアクセスする機能を提供します。

モバイルデバイスでキーボードにアクセスする権限は モバイルキーボード を経由して与えられます。

マルチタッチスクリーン

iPhone、iPad、iPod などのタッチデバイスは、最多で同時に 5 本の指がスクリーンをタッチしているのを追跡する能力があります。Input.touches プロパティの配列へアクセスすることによって、直前のフレームでの各指のスクリーンへのタッチ状況を取得することができます。

Android デバイスには、何本の指を追跡するかということに対して統一された制限はなく、デバイスによって違います。古いデバイスでの 2 本指対応から、新しいデバイスでの 5 本指対応までありえます。

それぞれの指のタッチは Input.Touch のデータ構造体に掲載してあります。

Property: Description:
fingerId The unique index for a touch.
position The screen position of the touch.
deltaPosition The screen position change since the last frame.
deltaTime Amount of time that has passed since the last state change.
tapCount The iPhone/iPad screen is able to distinguish quick finger taps by the user. This counter will let you know how many times the user has tapped the screen without moving a finger to the sides. Android devices do not count number of taps, this field is always 1.
phase Describes the state of the touch, which can help you determine whether the user has just started to touch screen, just moved their finger or just lifted their finger.
Began A finger just touched the screen.
Moved A finger moved on the screen.
Stationary A finger is touching the screen but hasn’t moved since the last frame.
Ended A finger was lifted from the screen. This is the final phase of a touch.
Canceled The system cancelled tracking for the touch, as when (for example) the user puts the device to their face or more than five touches happened simultaneously. This is the final phase of a touch.

以下は、 ユーザーが画面をタップするたびにレイを発するスクリプトの例です。

using UnityEngine;

public class TouchInput : MonoBehaviour
{
    GameObject particle;

    void Update()
    {
        foreach(Touch touch in Input.touches)
        {
            if (touch.phase == TouchPhase.Began)
            {
                // 現在のタッチの座標でレイを作ります
                Ray ray = Camera.main.ScreenPointToRay(touch.position);
                if (Physics.Raycast(ray))
                {
                    // ヒットしたらパーティクルを作ります
                    Instantiate(particle, transform.position, transform.rotation);
                }
            }
        }
    }
}

マウスシミュレーション

ネイティブのタッチサポートに加えて、Unity iOS/Android はマウスシミュレーションを提供します。標準の Input クラスからマウス機能を使用できます。iOS/Android デバイスはマルチタッチに対応するようデザインされていることに注意してください。マウス機能は、1 本指のタッチだけに対応します。また、モバイルデバイス上のタッチは、その間の移動なしに 1 点からもう 1 点へと動きます。しかし、モバイルデバイスのマウスシミュレーションはその間も移動を示します。そのため、タッチ入力と非常に異なります。開発の早期にはマウスシミュレーションを使用してもかまいませんが、できるだけ早くタッチ入力を使用することを推奨します。

加速度センサー

モバイルデバイスの動きに応じて、ビルトインの加速度センサーは 3 次元空間内で主要な 3 つの軸に沿った線形加速度の変化を報告します。 それぞれの軸に沿った加速度は重力の値としてハードウェアによって直接報告されます。 1.0 という値は対象の軸に関して +1 の重力値を表しており、 –1.0 という値は –1 の重力値を表しています。 もしデバイスを(ホームボタンは下にある)直立状態で持っているなら、X 軸は右に沿って正の値を取り、 Y 軸は上向きがそのまま正の値を取り、Z 軸は手前に向かって指している方が正の値を取ります。

Input.acceleration プロパティにアクセスすることで加速度センサーの値を取り出すことができます。

以下は、加速度センサーを用いてオブジェクトを動かすサンプルスクリプトです。

using UnityEngine;

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

    void Update()
    {
        Vector3 dir = Vector3.zero;
        // デバイスは地面に対して平行だと仮定します
        // ホームボタンは右側と仮定します

        // デバイスの加速度軸をゲームの座標にリマップします。
        // 1) デバイスの XY 面は XZ 面にマップします
        // 2)  Y 軸を中心に 90 度回転します

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

        // 加速度ベクトルを単位となるスフィアへ固定
        if (dir.sqrMagnitude > 1)
            dir.Normalize();

        // 1 フレーム 10 メートルではなく、1 秒間に 10 メートル動くようにします
        dir *= Time.deltaTime;

        // オブジェクトを動かします
        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 は周波数が 60 ヘルツのときにハードウェアをサンプリングし、変数に結果を保存します。実際はもう少しだけ複雑です。どういうことかというと、CPU が過負荷状態にあるならば、加速度センサーのサンプリングは決まった間隔では行われないということです。結果として、システムは 1 フレームの間に 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
モバイルキーボード