2015年1月20日火曜日

【Unity】uGUIでボタン作成、長押しまで

タイトル通りです。まずやりたいことを列挙します。

・uGUIでボタンをつくる
・モバイル端末に移す、モバイルでの動作確認
・ボタン連打、長押しの差別化

こんなところです。では早速やっていきましょう。

まず Hierarchyビューの create > UI > Button でボタンを作ります。
1クリックで最低限必要なものが全て作られます。

Gameビューにボタンが出てきます。


Canvas > Button にスクリプトの追加と On Click(UnityEngine.UI.ButtonClickedEvent)に対象として Buttonオブジェクトを追加。
On Click() は右下の + アイコンを押せば追加できます。

Runtime Only は Editor and Runtime でもいいんですが Off にはしないでください。
Off にするとボタンを押してもスクリプトが呼ばれなくなってしまいます。
Runtime Only と Editor and Runtime の違いはシーン未実行時に On Click() を実行するかの違いらしいのですが Button だと動作に違いはありませんでした。Button ではなく Slider とかだと機能何か違いが出るらしいのですが…
アタッチしたスクリプトはこちらです。
using UnityEngine;
using System.Collections;

public class ButtonTest : MonoBehaviour {
    public void ClickMyButton()
    {
        Debug.Log("Button is clicked");
    }
}

シーン実行、Gameビューのボタンを押して Console にメッセージが出ればOKです。

ボール動かしてみましょう。
ButtonTest.cs を以下の上書き、
using UnityEngine;
using System.Collections;

public class ButtonTest : MonoBehaviour {
    SphereMovement _sphereMovement;
    GameObject _sphere;

    void Awake()
    {
        _sphere = GameObject.Find("Sphere");
        _sphereMovement = _sphere.GetComponent<SphereMovement>();
    }

    public void ClickMyButton()
    {
        Debug.Log("Button is clicked");
        _sphereMovement.AddForce2Sphere();
    }
}

Sphere と Capsule を作成、Cube で地面を作って3つ全てに Rigidbody & 拘束条件追加。
Sphere に以下をアタッチ、
using UnityEngine;
using System.Collections;

public class SphereMovement : MonoBehaviour {
    public float _power = 5.0f;
    //Rigidbody _rigid;

    void Awake()
    {
        //_rigid = gameObject.GetComponent<Rigidbody>();
    }

    public void AddForce2Sphere()
    {
        rigidbody.AddForce(Vector3.right * _power);
    }
}

シーン実行、ボタン連打、

動きましたね。どうもデフォルトではボタンを押して離した時、つまりボタンが上がった時に On Click() で設定したスクリプトが実行されるようです。更に言えば上がる瞬間にカーソル(もしくは指)がボタン上になければ実行されません。

これ、押した直後にとか設定できないのかな?On Click() を使っている以上無理なのか。

モバイルに転送してみましょう。

モバイルでも動きました。しかしやけにボタンが小さいような…。これが前回問題になりそうで問題にならなかったやつかな?今回は無視します。


次は長押しの設定です。
出来合いのものだと現状無理らしいので作るしかないそうです。

UnityEngine.EventSystems の EventTriggerクラスの Pointer Down, Pointer Up を使う

ヒエラルキーにある EventSystem の Previewビューを見ていて、UnityEngine.EventSystems.PointerEventData.pointerPress を使えばできそうだなーと最初は思ってたんですがこのオブジェクトは EventSystems.EventTrigger.OnPointerDown のレシーバーっぽいのでやはり EventTrigger 使うのが正解のようですね。

以下のスクリプトを Button にアタッチします。
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;

public class UGUILongPress : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
    public UnityEvent _onLongPress = new UnityEvent ();//長押しで呼び出すイベント
    public float _intervalAction = 0.2f;//イベントを呼び出す間隔、イベントは長押ししてる間何度も呼ばれる
    public bool _callEventFirstPress;// 押下開始時にもイベントを呼び出すフラグ//trueにすると連打との区別ができなくなる
    float _nextTime = 0f;// 次の押下判定時間
    public bool _pressed//押下状態
    {
        get;
        private set;
    }

    float _chargePower = 0.0f;
    //Reference
    GameObject _sphere;

    void Awake()
    {
        _sphere = GameObject.Find("Sphere");
    }

    void Update ()
    {
        if (_pressed && _nextTime < Time.realtimeSinceStartup)
        {
            _onLongPress.Invoke ();
            _nextTime = Time.realtimeSinceStartup + _intervalAction;
        }
    }

    public void OnPointerDown (PointerEventData _eventData)
    {
        _pressed = true;
        if (_callEventFirstPress)
        {
            _onLongPress.Invoke ();
        }
        _nextTime = Time.realtimeSinceStartup + _intervalAction;
    }

    public void OnPointerUp (PointerEventData _eventData)
    {
        _pressed = false;
        _sphere.rigidbody.AddForce((Vector3.right + Vector3.up) * _chargePower * 100.0f);
        _chargePower = 0.0f;
    }

    public void LongPress()
    {
        _chargePower += 1.0f;
        Debug.Log (_chargePower);
    }
}

インスペクター上でいくつか設定します。

設定が終ったら動作確認をしてみましょう。

長押しの動作を追加することができました。
ボタンの上にカーソルがある時にボタンを赤くする設定は Button のインスペクターで設定できます。

ひとまずはこんなところですかね、ちょっと問題も残っていますけど。

問題というのは長押しを実行すると加えて単押しも実行してしまうという事が1つ目。
もう1つはボタンからカーソルが外れた場合の処理。
現状、『 押し → 押しっぱなしでボタンからカーソルを離す → 離す 』 でも長押し動作が実行されてしまいます。このように。

ここらへんの処理を変えるにはスクリプトをいじるしかないです。必要に応じて追々やっていきます。その時にまたまとめようと思います。


<おまけ>
デフォルトの設定だと画面サイズが変わるとボタンが写らなくなってしまう、ということもあります。

Button のインスペクターでアンカーの位置を右上に変えておきましょう。


いいかんじですね。それではまた。



参考:
テラシュールブログ Unityの新GUI、UGUIのイベント制御について
チラ裏Unity uGUIでボタンのクリックイベントを取得
Unity公式Community Long press gesture on uGUI button?
West Hill 開発メモ [Unity][uGUI] uGUIでボタン 長押し 判定

0 件のコメント:

コメントを投稿