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. Déposez sur le script ci-dessous. Cliquez pour ajouter les quatre déclencheurs évidents. Vous avez terminé.
Toutefois.
Je suis totalement perdu dans la relation entre coordonnées du pointeur et coordonnées UI (comme on le voit dans RectTransform et ainsi de suite).
Dans DragIt
ci-dessous: comment diable déplacez-vous un panneau d'interface utilisateur correctement sous le doigt?
Disons que vous avez un grand panneau, avec dix UIButton assis dans le panneau avec 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 dans 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()
{
? ? W T F ? ?
}
public void DragEnd()
{
beingDragged = false;
}
public void DroppedBra()
{
Debig.Log("Drag: from/to " +dragFrom +" --> " +index);
}
}
Pour faire glisser des trucs, 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 ferais en sorte que votre script implémente les interfaces de glisser
public class Dragster:MonoBehaviour,IBeginDragHandler, IEndDragHandler, IDragHandler
Ce qui fera que votre fonction DragIt
deviendra
public void OnDrag(PointerEventData eventData)
{
transform.position += (Vector3)eventData.delta;
}
vous donnant accès au delta de cet événement (combien la souris a bougé) pour pouvoir déplacer votre objet.
Si vous préférez toujours utiliser le composant EventTrigger (de manière moins préférée), il vous suffit de changer votre fonction DragIt
en DragIt(PointerEventData eventData)
et d'utiliser l'option Dynamic EvenData dans la liste déroulante du déclencheur pour recevoir le PointerEventData pour accéder aux informations delta
Voici en fait une solution totale et complète de glisser-déposer des éléments "UnityEngine.UI", basée sur le code d'Uri & Colton. Copiez et collez.
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);
}
}
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. Il ajoute un moyen d'empêcher que d'autres objets d'interface utilisateur indésirables ne soient traînés.
Mon objectif officiel était de fournir un moyen de le faire sans utiliser bool beingDragged = false;
. Vous ne saurez simplement pas qui Button
ou Image
est déplacé si vous le faites comme ça.
Glisser UI:
Convertissez Screenpoint 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 d'autres réponses, mais il semble fonctionner dans tous les modes de la caméra Canvas.
Détecter quel objet est sur le point d'être glissé:
La façon la plus simple de procéder consiste à créer une variable globale que vous pouvez utiliser pour enregistrer l'objet que l'utilisateur souhaite faire glisser dans la fonction OnBeginDrag
, puis vous pouvez faire glisser cet objet dans le OnDrag
. Définissez cet objet 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 fonctionne, ce n'est pas toujours le cas. Il retourne même null parfois pendant OnDrag
. C'est pourquoi cela doit être fait dans la fonction OnBeginDrag
.
Détection et déplacement du bouton par rapport à l'image:
Détecter si l'interface utilisateur n'est qu'un Image
et faire glisser un Image
est très facile.
objectToBeDragged = eventData.pointerCurrentRaycast.gameObject;
Button tempButton = objectToBeDragged.GetComponent<Button>();
Image tempImage = objectToBeDragged.GetComponent<Image>();
Si tempImage
est pasnull
et tempButton
est null
alors c'est une Image.
Détecter si l'interface utilisateur n'est qu'un Button
et faire glisser un Button
est PAS facile. Lorsqu'un bouton est cliqué sur 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 dans le milie du Button
qui ne pas retourne l'instance ou le nom du bouton mais renvoie à la place le Text
(objet enfant). Vous NE POUVEZ PAS déplacer un texte en tant que bouton. Ça ne marchera pas.
objectToBeDragged = eventData.pointerCurrentRaycast.gameObject;
Button tempButton = objectToBeDragged.GetComponent<Button>();
Image tempImage = objectToBeDragged.GetComponent<Image>();
Text tempText = objectToBeDragged.GetComponent<Text>();
si tempText
est pas null, obtenez GetComponentInParent
du composant Image et Button du texte. Si le Image
n'est pas nul et que le Button
n'est pas nul alors c'est un Button
.
if (tempText != null)
{
tempButton = tempText.GetComponentInParent<Button>();
tempImage = tempText.GetComponentInParent<Image>();
if (tempButton != null && tempImage != null)
{
//This is a Button
}
}
Vous trouverez ci-dessous le script complet de déplacement de l'image/du panneau et du bouton de l'interface utilisateur. Tout bouton qui doit être glissé doit être placé dans le tableau UIButtons
et tout panneau/image qui doit être glissé 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<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 };
}