質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.64%

Unityでドラッグ移動が可能なUIパネルを作りたいです。

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 5,328

Picasso

score 9

実現したいこと

UIのパネルを使って、ステータス表示ウィンドウ的なものを作ろうとしています。

パネルをドラッグで自由に移動させたいのですが、方法が思いつきません。

発生している問題

同じスクリプトをアタッチしている複数のパネルが、ドラッグで同時に動いてしまいます。

該当のソースコード

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class PanelDragCtrl : MonoBehaviour{
    Vector3 mousePos;
    Vector3 clickPos;
    Vector3 offSet;

    bool dragMode = false;

    void Start () {
    }

    void Update () {

        // UIの上にカーソルがある時だけ実行
        if (EventSystem.current.IsPointerOverGameObject() == false)
        {
            return;
        }


        if (Input.GetMouseButtonDown(0))  //クリック開始時に
        {
            clickPos = Input.mousePosition; //ドラッグ開始位置を取得して、
            offSet = transform.position - clickPos; //UIの中心とドラッグ開始位置のズレを取得

            dragMode = true; //ドラッグ処理を開始
        }
        else if (Input.GetMouseButtonUp(0)) //クリック終了時に
        {
            dragMode = false; //ドラッグ処理を終了
        }


        if (dragMode)
            PanelDrag();
    }


    void PanelDrag() 
    {
        mousePos = Input.mousePosition; //ドラッグ中のカーソル位置

        transform.position = mousePos + offSet; //UIをドラッグさせる
    }
}


上記のスクリプトを、UIのパネルにアタッチしていました。
ですが、このままだと、同じスクリプトをアタッチしているパネルが同時に動いてしまいます。

試したこと

まずパネル自体にスクリプトをアタッチするのを止めました。

そして、
『どのパネルをドラッグしているかを認識するために、Rayを飛ばして、RaycastHitを取得。

そして、取得したRaycastHitの座標を移動させる』みたいなスクリプトを書こうとしました。
(書いたスクリプトはメインカメラにアタッチ)

……ですが、RayがUIパネルに当たらないっぽいんです……。

補足情報

Unityのバージョンは、5.6.1f1です。
プログラムは、つい最近始めたばかりの素人です。よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+1

簡単に調べてみたところ、EventSystem.current.IsPointerOverGameObject()はEventSystemオブジェクト上にあるかどうかをチェックするものだと書かれていました。
https://docs.unity3d.com/ja/540/ScriptReference/EventSystems.EventSystem.IsPointerOverGameObject.html
なので、パネルが同時に動いてしまう点については、EventSystem.current.IsPointerOverGameObject()によって、すべてのパネルが反応して動いてしまっていることが原因だと思われます。

また、RayがUIパネルに当たらないとのことですが、通常のRaycastHitではなく、EventSystem.current.RaycastAll()を使えば、反応しました。
こちらを参考に書いてみたところ、こうなりました。
このスクリプトでは、パネル上にポインタがあるだけで反応してしまいますが、これをドラッグ時のみに反応するようにすれば大丈夫でしょう。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class UGuiRaycast : MonoBehaviour
{
    void Update()
    {
        PointerEventData pointer = new PointerEventData(EventSystem.current);
        pointer.position = Input.mousePosition;
        List<RaycastResult> result = new List<RaycastResult>();
        EventSystem.current.RaycastAll(pointer, result);

        foreach (RaycastResult raycastResult in result)
        {
            // 反応したパネルの名前を表示
            Debug.Log(raycastResult.gameObject.name);
        }
    }
}

補足ですが、このUnityのデフォルトのGUIは「uGUI」と呼ばれております。
Googleで「uGUI ドラッグ」と検索すれば、いくつか実装例が見つかるので、一度確認してみるとよいと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

私も初心者なので、見当違いでしたらごめんなさい。
とりあえず、複数のパネルを個別にドラッグさせたいなら、こんな方法はどうでしょうか。

    public void OnDrag ()
    {
        //マウスの座標を取得
        Vector3 mousePos = Camera.main.ScreenToWorldPoint (Input.mousePosition);
        //取得したマウスのz座標をゲームオブジェクトに合わせる(Z座標を固定する)
        mousePos.z = gameObject.transform.position.z;
        //ゲームオブジェクトのワールド座標をマウスのワールド座標に合わせる
        gameObject.transform.position = mousePos;
    }


上記のコードを、Event TriggerのDragにアタッチ。
これで、複数のパネルに同じスクリプトをアタッチしても個別でドラッグできると思います。

UIの上にカーソルがある時だけ実行

当たり判定でhitしていたらOnDrag()を実行するとか、どうでしょう?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

IPointerUpHandler、IPointerDragHandler、IPointerDownHanderあたりを継承して、そちらに処理を書くと楽です。
手抜きで作ると↓みたいな感じ

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class ExampleClass : MonoBehaviour, IPointerDownHandler, IPointerDragHandler
{
    void OnPointerDrag(PointerEventData ev)
    {
        this.GetComponent<RectTransform>().anchoredPosition += ev.delta;
    }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.64%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる