【コピペでUnity】キーボードでもGUIでも長押しを迷わず実装する方法

Unity
Unity

長押しの実装をしたい人

長押しって簡単に言うけど、意外とどう実装したらいいか分からないぞ?
GUIで長押しがないらしいから作りたいんだけど、Event?分からん…。

こんなお悩みを解決します。

 

本記事の内容

●長押しのサンプルコード
●長押しの設定方法
●長押しのアルゴリズム解説

 

この記事を書いている私は12才からフルスクラッチでゲームを作っています。
またコンパイラを専門として情報理工学の博士まで進学、中退をしており、プログラミング言語の文法にも関わる論文を書いていました。

 

本記事ではコピペで使える最低限の実行済みコードと設定方法を紹介します。

※実行環境
Unity2021.3.1f1
Windows 10

 

長押しのサンプルコード

以下2つがキー入力用とGUI用の、長押しのサンプルコードです。
やっていることは本質的には同じなのですが、UnityのGUIには少しクセがあります。

目的に合わせて好きな方を選んでいただいてもいいですし、2つを比べることで理解を深めてみるのもまたいいでしょう。

 

キー入力による長押し

using UnityEngine;

public class HoldKey : MonoBehaviour {
    //長押しと判定するフレーム数を管理
    private const int _threshold = 30;
    //キーを押しているフレーム数を記録
    private int _duration = 0;

    void Update() {
        //キーを押しているかを判定
        if (Input.GetKey(KeyCode.Space)) {
            //押しているフレーム数を加算
            _duration = _duration + 1;
        }

        //キーを離した瞬間を判定
        if (Input.GetKeyUp(KeyCode.Space)) {
            //押しているフレーム数をリセット
            _duration = 0;
        }

        //長押しを判定
        if (_duration == _threshold) {
            Debug.Log("長押し");
        }
    }
}

 

GUIの長押し

using UnityEngine;
using UnityEngine.EventSystems;

public class HoldGUI : MonoBehaviour, IPointerDownHandler, IPointerUpHandler {
    //長押しと判定するフレーム数を管理
    private const int _threshold = 30;
    //キーを押しているフレーム数を記録
    private int _duration = 0;

    //キーを押している状態を記録
    private bool _onPointer = false;

    void Update() {
        //ボタンを押しているかを判定
        if (_onPointer == true) {
            //押しているフレーム数を加算
            _duration = _duration + 1;
        }

        //長押しを判定
        if (_duration == _threshold) {
            Debug.Log("長押し");
        }
    }

    //ボタンを押した瞬間
    public void OnPointerDown(PointerEventData eventData) {
        //ボタンを押している状態に変更
        _onPointer = true;
    }

    //ボタンを離した瞬間
    public void OnPointerUp(PointerEventData eventData) {
        //押しているフレーム数をリセット
        _duration = 0;
        //ボタンを押していない状態に変更
        _onPointer = false;
    }
}

 

●_threshold
長押しを判定するためのフレーム数
thresholdは「しきい値」を意味する

●_duration
押しているフレーム数をカウントする
durationは「続いている時間」を意味する

●_onPointer
GUIなどを押している状態を記録する

 

長押しの設定方法

サンプルコードを使って、キー入力とGUIの2パターンで長押しの実装を解説します。
2つの処理は独立しているため試したい方を実装するのもよいですし、以下の手順で両方同時に実装することも出来ます。

 

キー入力による長押し

1.「Hierarchy」ウィンドウの余白で「右クリック > 3D Object > Cube」
2.「Inspector」ウィンドウでCubeの「Transform」を下図のように設定

 

3.「Project」ウィンドウの余白で「右クリック > Create > C#スクリプト」
4.名前を「HoldKey」に変更
5.サンプルコードをコピーペーストして保存

 

6.「Hierarchy」ウィンドウで追加した「Cube」をクリック
7.「Inspector」ウィンドウ最下部の「Add Component」ボタンをクリック
8.「holdkey」と入力すると先ほど作った「HoldKey」が出てくるのでクリック

 

ここまでを設定すると、スペースキーを30フレーム押せばConsoleウィンドウに「長押し」と表示されます。

 

GUIの長押し

