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.
Related
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.
How do I create the Zoom-in and Zoom-out feature in Unity-3d using UI button click?
Solution depends on your specific setup, but this should be a good starting point, if you're using an ortographic Camera. If you're using a perspective camera instead, you should move its Transform's position forward or backwards. I'm also using Mathf.Clamp to restrict the zooming level to a specific range.
using UnityEngine;
using UnityEngine.UI;
public class Zoomer: MonoBehaviour
{
public Button zoomInButton;
public Button zoomOutButton;
public float zoomDelta = 0.1f;
public float minZoom;
public float maxZoom;
Camera cam;
void Start()
{
cam = Camera.main;
}
void OnEnable()
{
zoomInButton.onClick.AddListener(delegate { Zoom(-zoomDelta); });
zoomOutButton.onClick.AddListener(delegate { Zoom(zoomDelta); });
}
void Zoom(float value)
{
float v = Mathf.Clamp(
cam.orthographicSize + value,
minZoom,
maxZoom
);
cam.orthographicSize = v;
}
}
I'm building an android game in which the player is controlled using Simple joystick plugin. When I am controlling the player using Keyboard the player animations work but when I control it using the joystick ui button the walk animation does not trigger even when the player is moving.Following are the codes used.
Player movement
using UnityEngine;
using UnityEngine.UI;
namespace CompleteProject
{
public class PlayerMovement : MonoBehaviour
{
public float speed = 6f; // The speed that the player will move at.
public Text teleportText;
public GameObject teleportCanvas;
public GameObject teleOptionCanvas;
Vector3 movement; // The vector to store the direction of the player's movement.
Animator anim; // Reference to the animator component.
Rigidbody playerRigidbody; // Reference to the player's rigidbody.
int floorMask; // A layer mask so that a ray can be cast just at gameobjects on the floor layer.
float camRayLength = 100f; // The length of the ray from the camera into the scene.
void Awake ()
{
// Create a layer mask for the floor layer.
floorMask = LayerMask.GetMask ("Floor");
// Set up references.
anim = GetComponent <Animator> ();
playerRigidbody = GetComponent <Rigidbody> ();
}
void FixedUpdate ()
{
// Store the input axes.
float h = Input.GetAxisRaw ("Horizontal");
float v = Input.GetAxisRaw ("Vertical");
// Move the player around the scene.
Move (h, v);
// Turn the player to face the mouse cursor.
Turning ();
// Animate the player.
Animating (h, v);
}
void Move (float h, float v)
{
// Set the movement vector based on the axis input.
movement.Set (h, 0f, v);
// Normalise the movement vector and make it proportional to the speed per second.
movement = movement.normalized * speed * Time.deltaTime;
// Move the player to it's current position plus the movement.
playerRigidbody.MovePosition (transform.position + movement);
}
void Turning ()
{
// Create a ray from the mouse cursor on screen in the direction of the camera.
Ray camRay = Camera.main.ScreenPointToRay (Input.mousePosition);
// Create a RaycastHit variable to store information about what was hit by the ray.
RaycastHit floorHit;
// Perform the raycast and if it hits something on the floor layer...
if(Physics.Raycast (camRay, out floorHit, camRayLength, floorMask))
{
// Create a vector from the player to the point on the floor the raycast from the mouse hit.
Vector3 playerToMouse = floorHit.point - transform.position;
// Ensure the vector is entirely along the floor plane.
playerToMouse.y = 0f;
// Create a quaternion (rotation) based on looking down the vector from the player to the mouse.
Quaternion newRotation = Quaternion.LookRotation (playerToMouse);
// Set the player's rotation to this new rotation.
playerRigidbody.MoveRotation (newRotation);
}
}
void Animating (float h, float v)
{
// Create a boolean that is true if either of the input axes is non-zero.
bool walking = h != 0f || v != 0f;
// Tell the animator whether or not the player is walking.
anim.SetBool ("IsWalking", walking);
}
void OnTriggerEnter(Collider col)
{
if (col.tag == "Teleport")
{
teleportCanvas.SetActive (true);
if (ScoreManager.score < 200)
teleportText.text = "SORRY!! ATLEAST 200 POINTS REQUIRED";
else if (ScoreManager.score >= 200)
{
teleportText.text = "READY TO GO!!";
teleOptionCanvas.SetActive (true);
}
}
}
void OnTriggerStay(Collider col)
{
if(col.tag == "Teleport")
Time.timeScale = 0.6f;
}
void OnTriggerExit(Collider col)
{
if (col.tag == "Teleport")
{
Time.timeScale = 1f;
teleportCanvas.SetActive (false);
teleOptionCanvas.SetActive (false);
}
}
}
}
Joystick control
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
namespace GeekGame.Input{
public class JoystickMove : MonoBehaviour ,IDragHandler,IEndDragHandler
{
// remember turning is with joystick rotate
// calculate the h and the v, then give it to PlayerMovement
Animator anim;
public static JoystickMove instance=null;
public float _speed=6f;
[Tooltip("the joystick radius ")]
public float R=90f;
private float _r;
private Vector2 centerPos;
private float _h;
private float _v;
public float H{
get{return _h;}
}
public float V{
get{return _v;}
}
void Awake(){
if(instance!=null){
Destroy(this.gameObject);
}else{
instance=this;
}
}
void Start(){
_r=1f*Screen.width/960f*R; //this to calculate the scale of screen
centerPos=GetComponent<RectTransform>().position;
}
void SetHAndF(Vector2 pos){ //Horizontall and Vertical axes
Vector2 diff=pos-centerPos;
float distance=diff.magnitude;
if(distance>_r){
pos=centerPos+diff/distance*_r;
}
GetComponent<RectTransform>().position=pos;
Vector2 move=pos-centerPos;
_h=move.x;
_v=move.y;
}
public void OnDrag(PointerEventData data)
{
Vector2 newPos =new Vector2(data.position.x-20f,data.position.y-20f);
//clamp the sprite
SetHAndF(newPos);
}
public void OnEndDrag(PointerEventData data){
Debug.Log("End Drag"+centerPos);
GetComponent<RectTransform>().position=centerPos;
SetHAndF(centerPos);
}
}
}
Fixed by adding the animating function in Joystickmovement and calling it in update.
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
namespace GeekGame.Input{
public class JoystickMove : MonoBehaviour ,IDragHandler,IEndDragHandler
{
// remember turning is with joystick rotate
// calculate the h and the v, then give it to PlayerMovement
public static JoystickMove instance=null;
public float _speed=6f;
public GameObject player;
public Animator animate;
bool walking;
[Tooltip("the joystick radius ")]
public float R=90f;
private float _r;
private Vector2 centerPos;
private float _h;
private float _v;
public float H{
get{return _h;}
}
public float V{
get{return _v;}
}
void Awake(){
if(instance!=null){
Destroy(this.gameObject);
}else{
instance=this;
}
animate = player.GetComponent<Animator> ();
}
void Start(){
_r=1f*Screen.width/960f*R; //this to calculate the scale of screen
centerPos=GetComponent<RectTransform>().position;
}
void Update()
{
Animating (_h, _v);
}
void SetHAndF(Vector2 pos){ //Horizontall and Vertical axes
Vector2 diff=pos-centerPos;
float distance=diff.magnitude;
if(distance>_r){
pos=centerPos+diff/distance*_r;
}
GetComponent<RectTransform>().position=pos;
Vector2 move=pos-centerPos;
_h=move.x;
_v=move.y;
}
public void OnDrag(PointerEventData data)
{
Vector2 newPos =new Vector2(data.position.x-20f,data.position.y-20f);
//clamp the sprite
SetHAndF(newPos);
Animating (_h, _v);
}
public void OnEndDrag(PointerEventData data){
Debug.Log("End Drag"+centerPos);
GetComponent<RectTransform>().position=centerPos;
SetHAndF(centerPos);
}
void Animating (float h, float v)
{
// Create a boolean that is true if either of the input axes is non-zero.
bool walking = h != 0f || v != 0f;
// Tell the animator whether or not the player is walking.
animate.SetBool ("IsWalking", walking);
}
}
}
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.