web-dev-qa-db-ja.com

Unity3D UI、アイテムをドラッグする位置の計算?

最近では、UnityでUI要素をドラッグするのは非常に簡単です。いくつかのUIアイテムを作成します。コンポーネント->イベント-> イベントトリガーを追加します。以下のスクリプトにドロップしてください。クリックして、4つの明白なトリガーを追加します。完了です。

しかしながら。

ポインター座標I座標(RectTransformなどで見られる)の関係に完全に夢中になっています。

以下のDragItで:UIパネルを指の下で正しく移動するにはどうすればよいですか?

大きなパネルが1つあり、そのパネルに10個のUIButtonがあり、ボタンにDragsterが付いているとします。 RectTransformの座標とマウスポインターの関係は何ですか?.

簡単に言うと、下のDragIt()でボタンの1つをどのように移動しますか?

/* modern Unity drag of UI element */
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
public class Dragster:MonoBehaviour
    {
    public int index; // number each of your UI items
    static bool beingDragged = false;
    static int dragFrom;
    public void DragStart()
        {
        beingDragged = true; dragFrom = index;
        }
    public void DragIt()
        {
        ? ? W T F ? ?
        }
    public void DragEnd()
        {
        beingDragged = false;
        }
    public void DroppedBra()
        {
        Debig.Log("Drag: from/to " +dragFrom +" --> " +index);
        }
    }
13
Fattie

ドラッグのものについては、これを行うだけです:

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class Draggable : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler {



    public void OnBeginDrag(PointerEventData eventData) {

    }

    public void OnDrag(PointerEventData eventData) {
        //Debug.Log ("OnDrag");

        this.transform.position = eventData.position;

        }

    public void OnEndDrag(PointerEventData eventData) {
        Debug.Log ("OnEndDrag");

    }
}
5
Uri Popov

スクリプトにドラッグインターフェイスを実装させます

_public class Dragster:MonoBehaviour,IBeginDragHandler, IEndDragHandler, IDragHandler_

どちらがDragIt関数になるか

_public void OnDrag(PointerEventData eventData)
{
    transform.position += (Vector3)eventData.delta;
}
_

オブジェクトを移動できるように、そのイベントのデルタ(マウスの移動量)にアクセスできるようにします。

それでもEventTriggerコンポーネントを使用する場合(あまりお勧めしない方法)、DragIt関数をDragIt(PointerEventData eventData)に変更し、トリガーのドロップダウンで[Dynamic EvenData]オプションを使用するだけです。デルタ情報にアクセスするためのPointerEventDataを受け取ります


Uri&Coltonのコードに基づいて、ドラッグアンドドロップの「UnityEngine.UI」アイテムの完全で完全なソリューションを次に示します。コピーして貼り付けてください。

Unity UI、wtt Colton&Uriのための驚異的なコピーと貼り付けの完璧なドラッグアンドドロップ:

_using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class UNCDraggable:MonoBehaviour,
IBeginDragHandler, IDragHandler, IEndDragHandler, IDropHandler
    {
    public Image ghost;
    // note DON'T try to drag the actual item: it's not worth the hassle.
    // a problem arises where you can't have it on top (as you would want
    // visually), and still easily get the drops. always use a ghost.
    // even if you want the "original invisible" while dragging,
    // simply hide it and use a ghost. everything is tremendously
    // easier if you do not move the originals.

    void Awake()
        {
        ghost.raycastTarget = false;
        // (just in case you forgot to do that in the Editor)
        ghost.enabled = false;
        }

    public void OnBeginDrag(PointerEventData eventData)
        {
        ghost.transform.position = transform.position;
        ghost.enabled = true;
        }

    public void OnDrag(PointerEventData eventData)
        {
        ghost.transform.position += (Vector3)eventData.delta;
        }

    public void OnEndDrag(PointerEventData eventData)
        {
        ghost.enabled = false;
        }

    public void OnDrop(PointerEventData data)
        {
        GameObject fromItem = data.pointerDrag;
        if (data.pointerDrag == null) return; // (will never happen)

        UNCDraggable d = fromItem.GetComponent<UNCDraggable>();
        if (d == null)
          {
          // means something unrelated to our system was dragged from.
          // for example, just an unrelated scrolling area, etc.
          // simply completely ignore these.
          return;
          // note, if very unusually you have more than one "system"
          // of UNCDraggable items on the same screen, be careful to
          // distinguish them! Example solution, check parents are same.
          }

        Debug.Log ("dropped  " + fromItem.name +" onto " +gameObject.name);

        // your code would look probably like this:
        YourThings fromThing = fromItem.GetComponent<YourButtons>().info;
        YourThings untoThing = gameObject.GetComponent<YourButtons>().info;

        yourBossyObject.dragHappenedFromTo(fromThing, untoThing);
        }
    }
