Unity

Event Triggerを使ってButtonでキャラを操作する方法とボタンを押したままで移動させる方法

TETRY 3Dに使われている技術 2

今回も解説していきます。内容はEventをButtonに登録して、押し続けた状態も検知することが目的です。ボタンを押し続けるには一定間隔で入力を送信する必要があります。今回は0.1秒間に1回ボタンが押されるように作っています。

コンテンツ

デモ

まずは動作を先に紹介します。

移動用のボタンを押すことで1歩分移動します。

その後ボタンを押し続けると連続移動を開始します。

ButtonにEventを登録する

まずは作成したButtonオブジェクトにEvent Triggerコンポーネントを追加します。

それからこちらのコードを用意します。

using UnityEngine;
using UnityEngine.EventSystems;
public class bodywalk : MonoBehaviour
{
    //ボタンオブジェクト
    public GameObject leftbutton;
    public GameObject rightbutton;
    //ボタンに登録するイベント。オンオフ両方
    private EventTrigger.Entry entry = new EventTrigger.Entry();
    private EventTrigger.Entry entry0 = new EventTrigger.Entry();
    private EventTrigger.Entry entry2 = new EventTrigger.Entry();
    private EventTrigger.Entry entry20 = new EventTrigger.Entry();
    //押しっぱなしのタイマー
    private float tm = 0;
    //ボタンを単発で押した場合のフラグ
    private bool leftok = true;
    private bool rightok = true;
    //歩きモーション切り替え
    private Animator animator;
    // Start is called before the first frame update
    void Start()
    {
        setButton();
        animator = GetComponent<Animator>();
    }
    // Update is called once per frame
    void Update()
    {
        Moving();
    }
    void setButton()
    {
        //左ボタン用のイベントを作成する。
        EventTrigger _leftbutton = leftbutton.GetComponent<EventTrigger>();
        entry.eventID = EventTriggerType.PointerDown; //ボタン押した時
        entry0.eventID = EventTriggerType.PointerUp; //ボタン離した時
        //ボタン押した時のイベントにLeftMove()を登録
        entry.callback.AddListener((eventData) => { LeftMove(); });
        //ボタン離した時のイベントにLeftMoveOff()を登録
        entry0.callback.AddListener((eventData) => { LeftMoveOff(); });
        //作成したイベントをボタンに登録する。
        _leftbutton.triggers.Add(entry);
        _leftbutton.triggers.Add(entry0);
        //右ボタン用のイベントを作成する。
        EventTrigger _rightbutton = rightbutton.GetComponent<EventTrigger>();
        entry2.eventID = EventTriggerType.PointerDown;
        entry20.eventID = EventTriggerType.PointerUp;
        entry2.callback.AddListener((eventData) => { RightMove(); });
        entry20.callback.AddListener((eventData) => { RightMoveOff(); });
        _rightbutton.triggers.Add(entry2);
        _rightbutton.triggers.Add(entry20);
    }
    //左ボタンを単発で押した場合
    void LeftMove()
    {
        if (leftok)
        {
            animator.SetBool("walking", true);
            transform.rotation = Quaternion.Euler(0, 180, 0);
            //押し続けた時のタイマーを初期化する。
            tm = 0;
            transform.position = new Vector3(transform.position.x - 0.1f, transform.position.y, transform.position.z);
            if(transform.position.x < -9.0f)
            {
                transform.position = new Vector3(-9.0f, transform.position.y, transform.position.z);
            }
        }
        //押し続けた状態のフラグ
        leftok = false;
    }
    //左ボタンを離したとき
    void LeftMoveOff()
    {
        animator.SetBool("walking", false);
        //ボタンを離すと単発フラグがtrueになる。
        leftok = true;
    }
    //右ボタン用
    void RightMove()
    {
        if (rightok)
        {
            animator.SetBool("walking", true);
            transform.rotation = Quaternion.Euler(0, 0, 0);
            tm = 0;
            transform.position = new Vector3(transform.position.x + 0.1f, transform.position.y, transform.position.z);
            if (transform.position.x > 9.0f)
            {
                transform.position = new Vector3(9.0f, transform.position.y, transform.position.z);
            }
        }
        rightok = false;
    }
    void RightMoveOff()
    {
        animator.SetBool("walking", false);
        rightok = true;
    }
    //押し続けたときの挙動
    void Moving()
    {
        if (!leftok && rightok)
        {
            //押した直後はtmが0のためTime.deltaTimeで加算していく。
            if (tm == 0)
            {
                tm += Time.deltaTime;
            }
            //tmが0.25秒のときに位置移動
            else if (tm >= 0.25 && tm < 0.26)
            {
                transform.position += transform.right / 20;
                if (transform.position.x < -9.0f)
                {
                    transform.position = new Vector3(-9.0f, transform.position.y, transform.position.z);
                }
            }
            //tmが0.35秒のときに位置移動
            else if (tm >= 0.35)
            {
                transform.position += transform.right / 20;
                if (transform.position.x < -9.0f)
                {
                    transform.position = new Vector3(-9.0f, transform.position.y, transform.position.z);
                }
                //tmが0.15秒に戻り、0.1秒後に再び押される。
                tm = 0.15f;
            }
            //0.25秒になるまで待機
            else { tm += Time.deltaTime; }
        }
        else if (leftok && !rightok)
        {
            if (tm == 0)
            {
                tm += Time.deltaTime;
            }
            else if (tm >= 0.25 && tm < 0.26)
            {
                transform.position += transform.right / 20;
                if (transform.position.x > 9.0f)
                {
                    transform.position = new Vector3(9.0f, transform.position.y, transform.position.z);
                }
            }
            else if (tm >= 0.35)
            {
                transform.position += transform.right / 20;
                if (transform.position.x > 9.0f)
                {
                    transform.position = new Vector3(9.0f, transform.position.y, transform.position.z);
                }
                tm = 0.15f;
            }
            else { tm += Time.deltaTime; }
        }
        //ボタンが離れればtmを初期化
        else if (leftok || rightok)
        {
            tm = 0;
        }
    }
}

