So I have a script (For drag and drop inventory system) that was working fine yesterday, but this morning the Items being dragged no longer followed the mouse pointer at the crusors position but instead followed it with a at a distance. So upon clicking the item, nothing happened, once i start dragging the item x,y values just changed and placed itself a few centimeters above the crusor whilst still following the crusor.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class DragHandler : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
public static GameObject itemBeingDragged;
Vector2 startPosition;
Transform startParent;
public void OnBeginDrag ( PointerEventData eventData)
{
itemBeingDragged = gameObject;
startPosition = transform.position;
startParent = transform.parent;
GetComponent<CanvasGroup>().blocksRaycasts = false;
}
public void OnDrag (PointerEventData eventData)
{
transform.position = Input.mousePosition;
}
public void OnEndDrag (PointerEventData eventData)
{
itemBeingDragged = null;
GetComponent<CanvasGroup>().blocksRaycasts = true;
if (transform.parent == startParent)
{
transform.position = startPosition;
}
}
}
ยดยดยด
When you drag an item, the mouse can be anywhere inside the item. You should therefore calculate the delta between the mouse position and the position of the dragged item. You can then add this delta in the OnDrag() functions when setting a new position.
Vector3 delta;
public void OnBeginDrag(PointerEventData eventData)
{
itemBeingDragged = gameObject;
delta = itemBeingDragged.transform.position -
new Vector3(eventData.pressPosition.x, eventData.pressPosition.y, 0);
// ....
}
...
public void OnDrag(PointerEventData eventData)
{
transform.position = Input.mousePosition + delta;
}
Note that we should not use the Input.mousePosition in the OnBeginDrag() since the drag operation starts first after the mouse has moved a bit. We could of course calculate the delta as soon as the mouse button was pressed, and then we can use the Input.mousePosition. But, since you use the OnBeginDrag() we use the event's pressPosition which is the mousePosition when pressed.
Related
I've been through number of answers on this topic, but nothing has seemed to work for my case. I'm trying to detect a mouseDown on a UI element with a canvas renderer which is inside the hierarchy of an object with the canvas on it. I'm new to this, so I'm not sure if the canvas needs to be linked to this canvas renderer or if they have to be on the same object, but the following code is not resulting in the OnPointerDown method being activated.
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections;
public class Knob : MonoBehaviour, IPointerDownHandler, IPointerUpHandler {
public Slider slider;
public GameObject pivot;
public bool selected;
public float z;
public Image image;
public UtilityClass the;
public float min;
public float max;
void Start () {
z = 90;
Quaternion rotation = Quaternion.Euler (0, 0, z);
pivot.transform.rotation = rotation;
}
void Update() {
Vector3 mousePosition = Camera.main.ScreenToWorldPoint (Input.mousePosition);
if (selected) {
float pivotAngle = the.AngleFrom (the.Heading (pivot.transform.position, mousePosition));
if (pivotAngle >= min && pivotAngle <= max)
z = pivotAngle;
Quaternion rotation = Quaternion.Euler (0, 0, z);
pivot.transform.rotation = rotation;
}
}
public void OnPointerDown(PointerEventData eventData) {
selected = true;
}
public void OnPointerUp(PointerEventData eventData) {
selected = false;
}
}
At the moment I don't have a Collider 2D on the object, but I have "Raycast Target" selected in the Image script. Any help would be appreciated.
Credit to Juan Bayona Beriso I was missing an Event System Component.
There is a game Object "Heat" in Unity 2D. I am trying to drag and drop game object on another game object Sun using UI(works for unity version greater than 4.6). Drag works right but when I drop the object in space other than Sun, heat object does not retain its original position. I tried to make it work using colliders and raycasting but it does not seem to work. Here is the code:
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
public class Drag : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler {
public static GameObject itemBeingDragged;
public static Vector2 startPos;
void Start () {
}
#region IBeginDragHandler implementation
public void OnBeginDrag (PointerEventData eventData)
{
itemBeingDragged = gameObject;
startPos = transform.position;
}
#endregion
#region IDragHandler implementation
public void OnDrag (PointerEventData eventData)
{
transform.position = eventData.position;
}
#endregion
#region IEndDragHandler implementation
public void OnEndDrag (PointerEventData eventData)
{
//if itemBeingDragged is in Space then move it to its original position and then assign null
//itemBeingDragged = null;
RaycastHit2D hit = Physics2D.Raycast (Camera.main.ScreenToWorldPoint (Input.mousePosition), Vector2.zero);
if (hit.collider != null)
{
print ("Inside hit.collider" + hit.collider.name);
//Itembeing Dragged ... set it to startPos if released in space
if (hit.collider.gameObject.name == "Heat")
{
LeanTween.move (hit.collider.gameObject,PublicVariables.startPosHeat, 1.5f);
}
}
}
#endregion
}
Any help is much appreciated. Thanks.
I have a script for dragging GameObjects around, but at the moment, whenever I start to drag on the object it jumps to the center itself onto the pointer. What I'd like to achieve is regardless of where I start to drag on the object it initiates drag at that point instead of jumping to the object center first. What do I need to modify in my OnDrag or OnBeginDrag method to achieve this?
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using UnityEngine.EventSystems;
using System.Collections.Generic;
public class DragHandling : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler, IPointerClickHandler
{
public float partScale;
[HideInInspector] public Transform placeholderParent = null;
[HideInInspector] public Transform parentToReturnTo = null;
[HideInInspector] public GameObject trashCan;
[HideInInspector] public GameObject partsPanel;
[HideInInspector] public GameObject partsWindow;
[HideInInspector] public GameObject buildBoard;
GameObject placeholder = null;
GameObject dragLayer;
Vector3 buildPanelScale;
Vector3 partsPanelScale = new Vector3(1.0f, 1.0f, 1.0f);
Vector3 startPosition;
// PolygonCollider2D collider;
void Start ()
{
dragLayer = GameObject.FindGameObjectWithTag("DragLayer");
buildBoard = GameObject.FindGameObjectWithTag("Board");
partsPanel = GameObject.FindGameObjectWithTag("Parts");
partsWindow = GameObject.FindGameObjectWithTag("PartsWindow");
trashCan = GameObject.FindGameObjectWithTag("Trash");
// collider = transform.GetComponent<PolygonCollider2D>();
}
#region IPointerClickHandler implementation
public void OnPointerClick (PointerEventData eventData)
{
if(transform.parent.gameObject == buildBoard)
transform.SetAsLastSibling();
}
#endregion
#region IBeginDragHandler implementation
public void OnBeginDrag (PointerEventData eventData)
{
// create placeholder gap and hold correct position in layout
placeholder = new GameObject();
placeholder.transform.SetParent(transform.parent);
placeholder.transform.SetSiblingIndex(transform.GetSiblingIndex());
parentToReturnTo = transform.parent; // store original parent location
placeholderParent = parentToReturnTo; // set placeholder gameobject transform
startPosition = transform.position;
GetComponent<CanvasGroup>().blocksRaycasts = false; // turn off image raycasting when dragging image in order to see what's behind the image
}
#endregion
#region IDragHandler implementation
public void OnDrag (PointerEventData eventData)
{
Vector3 mousePosition = new Vector3(eventData.position.x, eventData.position.y, 0);
transform.position = Input.mousePosition; // set object coordinates to mouse coordinates
if(transform.parent.gameObject == partsPanel)
transform.SetParent(dragLayer.transform); // pop object to draglayer to move object out of parts Panel
if(transform.parent.gameObject == buildBoard)
transform.SetParent(dragLayer.transform);
}
#endregion
#region IEndDragHandler implementation
public void OnEndDrag (PointerEventData eventData)
{
transform.SetParent(parentToReturnTo); // Snaps object back to orginal parent if dropped outside of a dropzone
transform.SetSiblingIndex(placeholder.transform.GetSiblingIndex()); // Returns card back to placeholder location
GetComponent<CanvasGroup>().blocksRaycasts = true; // turn Raycast back on
Destroy(placeholder); // kill the placeholder if object hits a drop zone or returns to parts panel
if(transform.parent.gameObject == buildBoard)
{
buildPanelScale = new Vector3(partScale, partScale, partScale);
transform.localScale = buildPanelScale;
transform.SetAsLastSibling(); // always place last piece on top
}
if(transform.parent.gameObject == partsPanel)
transform.localScale = partsPanelScale;
}
#endregion
}
I have never used any interface to implement this, But the solution should be the same as using with OnMouseDown, OnMouseUp and OnMouseDrag with the sprites. Try this with your current implementation
using UnityEngine;
using System.Collections;
public class Drag : MonoBehaviour {
private Vector3 offset = Vector3.zero;
void OnMouseDown () {
Vector3 worldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
worldPos.z = transform.position.z;
offset = worldPos - transform.position;
}
void OnMouseDrag () {
Vector3 worldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
worldPos.z = transform.position.z;
worldPos = worldPos - offset;
transform.position = worldPos;
}
void OnMouseUp () {
offset = Vector3.zero;
}
}
I have used this with an orthographic camera on Sprites. Hope this helps.
EDIT
Tried implementing the interfaces as in your code with UI elements. It is working as expected. Only thing is to set the canvas to ScreenSpace-Camera implement the code in the respective interfaces
your question is a bit confusing and if im correct you are saying that the object you start to drag keeps moving to the middle of screen , if you dont want that just update the dragged objects transform in OnEndDrag.
I'm trying to implement a drag and drop system but I'm having a problem with the drag rate at the moment. Currently when I drag an object it only moves a tiny fraction of the amount that my pointer actually moves. How do I fix this?
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using UnityEngine.EventSystems;
using System.Collections.Generic;
public class DragHandling : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler, IPointerClickHandler
{
public float partScale;
[HideInInspector] public Transform placeholderParent = null;
[HideInInspector] public Transform parentToReturnTo = null;
[HideInInspector] public GameObject trashCan;
[HideInInspector] public GameObject partsPanel;
[HideInInspector] public GameObject partsWindow;
[HideInInspector] public GameObject buildBoard;
GameObject placeholder = null;
GameObject dragLayer;
Vector3 buildPanelScale;
Vector3 partsPanelScale = new Vector3(1.0f, 1.0f, 1.0f);
Vector3 startPosition;
private Vector3 offset = Vector3.zero;
void Start ()
{
dragLayer = GameObject.FindGameObjectWithTag("DragLayer");
buildBoard = GameObject.FindGameObjectWithTag("Board");
partsPanel = GameObject.FindGameObjectWithTag("Parts");
partsWindow = GameObject.FindGameObjectWithTag("PartsWindow");
trashCan = GameObject.FindGameObjectWithTag("Trash");
}
#region IPointerClickHandler implementation
public void OnPointerClick (PointerEventData eventData)
{
if(transform.parent.gameObject == buildBoard)
transform.SetAsLastSibling();
}
#endregion
#region IBeginDragHandler implementation
public void OnBeginDrag (PointerEventData eventData)
{
Vector3 worldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
worldPos.z = transform.position.z;
offset = worldPos - transform.position;
// create placeholder gap and hold correct position in layout
placeholder = new GameObject();
placeholder.transform.SetParent(transform.parent);
placeholder.transform.SetSiblingIndex(transform.GetSiblingIndex());
parentToReturnTo = transform.parent; // store original parent location
placeholderParent = parentToReturnTo; // set placeholder gameobject transform
GetComponent<CanvasGroup>().blocksRaycasts = false; // turn off image raycasting when dragging image in order to see what's behind the image
}
#endregion
#region IDragHandler implementation
public void OnDrag (PointerEventData eventData)
{
Vector3 worldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
worldPos.z = transform.position.z;
worldPos = worldPos - offset;
transform.position = worldPos;
if(transform.parent.gameObject == partsPanel)
transform.SetParent(dragLayer.transform); // pop object to draglayer to move object out of parts Panel
if(transform.parent.gameObject == buildBoard)
transform.SetParent(dragLayer.transform);
}
#endregion
#region IEndDragHandler implementation
public void OnEndDrag (PointerEventData eventData)
{
offset = Vector3.zero;
transform.SetParent(parentToReturnTo); // Snaps object back to orginal parent if dropped outside of a dropzone
transform.SetSiblingIndex(placeholder.transform.GetSiblingIndex()); // Returns card back to placeholder location
GetComponent<CanvasGroup>().blocksRaycasts = true; // turn Raycast back on
Destroy(placeholder); // kill the placeholder if object hits a drop zone or returns to parts panel
if(transform.parent.gameObject == buildBoard)
{
buildPanelScale = new Vector3(partScale, partScale, partScale);
transform.localScale = buildPanelScale;
transform.SetAsLastSibling(); // always place last piece on top
}
if(transform.parent.gameObject == partsPanel)
transform.localScale = partsPanelScale;
}
#endregion
}
Right off the back, you should use eventData.position instead of Input.mousePosition. ScreenToWorldPoint takes a Vector3 but Input.mousePosition is a Vector2. I also personally wouldn't use ScreenToWorldPoint for this purpose, id use a raycast, and use the RayCastHit hit.point for where to put the object as its being dragged, which would be alot more accurate for you.
Actually, since you are using Unity Canvas, you should use RectTransformUtility.ScreenPointToLocalPointInRectangle(...) and put in the parent rect or canvas for what you are trying to drag. It will give you the coordinates you want.
implementation:
RectTransform parentRect = (RectTransform)objectToBeDragged.transform.parent;
Vector2 posInParent;
RectTransformUtility.ScreenPointToLocalPointInRectangle(parentRect, eventData.position, Camera.main, out posInParent);
objectToBeDragged.localPosition = posInParent;
I also just realized another problem you might be experiencing is that you are using transform.position instead of transform.localPosition not saying for sure thats the problem but sometimes that can really bite you in the ass.
I'm using Unity 5, withthe new uGUI system and I'm having a terrible time getting pointer events to ignore the clear space around my sprites and register only the image area. I've attached images and code to show where I'm at. I cannot get the this to work.
Ultimately, the thing I'm trying to achieve is to just have the click event interact with the image rather than the entire image sprite (everything in the rectangular bounding box).
My image texture type is Sprite (2D and UI). I made sure the space around my image is indeed transparent, yet the clear space around the image is still registering a click.
What am I doing wrong here? Need help!
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using UnityEngine.EventSystems;
using System.Collections.Generic;
public class DragHandling : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler, IPointerClickHandler
{
public float partScale;
[HideInInspector] public Transform placeholderParent = null;
[HideInInspector] public Transform parentToReturnTo = null;
[HideInInspector] public GameObject trashCan;
[HideInInspector] public GameObject partsPanel;
[HideInInspector] public GameObject partsWindow;
[HideInInspector] public GameObject buildBoard;
GameObject placeholder = null;
GameObject dragLayer;
Vector3 buildPanelScale;
Vector3 partsPanelScale = new Vector3(1.0f, 1.0f, 1.0f);
Vector3 startPosition;
void Start ()
{
dragLayer = GameObject.FindGameObjectWithTag("DragLayer");
buildBoard = GameObject.FindGameObjectWithTag("Board");
partsPanel = GameObject.FindGameObjectWithTag("Parts");
partsWindow = GameObject.FindGameObjectWithTag("PartsWindow");
trashCan = GameObject.FindGameObjectWithTag("Trash");
}
#region IPointerClickHandler implementation
public void OnPointerClick (PointerEventData eventData)
{
if(transform.parent.gameObject == buildBoard)
transform.SetAsLastSibling();
}
#endregion
#region IBeginDragHandler implementation
public void OnBeginDrag (PointerEventData eventData)
{
// create placeholder gap and hold correct position in layout
placeholder = new GameObject();
placeholder.transform.SetParent(transform.parent);
placeholder.transform.SetSiblingIndex(transform.GetSiblingIndex());
parentToReturnTo = transform.parent; // store original parent location
placeholderParent = parentToReturnTo; // set placeholder gameobject transform
startPosition = transform.position;
GetComponent<CanvasGroup>().blocksRaycasts = false; // turn off image raycasting when dragging image in order to see what's behind the image
}
#endregion
#region IDragHandler implementation
public void OnDrag (PointerEventData eventData)
{
Vector3 mousePosition = new Vector3(eventData.position.x, eventData.position.y, 0);
transform.position = Input.mousePosition; // set object coordinates to mouse coordinates
if(transform.parent.gameObject == partsPanel)
transform.SetParent(dragLayer.transform); // pop object to draglayer to move object out of parts Panel
if(transform.parent.gameObject == buildBoard)
transform.SetParent(dragLayer.transform);
}
#endregion
#region IEndDragHandler implementation
public void OnEndDrag (PointerEventData eventData)
{
transform.SetParent(parentToReturnTo); // Snaps object back to orginal parent if dropped outside of a dropzone
transform.SetSiblingIndex(placeholder.transform.GetSiblingIndex()); // Returns card back to placeholder location
GetComponent<CanvasGroup>().blocksRaycasts = true; // turn Raycast back on
Destroy(placeholder); // kill the placeholder if object hits a drop zone or returns to parts panel
if(transform.parent.gameObject == buildBoard)
{
buildPanelScale = new Vector3(partScale, partScale, partScale);
transform.localScale = buildPanelScale;
transform.SetAsLastSibling(); // always place last piece on top
}
if(transform.parent.gameObject == partsPanel)
transform.localScale = partsPanelScale;
}
#endregion
}