_
10
Colton White

まず、この投稿の他のすべての回答は非常にうまく機能しています。私はこれに長い間取り組んでおり、ここに投稿したかっただけです。他の不要なUIオブジェクトがドラッグされるのを防ぐ方法を追加します。

私の公式の目標は、bool beingDragged = false;を使用せずにこれを行う方法を提供することでした。このようにすると、ドラッグされているButtonまたはImageがわかりません。

Iのドラッグ

RectTransformUtilityの助けを借りてRectTransformでスクリーンポイントをローカルポイントに変換し、次にCanvas.transform.TransformPointを使用して、子UIが正確にどこにあるかを確認します。

public Canvas parentCanvasOfImageToMove;
Vector2 pos;
RectTransformUtility.ScreenPointToLocalPointInRectangle(parentCanvasOfImageToMove.transform as RectTransform, eventData.position, parentCanvasOfImageToMove.worldCamera, out pos);
UIToMove.transform.position = parentCanvasOfImageToMove.transform.TransformPoint(pos);

ドラッグコードは、他の回答では他のドラッグコードよりも複雑に見えますが、すべてのCanvasカメラモードで機能しているようです。

ドラッグされようとしているオブジェクトの検出

これを行う最も簡単な方法は、ユーザーがOnBeginDrag関数にドラッグしたいオブジェクトを保存するために使用できるグローバル変数を作成し、そのオブジェクトをOnDragにドラッグすることです。 OnEndDragが呼び出されたときに、そのオブジェクトをnullに設定します。

objectToBeDragged = eventData.pointerCurrentRaycast.gameObject;

これは、OnBeginDrag関数で一度実行してから、グローバル変数に保存する必要があります。

OnDrag関数では次のことはできません

if (eventData.pointerCurrentRaycast.gameObject == someOtherUI)
{
   someOtherUI....drag
}

動作することを想定していますが、動作しない場合もあります。 OnDragの実行中にnullが返されることもあります。これがOnBeginDrag関数で行わなければならない理由です。

ボタンとイメージの検出とドラッグ

UIがImageであるかどうかの検出とImageのドラッグは非常に簡単です。

objectToBeDragged  = eventData.pointerCurrentRaycast.gameObject;
Button tempButton = objectToBeDragged.GetComponent<Button>();
Image tempImage = objectToBeDragged.GetComponent<Image>();

tempImagenotnullで、tempButtonnullの場合、それは画像です。

