Unity3D UI, расчет для перетаскивания позиции элемента?
В наши дни невероятно легко перетаскивать элементы пользовательского интерфейса в Unity: сделайте несколько элементов пользовательского интерфейса. Добавить Компонент - > Событие ->Триггер Событие. Падение на сценарий ниже. Нажмите, чтобы добавить четыре очевидных триггеров. Вы закончили.
однако.
я полностью потерялся в отношениях между указатель с координатами и UI координаты (как видно из RectTransform и так далее).
на DragIt
ниже: как ты переместить пользовательского интерфейса панель правильно под пальцем?
скажем, у вас есть одна большая панель с десятью UIButton, сидящими на панели с Dragster
на кнопках. Какова связь между координатами RectTransform и указателем мыши ...
короче говоря, как вы перемещаете одну из кнопок на DragIt () ниже?
/* 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);
}
}
3 ответов
для перетаскивания вещей я просто делаю это:
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");
}
}
Я бы сделал ваш скрипт реализовать интерфейсы перетаскивания
public class Dragster:MonoBehaviour,IBeginDragHandler, IEndDragHandler, IDragHandler
который сделает ваш до DragIt(PointerEventData eventData)
и используйте опцию Dynamic EvenData в раскрывающемся списке для триггера для получения PointerEventData для доступа к Дельта-информации
вот на самом деле общее, полное решение для перетаскивания " UnityEngine.Элементы пользовательского интерфейса, основанные на коде Uri & Colton. Просто скопируйте и вставьте.
поразительное копирование и вставка без проблем идеальное перетаскивание для 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);
}
}
прежде всего, все остальные anwers в этом посте работают очень хорошо. Я работал над этим так долго и просто хотел разместить его здесь. Он добавляет способ предотвратить перетаскивание других нежелательных объектов пользовательского интерфейса.
моей официальной целью было предоставить способ сделать это без использования bool beingDragged = false;
. Вы просто не будете знать, какой Button
или Image
тащат, если вы делаете это так.
перетаскивание UI:
конвертировать Screenpoint в локальную точку в Ректтрансформе с помощью RectTransformUtility
затем использовать Canvas.transform.TransformPoint
чтобы узнать, где именно находится дочерний пользовательский интерфейс.
public Canvas parentCanvasOfImageToMove;
Vector2 pos;
RectTransformUtility.ScreenPointToLocalPointInRectangle(parentCanvasOfImageToMove.transform as RectTransform, eventData.position, parentCanvasOfImageToMove.worldCamera, out pos);
UIToMove.transform.position = parentCanvasOfImageToMove.transform.TransformPoint(pos);
код перетаскивания выглядит более сложным, чем другой код перетаскивания в других ответах, но он, похоже, работает в каждом режиме камеры холста.
обнаружение объекта, который будет перетаскиваться:
самый простой способ сделать это-создать глобальную переменную, которую вы можете использовать для сохранения объекта, который пользователь хочет перетащить в OnBeginDrag
затем вы можете перетащить этот объект в OnDrag
. Установить, что объект в null, когда OnEndDrag
называется.
objectToBeDragged = eventData.pointerCurrentRaycast.gameObject;
это должно быть сделано один раз в OnBeginDrag
функция затем сохраняется в глобальную переменную.
вы не можете сделать следующее в OnDrag
функции
if (eventData.pointerCurrentRaycast.gameObject == someOtherUI)
{
someOtherUI....drag
}
хотя предполагается, что это работает, иногда это не так. Он даже возвращает null иногда во время OnDrag
. Вот почему это должно быть сделано в OnBeginDrag
функция.
обнаружение и перетаскивание кнопки Vs Image:
обнаружение, если пользовательский интерфейс просто Image
и перетащив Image
очень легко.
objectToBeDragged = eventData.pointerCurrentRaycast.gameObject;
Button tempButton = objectToBeDragged.GetComponent<Button>();
Image tempImage = objectToBeDragged.GetComponent<Image>();
если tempImage
is не null
и tempButton
is null
тогда это изображение.
обнаружение, если пользовательский интерфейс просто Button
и перетащив Button
и не легко.
Когда кнопка нажата на сторона/кромка имя the Button
возвращается, что нормально. Но в большинстве случаев, щелчок на Button
происходит средний на Button
что значит не возвращает экземпляр или имя кнопки, но вместо этого возвращает Text
(Дочерний Объект). Вы не могу переместить текст в виде кнопки. Это не сработает.
objectToBeDragged = eventData.pointerCurrentRaycast.gameObject;
Button tempButton = objectToBeDragged.GetComponent<Button>();
Image tempImage = objectToBeDragged.GetComponent<Image>();
Text tempText = objectToBeDragged.GetComponent<Text>();
если tempText
is не null, get 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 Image / Panel и Button. Любая кнопка, которую нужно перетащить, должна быть помещена в 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 };
}