Unity3D UI, calcul pour la position en faisant glisser un élément?

De nos jours, il est incroyablement facile de faire glisser des éléments d’interface utilisateur dans Unity: créez quelques éléments d’interface utilisateur. Ajouter un composant -> Événement -> Déclencheur d’événement . Drop sur le script ci-dessous. Cliquez pour append les quatre déclencheurs évidents. Vous avez terminé.

Toutefois.

Je suis totalement perdu dans la relation entre les coordonnées du pointeur et les coordonnées de l’interface utilisateur (comme dans RectTransform, etc.).

Dans DragIt ci-dessous: comment diable déplacez-vous correctement un panneau d’interface utilisateur sous le doigt?

Supposons que vous ayez un grand panneau, avec dix UIButton assis dans le panneau et Dragster sur les boutons. Quelle est la relation entre les coordonnées RectTransform et le pointeur de la souris …

En bref, comment déplacez-vous l’un des boutons de DragIt () ci-dessous?

 /* 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() { ? ? WTF ? ? } public void DragEnd() { beingDragged = false; } public void DroppedBra() { Debig.Log("Drag: from/to " +dragFrom +" --> " +index); } } 

Pour le Draging, je fais juste ceci:

 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"); } } 

Je voudrais que votre script implémente les interfaces de glisser

public class Dragster:MonoBehaviour,IBeginDragHandler, IEndDragHandler, IDragHandler

Qui fera de votre fonction DragIt devenir

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

en vous donnant access au delta de cet événement (de combien la souris a bougé) pour pouvoir déplacer votre object.

Si vous préférez toujours utiliser le composant EventTrigger (méthode préférée), il vous suffit de modifier votre fonction DragIt en DragIt(PointerEventData eventData) et d’utiliser l’option Dynamic EvenData dans le menu déroulant pour que le déclencheur reçoive PointerEventData pour accéder au delta information


Voici en fait une solution complète et complète pour le glisser-déposer des éléments ‘UnityEngine.UI`, basée sur le code d’Uri & Colton. Il suffit de copier et coller.

Copier-coller stupéfiant et glisser-déposer parfait pour 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(); 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().info; YourThings untoThing = gameObject.GetComponent().info; yourBossyObject.dragHappenedFromTo(fromThing, untoThing); } } 

Tout d’abord, toutes les autres réponses de ce post fonctionnent très bien. J’ai travaillé dessus pendant si longtemps et je voulais juste le poster ici. Cela ajoute un moyen d’empêcher d’autres objects d’interface utilisateur non désirés d’être déplacés.

Mon objective officiel était de fournir un moyen de faire cela sans utiliser bool beingDragged = false; . Vous ne saurez tout simplement pas quel Button ou quelle Image est déplacé si vous le faites comme ça.

Glisser l’interface utilisateur :

Convertissez le sharepoint vue en point local dans RectTransform à l’aide de RectTransformUtility puis utilisez Canvas.transform.TransformPoint pour savoir où se trouve exactement l’interface utilisateur enfant.

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

Le code de glissement semble plus compliqué que les autres codes de glissement dans les autres réponses, mais il semble fonctionner dans tous les modes de caméra Canvas.

Détecter quel object est sur le point d’être glissé :

Le moyen le plus simple consiste à créer une variable globale que vous pouvez utiliser pour enregistrer l’object que vous souhaitez faire glisser dans la fonction OnBeginDrag . Vous pouvez également faire glisser cet object dans OnDrag . Définissez cet object sur null lorsque OnEndDrag est appelé.

 objectToBeDragged = eventData.pointerCurrentRaycast.gameObject; 

Cela doit être fait une fois dans la fonction OnBeginDrag , puis enregistré dans une variable globale.

Vous ne pouvez pas faire ce qui suit dans la fonction OnDrag

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

Même si cela est supposé fonctionner, cela ne fonctionne pas parfois. Il retourne même null parfois pendant OnDrag . C’est pourquoi cela doit être fait dans la fonction OnBeginDrag .

Détection et glissement du bouton contre l’image :

Détecter si l’interface utilisateur est juste une Image et faire glisser une Image est très facile.

 objectToBeDragged = eventData.pointerCurrentRaycast.gameObject; Button tempButton = objectToBeDragged.GetComponent 

Si tempImage n’est pas null et que tempButton est null il s’agit d’une image.

Détecter si l’interface utilisateur est juste un Button et faire glisser un Button n’est pas facile. Quand un bouton est cliqué sur le côté / bord , le nom du Button est renvoyé, ce qui est correct. Mais la plupart du temps, un clic sur un Button se produit au milieu du Button ce qui ne renvoie ni l’instance ni le nom du bouton, mais renvoie le Text (object enfant). Vous NE POUVEZ PAS déplacer un texte en tant que bouton. Cela ne fonctionnera pas.

 objectToBeDragged = eventData.pointerCurrentRaycast.gameObject; Button tempButton = objectToBeDragged.GetComponent 

Si tempText n’est pas null, obtenez GetComponentInParent des composants Image et Button du texte. Si l’ Image n’est pas nulle et que Button n’est pas nul, il s’agit d’un Button .

 if (tempText != null) { tempButton = tempText.GetComponentInParent 

Vous trouverez ci-dessous le script complet consistant à faire glisser une image, un panneau et un bouton de l’interface utilisateur Tout bouton devant être déplacé doit être placé dans le tableau UIButtons et tout panneau / image devant être déplacé doit être placé dans le tableau UIPanels . Il ignorera les autres interfaces utilisateur qui ne sont pas dans le tableau.

 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(); } //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