UIがButtonであるかどうかの検出とButtonのドラッグは[〜#〜] not [〜#〜]簡単です。ボタンがside/Edgeでクリックされると、Buttonの名前が返されますが、これは問題ありません。しかし、ほとんどの場合、ButtonのクリックはButtonの-​​middleで発生しますnotはインスタンスまたは名前を返しますButtonの代わりにText(Child Object)を返します。あなたは[〜#〜]できません[〜#〜]テキストをボタンとして移動します。うまくいきません。

objectToBeDragged  = eventData.pointerCurrentRaycast.gameObject;
Button tempButton = objectToBeDragged.GetComponent<Button>();
Image tempImage = objectToBeDragged.GetComponent<Image>();
Text tempText = objectToBeDragged.GetComponent<Text>();

tempTextnot nullの場合、テキストの画像およびボタンコンポーネントのGetComponentInParentを取得します。 Imageがnullでなく、Buttonがnullでない場合は、Buttonです。

if (tempText != null)
{
    tempButton = tempText.GetComponentInParent<Button>();
    tempImage = tempText.GetComponentInParent<Image>();
    if (tempButton != null && tempImage != null)
    {
        //This is a Button
    }
}

以下は、UI画像/パネルとボタンをドラッグする完全なスクリプトです。ドラッグする必要のあるボタンはUIButtons配列に配置し、ドラッグする必要のあるパネル/画像はUIPanels配列に配置する必要があります。配列に含まれていない他のUIは無視されます。

public class UIDRAGGER : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    public Canvas parentCanvasOfImageToMove;

    //10 UI Buttons (Assign in Editor)
    public Button[] UIButtons;

    //2 UI Panels/Images (Assign in Editor)
    public Image[] UIPanels;

    //Hold which Button or Image is selected
    private Button selectedButton;
    private Image selectedUIPanels;

    //Used to make sure that the UI is position exactly where mouse was clicked intead of the default center of the UI
    Vector3 moveOffset;

    //Used to decide which mode we are in. Button Drag or Image/Panel Mode
    private DragType dragType = DragType.NONE;


    void Start()
    {
        parentCanvasOfImageToMove = gameObject.GetComponent<Canvas>();
    }

    //Checks if the Button passed in is in the array
    bool buttonIsAvailableInArray(Button button)
    {
        bool _isAValidButton = false;
        for (int i = 0; i < UIButtons.Length; i++)
        {
            if (UIButtons[i] == button)
            {
                _isAValidButton = true;
                break;
            }
        }
        return _isAValidButton;
    }

    //Checks if the Panel/Image passed in is in the array
    bool imageIsAvailableInArray(Image image)
    {
        bool _isAValidImage = false;
        for (int i = 0; i < UIPanels.Length; i++)
        {
            if (UIPanels[i] == image)
            {
                _isAValidImage = true;
                break;
            }
        }
        return _isAValidImage;
    }

    void selectButton(Button button, Vector3 currentPos)
    {
        //check if it is in the image array that is allowed to be moved
        if (buttonIsAvailableInArray(button))
        {
            //Make the image the current selected image
            selectedButton = button;
            dragType = DragType.BUTTONS;
            moveOffset = selectedButton.transform.position - currentPos;
        }
        else
        {
            //Clear the selected Button
            selectedButton = null;
            dragType = DragType.NONE;
        }
    }

    void selectImage(Image image, Vector3 currentPos)
    {
        //check if it is in the image array that is allowed to be moved
        if (imageIsAvailableInArray(image))
        {
            //Make the image the current selected image
            selectedUIPanels = image;
            dragType = DragType.IMAGES;
            moveOffset = selectedUIPanels.transform.position - currentPos;
        }
        else
        {
            //Clear the selected Button
            selectedUIPanels = null;
            dragType = DragType.NONE;
        }
    }


    public void OnBeginDrag(PointerEventData eventData)
    {
        GameObject tempObj = eventData.pointerCurrentRaycast.gameObject;

        if (tempObj == null)
        {
            return;
        }

        Button tempButton = tempObj.GetComponent<Button>();
        Image tempImage = tempObj.GetComponent<Image>();
        Text tempText = tempObj.GetComponent<Text>();

        //For Offeset Position
        Vector2 pos;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(parentCanvasOfImageToMove.transform as RectTransform, eventData.position, parentCanvasOfImageToMove.worldCamera, out pos);


        //Button must contain Text then Image and Button as parant
        //Check if this is an image
        if (tempButton == null || tempImage == null)
        {
            //Button not detected. Check if Button's text was detected
            if (tempText != null)
            {
                //Text detected. Now Look for Button and Image in the text's parent Object
                tempButton = tempText.GetComponentInParent<Button>();
                tempImage = tempText.GetComponentInParent<Image>();

                //Since child is text, check if parents are Button and Image
                if (tempButton != null && tempImage != null)
                {
                    //This is a Button
                    selectButton(tempButton, parentCanvasOfImageToMove.transform.TransformPoint(pos));
                }
                //Check if there is just an image
                else if (tempImage != null)
                {
                    //This is an Image
                    selectImage(tempImage, parentCanvasOfImageToMove.transform.TransformPoint(pos));
                }
            }
            else
            {
                //This is an Image
                selectImage(tempImage, parentCanvasOfImageToMove.transform.TransformPoint(pos));
            }
        }
        //Check if there is just an image
        else if (tempImage != null)
        {
            selectImage(tempImage, parentCanvasOfImageToMove.transform.TransformPoint(pos));
        }
    }

    public void OnDrag(PointerEventData eventData)
    {
        Vector2 pos;
        if (dragType == DragType.BUTTONS)
        {
            RectTransformUtility.ScreenPointToLocalPointInRectangle(parentCanvasOfImageToMove.transform as RectTransform, eventData.position, parentCanvasOfImageToMove.worldCamera, out pos);
            selectedButton.transform.position = parentCanvasOfImageToMove.transform.TransformPoint(pos) + moveOffset;
        }
        else if (dragType == DragType.IMAGES)
        {
            RectTransformUtility.ScreenPointToLocalPointInRectangle(parentCanvasOfImageToMove.transform as RectTransform, eventData.position, parentCanvasOfImageToMove.worldCamera, out pos);
            selectedUIPanels.transform.position = parentCanvasOfImageToMove.transform.TransformPoint(pos) + moveOffset;
        }
    }


    public void OnEndDrag(PointerEventData eventData)
    {
        //Buttons
        if (dragType == DragType.BUTTONS || dragType == DragType.IMAGES)
        {
            selectedButton = null;
            selectedUIPanels = null;
            dragType = DragType.NONE;
        }
    }

    DragType getCurrentDragType()
    {
        return dragType;
    }

    private enum DragType { NONE, BUTTONS, IMAGES };
}
7
Programmer