Unity3D UI, calculation for position dragging an item?
For Draging stuff I just do this :
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");
}
}
Here's the identical amazing URIPOPOV CODE with two simple features which you always need when dragging:
// allow dragging with two basic problem fixes:
// - limit drag to the parent box
// - don't "jump" based on where you hold down
100% tested:
Note that you MUST USE the scale conversion code from #programmer below.
using UnityEngine;
using UnityEngine.EventSystems;
public class AmazingUPDrag : MonoBehaviour,
IBeginDragHandler, IDragHandler, IEndDragHandler
{
RectTransform rt;
Vector2 dragOffset = Vector2.zero;
Vector2 limits = Vector2.zero;
Canvas canvas;
void Awake()
{
rt = GetComponent<RectTransform>();
canvas = GetComponentInParent<Canvas>();
}
public void OnBeginDrag(PointerEventData eventData)
{
dragOffset = ActualPos(eventData.position) - (Vector2)transform.position;
limits = transform.parent.GetComponent<RectTransform>().rect.max;
limits.x = limits.x - 100f;
limits.y = limits.y - 100f;
}
public void OnDrag(PointerEventData eventData)
{
transform.position = ActualPos(eventData.position) - dragOffset;
var p = transform.localPosition;
if (p.x < -limits.x) { p.x = -limits.x; }
if (p.x > limits.x) { p.x = limits.x; }
if (p.y < -limits.y) { p.y = -limits.y; }
if (p.y > limits.y) { p.y = limits.y; }
transform.localPosition = p;
}
public void OnEndDrag(PointerEventData eventData)
{
dragOffset = Vector2.zero;
}
Vector2 ActualPos(Vector2 unityDelusionPos)
{
Vector2 p;
RectTransformUtility.ScreenPointToLocalPointInRectangle(
(RectTransform)(canvas.transform),
unityDelusionPos,
canvas.worldCamera,
out p);
return canvas.transform.TransformPoint(p);
}
}
Unity drag and drop in world positions
So after a bit of playing around and inspecting the various values I was receiving from the calls to ScreenToWorldPoint I finally tracked down the issue.
In the code for my second attempted approach I found that I was using an incorrect value for the Z argument in ScreenToWorldPoint. After doing a bit of research I found that his should be the Z distance between the camera and the (i guess) touch surface.
Vector3 screenCenter = new Vector3(Screen.width * 0.5f, Screen.height * 0.5f, -Camera.main.transform.position.z);
Vector3 screenTouch = screenCenter + new Vector3(eventData.delta.x, eventData.delta.y, 0);
Thanks to everyone who took the time to read through my question.
Dragging Item With Icon Following Pointer Unity C#
Very fortunately, there is now an
incredibly simple way
to do this in Unity.
Here it is: https://stackoverflow.com/a/37473953/294884
Ask if you have more trouble!
How to make Unity UI object draggable when the objects are instantiating at runtime?
At the time you Instantiate your GameObject obj, do:
obj.addComponent("YourScript");
where YourScript is your script, which you have written, that attached to a GameObjects makes it draggable..
Alternatively, you instantiate a prefab, attach the script to the prefab through the editor.
This is preferrable because addComponent() will get deprecated in the next versions.
I also recommend to keep a List<YourInstantiatedObjectType>
in the parent.
Unity drag doesn't work, object moves away from the pointer
It's better to use Screen Space - Overlay
if the camera's viewport is unchanged. Then following code will work:
this.transform.position = eventData.position;
To use Screen Space - Camera
, you need transform the event position into the camera space:
Vector3 position = eventData.position;
var canvas = image.canvas;
position.z = canvas.planeDistance;
image.transform.position = canvas.worldCamera.ScreenToWorldPoint(position);
drag and drop in unity, drag behind other UI elements
Try adding a "Canvas" component to your prefab and check "override sorting" and set sort order. I think I also had to add a graphic raycaster.
Inspector:
Unity - How to calculate new position for an object from pitch of another object in 3D
Hotspots
If you'd like to place something at a particular location on a generic object which can be scaled or transformed anywhere, then a "hotspot" can be particularly useful.
What's a hotspot?
Edit the target gameobject (the line in this case) and add an empty gameobject to it. Give it some appropriate name - "cross arms hotspot" for example, and then move it to the location where you'd like your other gameobject to target. Essentially, a hotspot is just an empty gameobject - a placement marker of sorts.
How do I use it?
All you need is a reference to the hotspot gameobject. You could do this by adding a little script to the pole gameobject which tracks it for you:
public class PowerPole : MonoBehaviour {
public GameObject CrossArmsHotspot; // Set this in the inspector
}
Then you can get that hotspot reference from any power pole instance like this:
var targetHotspot = aPowerPoleGameObject.GetComponent<PowerPole>().CrossArmsHotspot;
Then it's just a case of getting your target object to place itself where that hotspot is, using whichever technique you prefer. If you want it to just "stick" there, then:
void Start(){
targetHotspot = aPowerPoleGameObject.GetComponent<PowerPole>().CrossArmsHotspot;
}
void Update(){
transform.position = targetHotspot.transform.position;
}
would be a (simplfied) example.
A more advanced example using lerp to move towards the hotspot:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CrossArmsMover : MonoBehaviour
{
public GameObject PowerPole;
private GameObject targetHotspot;
public GameObject CrossArms;
public float TimeToTake = 5f;
private float timeSoFar;
private Vector3 startPosition;
private Quaternion startRotation;
// Start is called before the first frame update
void Start()
{
startPosition = CrossArms.transform.position;
startRotation = CrossArms.transform.rotation;
targetHotspot = PowerPole.GetComponent<PowerPole>().CrossArmsHotspot;
}
// Update is called once per frame
void Update()
{
timeSoFar+=Time.deltaTime;
var progress = timeSoFar/TimeToTake;
// Clamp it so it doesn't go above 1.
if(progress > 1f){
progress = 1f;
}
// Target position / rotation is..
var targetPosition = targetHotspot.transform.position;
var targetRotation = targetHotspot.transform.rotation;
// Lerp towards that target transform:
CrossArms.transform.position = Vector3.Lerp(startPosition, targetPosition, progress);
CrossArms.transform.rotation = Quaternion.Lerp(startRotation, targetRotation, progress);
}
}
Related Topics
How to Programmatically List All Projects in a Solution
Equivalent Code of Createobject in C#
Return Only Digits 0-9 from a String
"The Linq Expression Node Type 'Invoke' Is Not Supported in Linq to Entities" - Stumped!
Will Using Linq to SQL Help Prevent SQL Injection
Mapping Database Views to Ef 5.0 Code First W/Migrations
How to Read Image Pixels' Values as Rgb into 2D Array
Async/Await Keywords Not Available in .Net 4.0
File Write Permission Issue Under "Program Files" Folder
Exceptions That Can't Be Caught by Try-Catch Block in Application Code
How to Print PDF on Default Network Printer Using Ghostscript (Gswin32C.Exe) Shell Command
Exporting Datagridview to CSV File
Is There a Synchronization Class That Guarantee Fifo Order in C#
How to Enable Nullable Reference Types Feature of C# 8.0 for the Whole Project