Unity3D UI,计算位置拖动项目?
现在,在Unity中拖动UI元素非常容易:制作一些UI项目。 添加组件 – >事件 – > 事件触发器 。 放在下面的脚本上。 单击以添加四个明显的触发器。 你完成了。
然而。
我完全迷失了指针坐标和UI坐标之间的关系(如RectTransform中所见,等等)。
在下面的DragIt
中:如何在手指下正确移动UI面板?
假设您有一个大面板,十个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() { ? ? WTF ? ? } public void DragEnd() { beingDragged = false; } public void DroppedBra() { Debig.Log("Drag: from/to " +dragFrom +" --> " +index); } }
对于Draging的东西我只是这样做:
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
function成为
public void OnDrag(PointerEventData eventData) { transform.position += (Vector3)eventData.delta; }
允许您访问该事件的增量(鼠标移动了多少)以便能够移动您的对象。
如果你仍然宁愿使用EventTrigger组件(不太喜欢的方式),你只需要将DragIt
函数更改为DragIt(PointerEventData eventData)
并在下拉列表中使用Dynamic EvenData选项来触发接收PointerEventData以访问delta信息
这里实际上是基于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(); 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); } }
首先,这篇文章中的所有其他答案都运作良好。 我在这方面工作了很长时间,只想在这里发布。 它添加了一种方法来防止拖动其他不需要的UI对象。
我的官方目标是提供一种方法来实现这一点,而不使用bool beingDragged = false;
。 如果您这样做,您将无法知道正在拖动哪个Button
或Image
。
拖动UI :
借助RectTransformUtility将Rectpoint中的Screenpoint转换为Local Point,然后使用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
函数中执行以下OnDrag
if (eventData.pointerCurrentRaycast.gameObject == someOtherUI) { someOtherUI....drag }
即使它被认为是有效的,但有时也没有。 它甚至在OnDrag
期间有时返回null。 这就是必须在OnBeginDrag
函数中完成的OnBeginDrag
。
检测并拖动按钮与图像 :
检测UI是否只是Image
和拖动Image
非常容易。
objectToBeDragged = eventData.pointerCurrentRaycast.gameObject; Button tempButton = objectToBeDragged.GetComponent
如果tempImage
不为 null
且tempButton
为null
那么这是一个Image。
检测UI是否只是一个Button
并拖动Button
并不容易。 在侧面/边缘上单击Button
将返回Button
的名称,这很好。 但是大多数情况下,在Button
的中间点击Button
会发生Button
,它不返回Button
的实例或名称,而是返回Text
(子对象)。 您无法将文本作为按钮移动。 它不会工作。
objectToBeDragged = eventData.pointerCurrentRaycast.gameObject; Button tempButton = objectToBeDragged.GetComponent
如果tempText
不为 null,则获取GetComponentInParent
的Image和Button组件的GetComponentInParent
。 如果Image
不为null且Button
不为null,那么它是一个Button
。
if (tempText != null) { tempButton = tempText.GetComponentInParent
下面是拖动UI图像/面板和按钮的完整脚本。 应该拖动的任何按钮都应该放在UIButtons
数组中,任何应该拖动的Panel / Image都应该放在UIPanels
数组中。 它将忽略不在Array中的其他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