長いので1つづつ解説します。

まずは変数について

//ボタンオブジェクト
    public GameObject leftbutton;
    public GameObject rightbutton;
    //ボタンに登録するイベント。オンオフ両方
    private EventTrigger.Entry entry = new EventTrigger.Entry();
    private EventTrigger.Entry entry0 = new EventTrigger.Entry();
    private EventTrigger.Entry entry2 = new EventTrigger.Entry();
    private EventTrigger.Entry entry20 = new EventTrigger.Entry();
    //押しっぱなしのタイマー
    private float tm = 0;
    //ボタンを単発で押した場合のフラグ
    private bool leftok = true;
    private bool rightok = true;
    //歩きモーション切り替え
    private Animator animator;

ButtonはInspectorから指定しています。左右両方です。

EventTriger.Entryに左右のボタンそれぞれにボタンを押した時と離したときのイベントをセットします。

tm以下は後で説明します。

void setButton()
    {
        //左ボタン用のイベントを作成する。
        EventTrigger _leftbutton = leftbutton.GetComponent<EventTrigger>();
        entry.eventID = EventTriggerType.PointerDown; //ボタン押した時
        entry0.eventID = EventTriggerType.PointerUp; //ボタン離した時
        //ボタン押した時のイベントにLeftMove()を登録
        entry.callback.AddListener((eventData) => { LeftMove(); });
        //ボタン離した時のイベントにLeftMoveOff()を登録
        entry0.callback.AddListener((eventData) => { LeftMoveOff(); });
        //作成したイベントをボタンに登録する。
        _leftbutton.triggers.Add(entry);
        _leftbutton.triggers.Add(entry0);}

SetButton()でButtonにイベントを登録します。

_leftbuttonにEventTriggerを格納して、

先程セットしたentryとentry0にボタンを押す・離すのアクションを加えます。

entryにはボタンを押したときにLeftMove()が、

Entry0にはボタンを離した時にLeftMoveOff()が走ることにします。

trigger.Addで作成したイベントを登録します。

右ボタンも同様にして登録すると、ボタンが使えるようになります。

ボタンの長押しを検知する

まずは単発用のコードを見ます。