1.「Hierarchy」ウィンドウの余白で「右クリック > UI > Legacy > Button」
2.「Scene」ビュー右上のボタンから、2Dビューに切り替える
3.「Scene」ビュー内を「ホイールクリック」や「Alt+右クリック」で縮小する
4.「Inspector」ウィンドウでButtonの「Rect Transform」を下図のように設定

 

5.「Project」ウィンドウの余白で「右クリック > Create > C#スクリプト」
6.名前を「HoldGUI」に変更
7.サンプルコードをコピーペーストして保存

 

8.「Hierarchy」ウィンドウで追加した「Button」をクリック
9.「Inspector」ウィンドウ最下部の「Add Component」ボタンをクリック
10.「holdgui」と入力すると先ほど作った「HoldGUI」が出てくるのでクリック

 

以上でボタンの長押しの実装が完了しました。
ボタンを30フレーム押していると「長押し」と表示されます。

 

長押しのアルゴリズム解説

長押しがひととおり作れたところで、余裕のある方はもう少し踏み込んで理解をしてみましょう。
コーディングも大事ですが、最終的に自分が作りたいものを実装できるようになることもまた大事だと思います。

ぜひ今後のヒントとしてご活用ください。

 

長押しの時間を測る

キー入力での時間計測

キー入力では、下記の判定で長押しの時間を計測しています。

        //キーを押しているかを判定
        if (Input.GetKey(KeyCode.Space)) {
            //押しているフレーム数を加算
            _duration = _duration + 1;
        }

この判定は毎フレーム呼ばれるので、_durationに長押しをしているフレーム数が保存されます。

 

重要なのは関数GetKeyで、Inputクラスには関連する下記の関数が用意されています。

●押した瞬間……GetKeyDown
●押している間……GetKey
●離した瞬間……GetKeyUp

より詳しくはキー入力の記事をご覧ください。
【コピペでUnity】これだけで矢印キーの取得がひととおり可能です

 

つまり、関数GetKeyの引数にKeyCode.Spaceを与えることで、スペースキーを押している間を判定出来るワケです。

 

GUIでの時間計測

一方でGUIには「GetKey」にあたる関数がないので、自前で用意する必要が出てきます。
とはいえGetKeyDownにあたるOnPointerDown、GetKeyUpにあたるOnPointerUp関数は実装できるので、これらを上手く組み合わせて判定を取ります。

    //ボタンを押した瞬間
    public void OnPointerDown(PointerEventData eventData) {
        //ボタンを押している状態に変更
        _onPointer = true;
    }

    //ボタンを離した瞬間
    public void OnPointerUp(PointerEventData eventData) {
        //押しているフレーム数をリセット
        _duration = 0;
        //ボタンを押していない状態に変更
        _onPointer = false;
    }

 

「押している間」を判定したいワケですが、単純に考えると押した瞬間から離した瞬間までが押している間です。
押している間を表す変数を「_onPointer」として、押した瞬間に「_onPointer」をtrue、離した瞬間に「_onPointer」をfalseとすれば正しく判定出来たことになりますね。

 

ちなみにOnPointer系の関数はEventSystemsにまとめられている関数で、扱う場合は「IPointerDownHandler」インターフェースと「IPointerUpHandler」を下記のように実装する必要があります。

public class HoldGUI : MonoBehaviour, IPointerDownHandler, IPointerUpHandler

 

以上を踏まえて、時間の計測は下記のように作れます。

        //ボタンを押しているかを判定
        if (_onPointer == true) {
            //押しているフレーム数を加算
            _duration = _duration + 1;
        }

 

長押しの時間を観察し、判定を出す

今回の長押しはフレーム数で判定しているので、毎フレーム呼び出されるUpdate関数を使います。

        //長押しを判定
        if (_duration == _threshold) {
            Debug.Log("長押し");
        }

 

_durationの値は押しているフレーム数がなので、thresholdに設定したフレーム数と一致すれば長押しの判定が出せることになります。
もちろんthresholdの値を大きくすれば、判定が出るまでの時間が長くなります。

また長押しが判定された時にdurationに0を代入すれば、FPSでの連射など、長押しをすると一定の間隔で繰り返される処理が作れるハズです。

 

単純なようで、アルゴリズムを考えると意外と奥が深いですね。
今回は以上です。

Unityはいいぞ。

コメント

タイトルとURLをコピーしました