i’m trying to create a drag and drop script but as you’ve seen in the title it doesn’t work. When i drag things (thanks to the dragable2 script) the dropzone2 script doesn’t fire OnPointerEnter and OnPointerExit while it does it very well when i’m not dragging anything (but the whole purpose is to actually work when i’m dragging things). So is it normal or is it a bug ? as far as i know it is a bug because you have this in the doc : Redirecting to latest version of com.unity.ugui
I’m using these scripts with sprites so i added a physicsRaycaster2D to my camera and a boxColliders2D to each of my objects.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class Dragable2 : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler,IPointerClickHandler {
public Transform parentToReturnTo = null;
public Transform placeholderParent = null;
int index;
DropZone2 dropzone = null;
GameObject placeholder = null;
public void OnPointerClick (PointerEventData eventData)
{
return;
}
public void OnBeginDrag(PointerEventData eventData){
parentToReturnTo = transform.parent;
index = transform.GetSiblingIndex();
}
public void OnDrag(PointerEventData eventData){
this.transform.position =
Camera.main.ScreenToWorldPoint (
new Vector3(
Mathf.Clamp(eventData.position.x, 0.0f, Screen.width),
Mathf.Clamp(eventData.position.y, 0.0f, Screen.height),
Mathf.Abs(Camera.main.transform.position.z)
)
);
}
public void OnEndDrag(PointerEventData eventData){
this.transform.SetParent( parentToReturnTo );
if (dropzone = GetComponentInParent<DropZone2> ())
dropzone.arrangeChilds ();
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class DropZone2 : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler,IPointerDownHandler, IPointerUpHandler {
public string _validObjectTag; // which kind of object is accepted
public int _size; // nb of elements
public int _maxSize; // max nb of elements
public float radius = 10; // used to place dragged objects
public float offset; // not used
private GameObject dragged; // object currently dragged
private Dragable2 dragable; // ref to draggable2 script
public void arrangeChilds(){ // place childs correctly
updateNbElement ();
if (_size == 0)
return;
else if (_size == 1) {
for (int i = 0; i < _size; ++i) {
Transform child = transform.GetChild(i);
if (child != transform)
child.position = transform.position;
}
} else {
float distance = ((radius + offset) / _size);
float startX = (0 - (radius / 2)) + (distance / 2);
for (int i = 0; i < _size; ++i) {
Transform child = transform.GetChild(i);
if (child != transform) {
child.localPosition = new Vector3 (startX, 0f, 0f);
startX += distance;
}
}
}
setColliderSize ();
}
void updateNbElement (){ // set size accordingly to nb of childs
_size = transform.childCount;
}
void setColliderSize(){ // set collider's size (not finished yet but not really importsnt for now)
GetComponent<BoxCollider2D> ().size = new Vector2 (5.0f, 2.5f);
}
public bool canAdd { // returns true if there's still enough room
get{ return _size < _maxSize; }
}
public void OnPointerEnter (PointerEventData eventData)
{
Debug.Log ("OnPointerEnter : " + name);
if (!canAdd)
return;
if (!(dragged = eventData.pointerDrag.gameObject))
return;
Debug.Log ("OnPointerEnter : " + name + " --> " + (dragged ? dragged.name : "null"));
if (dragged.CompareTag (_validObjectTag))
return;
dragable = dragged.GetComponent<Dragable2>();
if (null == dragable)
return;
dragable.parentToReturnTo = transform;
}
public void OnPointerExit (PointerEventData eventData)
{
Debug.Log ("OnPointerExit : " + name);
if (!canAdd || null == dragged || null == dragable)
return;
Transform tr = dragable.transform.parent;
if (null != tr)
dragable.parentToReturnTo = tr;
dragged = null;
dragable = null;
}
public void OnPointerDown (PointerEventData eventData){
Debug.Log ("OnPointerdown : " + name);
}
public void OnPointerUp (PointerEventData eventData){
Debug.Log ("OnPointerup : " + name);
}
public void OnPointerClick (PointerEventData eventData){
Debug.Log ("OnPointerclick : " + name);
}
}
since the object you’re dragging is over the cursor while being dragged its blocking any Ipointer events that the EventSystem does internally, which it does via raycasts from camera.
EventSystem’s OnDrag doesn’t assume that you are physically dragging an object with the cursor, as there can be some drags that don’t physically move objects. for example one could use dragging as a gesture, or to multi-select units, to link two nodes together, or to command a unit in which direction to face.
in your case when you begin dragging you need to make sure that its no longer blocking raycasts. if its a UI element simplly including a CanvasGroup with the draggable object and setting it to canvasGroup.blocksRaycast = false while dragging will fix that.
If its a physics object (with colliders) save the current gameobject.layer OnBeginDrag. then set gameObject.layer = 2 (sets to ignoreRayCast). then OnEndDrag set the layer index back to the old value you saved from OnBeginDrag
It probably doesn’t fire because whatever you are dragging is blocking the pointer event from triggering.
If you select the EventSystem in your Hierarchy, you can watch the different events to see if it’s triggering those events or not. You may be able to further test this by doing the drag without having the object actually move.
Such a this ? I get the idea but it doesn’t seem to work either. What if i deactivate the collider ?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class DropZone2 : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler,IPointerDownHandler, IPointerUpHandler {
public string _validObjectTag; // which kind of object is accepted
public int _size; // nb of elements
public int _maxSize; // max nb of elements
public float radius = 10; // used to place dragged objects
public float offset; // not used
private GameObject dragged; // object currently dragged
private Dragable2 dragable; // ref to draggable2 script
public void arrangeChilds(){ // place childs correctly
updateNbElement ();
if (_size == 0)
return;
else if (_size == 1) {
for (int i = 0; i < _size; ++i) {
Transform child = transform.GetChild(i);
if (child != transform)
child.position = transform.position;
}
} else {
float distance = ((radius + offset) / _size);
float startX = (0 - (radius / 2)) + (distance / 2);
for (int i = 0; i < _size; ++i) {
Transform child = transform.GetChild(i);
if (child != transform) {
child.localPosition = new Vector3 (startX, 0f, 0f);
startX += distance;
}
}
}
setColliderSize ();
}
void updateNbElement (){ // set size accordingly to nb of childs
_size = transform.childCount;
}
void setColliderSize(){ // set collider's size (not finished yet but not really important for now)
GetComponent<BoxCollider2D> ().size = new Vector2 (5.0f, 2.5f);
}
public bool canAdd { // returns true if there's still enough room
get{ return _size < _maxSize; }
}
public void OnPointerEnter (PointerEventData eventData)
{
Debug.Log ("OnPointerEnter : " + name);
if (!canAdd){
Debug.Log ("can't add");
return;
}
dragged = eventData.pointerDrag.gameObject;
if (null == dragged){
Debug.Log ("dragged is null");
return;
}
if (dragged.CompareTag (_validObjectTag)) {
Debug.Log ("Tag not valid");
return;
}
dragable = dragged.GetComponent<Dragable2>();
if (null == dragable){
Debug.Log ("draggable is null");
return;
}
dragable.parentToReturnTo = transform;
Debug.Log (dragable.parentToReturnTo.name);
}
public void OnPointerExit (PointerEventData eventData)
{
Debug.Log ("OnPointerExit : " + name);
if (!canAdd || null == dragged || null == dragable)
return;
Transform tr = dragable.transform.parent;
if (null != tr)
dragable.parentToReturnTo = tr;
dragged = null;
dragable = null;
}
public void OnPointerDown (PointerEventData eventData){
Debug.Log ("OnPointerdown : " + name);
}
public void OnPointerUp (PointerEventData eventData){
Debug.Log ("OnPointerup : " + name);
}
public void OnPointerClick (PointerEventData eventData){
Debug.Log ("OnPointerclick : " + name);
}
}
EDIT : tried disabling the collider and it doesn’t work either.
EDIT 2 : It seems to work but apparently it doesn’t check the tag properly… I’d still like to know how to do it without disabling the collider.
Does a CanvasGroup work with physics colliders? That’s what I use with the UI. But I’ve never specifically tried to solve this problem with the PhysicsRaycaster.
The other alternative would be to use EventSystem.RaycastAll and generate your own events.
I never said disable the collider, I said change the gameobject’s Layer. Besides, you can’t disable colliders (rather that colliders still work even when disabled) because they are designed to be able to activate objects they are on even when disabled
When the event system checks to see what the cursor is hovering over it actually performs a raycast against objects defined visible by the camera (eg the culling layer) and valid by the Raycaster. by default that should be excluding the ignoreRaycast layer. go your camera and confirm your camera’s culling layers and the Raycaster’s event layers.
it doesn’t have to be ignoreRaycast layer, if you want the dragging object to be colliding/triggering other objects you can just switch the object to a layer thats not seen by the current raycaster, or change which layers the raycaster is allowed to see. doing so should not break the dragging.
Ok i get it ! you can choose which layers are gonna block the rays. I hadn’t unchecked the layer 2 that’s why it didn’t work (i assumed ignoreRaycast was the only layer you could use to ignore the rays) As for the camera no need to hide some layers they all need to be visible. So it seems to work but i have this problem. the comparetag method returns false (even though it matches). I had this problem before when i was following the tutorials on the website and i don’t understand why it does this. What do you think ?
Dragable2 works fine now :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class Dragable2 : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler,IPointerClickHandler {
public Transform parentToReturnTo = null;
public Transform placeholderParent = null;
int index;
DropZone2 dropzone = null;
GameObject placeholder = null;
public void OnPointerClick (PointerEventData eventData)
{
return;
}
public void OnBeginDrag(PointerEventData eventData){
parentToReturnTo = transform.parent;
index = transform.GetSiblingIndex();
index = gameObject.layer;
gameObject.layer = 2;
}
public void OnDrag(PointerEventData eventData){
this.transform.position =
Camera.main.ScreenToWorldPoint (
new Vector3(
Mathf.Clamp(eventData.position.x, 0.0f, Screen.width),
Mathf.Clamp(eventData.position.y, 0.0f, Screen.height),
Mathf.Abs(Camera.main.transform.position.z)
)
);
}
public void OnEndDrag(PointerEventData eventData){
this.transform.SetParent( parentToReturnTo );
gameObject.layer = index;
if (dropzone = GetComponentInParent<DropZone2> ())
dropzone.arrangeChilds ();
}
}
DropZone2 comparetag is on line 75 i tried using “==” too but it doesn’t work either :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class DropZone2 : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler,IPointerDownHandler, IPointerUpHandler {
public string _validObjectTag; // which kind of object is accepted
public int _size; // nb of elements
public int _maxSize; // max nb of elements
public float radius = 10; // used to place dragged objects
public float offset; // not used
private GameObject dragged; // object currently dragged
private Dragable2 dragable; // ref to draggable2 script
public void arrangeChilds(){ // place childs correctly
updateNbElement ();
if (_size == 0)
return;
else if (_size == 1) {
for (int i = 0; i < _size; ++i) {
Transform child = transform.GetChild(i);
if (child != transform)
child.position = transform.position;
}
} else {
float distance = ((radius + offset) / _size);
float startX = (0 - (radius / 2)) + (distance / 2);
for (int i = 0; i < _size; ++i) {
Transform child = transform.GetChild(i);
if (child != transform) {
child.localPosition = new Vector3 (startX, 0f, 0f);
startX += distance;
}
}
}
setColliderSize ();
}
void updateNbElement (){ // set size accordingly to nb of childs
_size = transform.childCount;
}
void setColliderSize(){ // set collider's size (not finished yet but not really important for now)
GetComponent<BoxCollider2D> ().size = new Vector2 (5.0f, 2.5f);
}
public bool canAdd { // returns true if there's still enough room
get{ return _size < _maxSize; }
}
public void OnPointerEnter (PointerEventData eventData)
{
Debug.Log ("OnPointerEnter : " + name);
if (!canAdd){
Debug.Log ("can't add");
return;
}
dragged = eventData.pointerDrag.gameObject;
if (null == dragged){
Debug.Log ("dragged is null");
return;
}
if (dragged.CompareTag(_validObjectTag)) { // validObjectTag is supposed to be already set
Debug.Log ("Tag not valid");
return;
}
dragable = dragged.GetComponent<Dragable2>();
if (null == dragable){
Debug.Log ("draggable is null");
return;
}
dragable.parentToReturnTo = transform;
Debug.Log (dragable.parentToReturnTo.name);
}
public void OnPointerExit (PointerEventData eventData)
{
Debug.Log ("OnPointerExit : " + name);
if (!canAdd || null == dragged || null == dragable)
return;
Transform tr = dragable.transform.parent;
if (null != tr)
dragable.parentToReturnTo = tr;
dragged = null;
dragable = null;
}
public void OnPointerDown (PointerEventData eventData){
Debug.Log ("OnPointerdown : " + name);
}
public void OnPointerUp (PointerEventData eventData){
Debug.Log ("OnPointerup : " + name);
}
public void OnPointerClick (PointerEventData eventData){
Debug.Log ("OnPointerclick : " + name);
}
}
I can’t say why CompareTag isn’t working for you. I don’t know what values you’ve put into the variable and what the tag’s name is. double check that values are trimmed and you are using the proper case. I would also print out in that debug both the dragged.tag and the _validObjectTag as well as the string.length of both.
Then again I never use CompareTag due to its limitations with composition. Using getcomponent and checking if its null should be the best step at validating the dragged objects. Though you can add a property to Dragable2 that onpointerenter can validate against if more specificity is needed.
The thing is they never match (and my objects have their tags set so is validObjectTag) ! And if they match the draggable object is set as a child of the dropzone object it’s as simple as that and it works perfectly without this piece of code. By the way it also quits the function after printing the message (before it sets the object as a child).
EDIT : and the big problem here is that the two string are the same length and are both identical so WHY doesn’t it return true instead of false ?
EDIT 2 : 'cause everything else works fine and it would be nice if my compareTag function worked because imagine if i create a dropZone where i want to drop cards and another where i want to drop chickens (let’s say ^^). That’s why i have a string in my script that’s gonna verify what i can and cannot drop.