void LeftMove()
    {
        if (leftok)
        {
            animator.SetBool("walking", true);
            transform.rotation = Quaternion.Euler(0, 180, 0);
            //押し続けた時のタイマーを初期化する。
            tm = 0;
            transform.position = new Vector3(transform.position.x - 0.1f, transform.position.y, transform.position.z);
            if(transform.position.x < -9.0f)
            {
                transform.position = new Vector3(-9.0f, transform.position.y, transform.position.z);
            }
        }
        //押し続けた状態のフラグ
        leftok = false;
    }
    //左ボタンを離したとき
    void LeftMoveOff()
    {
        animator.SetBool("walking", false);
        //ボタンを離すと単発フラグがtrueになる。
        leftok = true;
    }

leftokは単発であるならtrueで押し続けている間falseになります。

tmは押し続けているボタンの連打間隔として使います。単発で押したときに0へ戻ります。

1回移動後にleftokはfalseになります。

LeftMoveOff()ではボタンから手を離したときにlefokをtrueへ戻して再び単発から始まるようにします。

次のコードが連続で押したときですが、左右共通にしたため長くなりました。

else if (leftok && !rightok)以下が右の動作なので前半を説明します。

void Moving()
    {
        if (!leftok && rightok)
        {
            //押した直後はtmが0のためTime.deltaTimeで加算していく。
            if (tm == 0)
            {
                tm += Time.deltaTime;
            }
            //tmが0.25秒のときに位置移動
            else if (tm >= 0.25 && tm < 0.26)
            {
                transform.position += transform.right / 20;
                if (transform.position.x < -9.0f)
                {
                    transform.position = new Vector3(-9.0f, transform.position.y, transform.position.z);
                }
            }
            //tmが0.35秒のときに位置移動
            else if (tm >= 0.35)
            {
                transform.position += transform.right / 20;
                if (transform.position.x < -9.0f)
                {
                    transform.position = new Vector3(-9.0f, transform.position.y, transform.position.z);
                }
                //tmが0.15秒に戻り、0.1秒後に再び押される。
                tm = 0.15f;
            }
            //0.25秒になるまで待機
            else { tm += Time.deltaTime; }
        }
        else if (leftok && !rightok)
        {
            if (tm == 0)
            {
                tm += Time.deltaTime;
            }
            else if (tm >= 0.25 && tm < 0.26)
            {
                transform.position += transform.right / 20;
                if (transform.position.x > 9.0f)
                {
                    transform.position = new Vector3(9.0f, transform.position.y, transform.position.z);
                }
            }
            else if (tm >= 0.35)
            {
                transform.position += transform.right / 20;
                if (transform.position.x > 9.0f)
                {
                    transform.position = new Vector3(9.0f, transform.position.y, transform.position.z);
                }
                tm = 0.15f;
            }
            else { tm += Time.deltaTime; }
        }
        //ボタンが離れればtmを初期化
        else if (leftok || rightok)
        {
            tm = 0;
        }
    }

左右のボタンを同時に長押ししないために!leftok かつ rightokで左長押しが動くようにしています。

まずはtmが0から始まるため、tm += Time.deltaTime;で0.25秒待機します。

tmが0.25になったときに移動が行われます。その後0.35になった時に再び移動が行われ、tmが0.15秒に戻されます。

そのため0.35の後は0.1秒後に0.25となるため、0.1秒間隔でボタンが連打されます。

どちらかのボタンが離されるとtmが0になります。

TETRY 3Dでの使われ方

TETRY 3Dはブロックを1マスずつ動かしていたため、シームレスな移動よりもメリハリのある移動が重視されました。そのため規則正しい移動間隔が重宝されましたが、別のゲームで使う場合には移動の場合にはいろいろなアプローチがあると思います。

今回は殆どそのまま移動のコードを流用しましたが、フレーム数により移動速度が変わる可能性があります。

また、TETRY 3Dは操作するブロックが次から次へと変わるため、その都度ボタンに操作対象を登録しなければならなかったため、Buttonオブジェクトの取得からスクリプトで行っています。

以上で第2回TETRY 3Dに使われている技術でした。

ご精読ありがとうございました。



0件のコメントを表示

コメントする