Unity3D OnDrag move 3D object doesn't follow pointer - c#

I'm new to the concept of transforming screen coordinates to world coordinates in a 3D world in general, even more so in Unity. I'm using the UnityEngine.EventSystems library, implementing the IDragHandler, as I want this to work the same no matter if a mouse or touch input is the source.
I want to drag around a 3D object in world space, locked to one z position. I found this excellent piece of code which I'm now using:
http://coffeebreakcodes.com/drag-object-with-mouse-unity3d/
That same code can also be found in the answer here: Drag 3d object using fingers in unity3d
It works exactly as I want it to, apart from one thing: The transformation works fine when the drag starts, but the object makes larger movements than the pointer does, getting worse the further from the object's original position it gets, as if the movement is multiplied with something that gets larger the further away from the original position I get.
This is my code, which is basically the same as in the link above, apart from using the PointerEventData's pointer coordinates instead of Input.mousePosition (a change that did not affect the behaviour):
public class DragInput : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
private Vector3 screenPoint;
private Vector3 offset;
public void OnBeginDrag(PointerEventData eventData)
{
screenPoint = Camera.main.WorldToScreenPoint(transform.position);
offset = transform.position - Camera.main.ScreenToWorldPoint(new Vector3(eventData.position.x, eventData.position.y, screenPoint.z));
}
public void OnDrag(PointerEventData eventData)
{
Vector3 cursorPoint = new Vector3(eventData.position.x, eventData.position.y, screenPoint.z);
Vector3 cursorPosition = Camera.main.ScreenToWorldPoint(cursorPoint) + offset;
transform.position = cursorPosition;
}
public void OnEndDrag(PointerEventData eventData)
{
}
}
EDIT: This video clip showcases the behaviour I'm describing: https://www.dropbox.com/s/qfx2p6kznizft1q/Unity%202017-01-13%2014-32-15-89.avi?dl=0

This is a perspective problem when dragging around 3D Object.
You need a make a Plane, covert the mouse position(screen pixels) to ray then check where they both intersect.
using UnityEngine;
using UnityEngine.EventSystems;
public class DragInput : MonoBehaviour, IPointerDownHandler, IDragHandler, IEndDragHandler
{
Camera mainCamera;
float zAxis = 0;
Vector3 clickOffset = Vector3.zero;
// Use this for initialization
void Start()
{
mainCamera = Camera.main;
zAxis = transform.position.z;
}
public void OnPointerDown(PointerEventData eventData)
{
clickOffset = transform.position - mainCamera.ScreenPointToWoldOnPlane(eventData.position, zAxis);
}
public void OnDrag(PointerEventData eventData)
{
transform.position = mainCamera.ScreenPointToWoldOnPlane(eventData.position, zAxis) + clickOffset;
}
public void OnEndDrag(PointerEventData eventData)
{
}
}
public static class extensionMethod
{
public static Vector3 ScreenPointToWoldOnPlane(this Camera cam, Vector3 screenPosition, float zPos)
{
float enterDist;
Plane plane = new Plane(Vector3.forward, new Vector3(0, 0, zPos));
Ray rayCast = cam.ScreenPointToRay(screenPosition);
plane.Raycast(rayCast, out enterDist);
return rayCast.GetPoint(enterDist);
}
}

The cause of the problem I posted for, was due to me having forgotten a PhysicsRaycaster on the MainCamera. I had a GraphicsRaycaster on a Canvas, but no PhysicsRaycaster present - I think that might have caused odd behaviours.
However, my code as it is has problems with the other desired behaviour I described, moving the object in a fixed distance to the camera. See #Programmer's answer to see how to fix that.
Their code is however not what solved the issue that was the purpose of this post, hence their answer not being the accepted answer.

Take a look at this snippet:
pos = Camera.main.ScreenToWorldPoint (Vector3 (Input.GetTouch(0).position.x,Input.GetTouch(0).position.y, 5));
transform.position = new Vector3(pos.x, pos.y, pos.z);
or else you can try this class, if this isn't working, I'm out of options :)
using UnityEngine;
using System.Collections;
public class DragObject : MonoBehaviour {
private float dist;
private Vector3 v3Offset;
private Plane plane;
private bool ObjectMouseDown = false;
public GameObject linkedObject;
void OnMouseDown() {
plane.SetNormalAndPosition(Camera.main.transform.forward, transform.position);
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
float dist;
plane.Raycast (ray, out dist);
v3Offset = transform.position - ray.GetPoint (dist);
ObjectMouseDown = true;
}
void OnMouseDrag() {
if (ObjectMouseDown == true){
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
float dist;
plane.Raycast (ray, out dist);
Vector3 v3Pos = ray.GetPoint (dist);
v3Pos.z = gameObject.transform.position.z;
v3Offset.z = 0;
transform.position = v3Pos + v3Offset;
if (linkedObject != null){
linkedObject.transform.position = v3Pos + v3Offset;
}
}
}
void OnMouseOut() {
ObjectMouseDown = false;
}
}

Related

The CineMachine Camera ruin the 2d parallax Effect because its shaking

I am working in a 2d platform game I applied cinemachine camera and parallax script to give a good effect ,but the parallax is shaking and vibrating hard , I found out that the cinamchine was the reason because the camera it shaking, when I disabled the cinemachine it work smoothly
here is the parallax code
private float startpos;
private GameObject cam;
[SerializeField] private float parallax;
[SerializeField] private float speed = 0.1f;
// Start is called before the first frame update
void Start()
{
cam = GameObject.Find("Main Camera");
startpos = transform.position.x;
}
// Update is called once per frame
void Update()
{
float distance = (cam.transform.position.x * parallax);
transform.position = new Vector3(startpos + distance, transform.position.y, transform.position.z);
}
and the settings of the MC vcam1
enter image description here
please any help I dont find any on with that problem
You could try setting the CinemachineBrain update method to Manual Update and then just calling ManualUpdate() in another script.
using UnityEngine;
using Cinemachine;
public class ManualBrainUpdate : MonoBehaviour
{
public CinemachineBrain cineBrain;
public float smoothTime;
private void Start()
{
cineBrain = GetComponent<CinemachineBrain>();
}
void Update()
{
cineBrain.ManualUpdate();
}
}
To avoid any kind of jitter in Unity (like what the camera is adding to distance when it shakes) use the various SmoothDamp functions e.g. https://docs.unity3d.com/ScriptReference/Vector3.SmoothDamp.html:
public float smoothTime = 0.3f; // adjust this to taste
private float distance;
private Vector3 velocity = Vector3.zero;
private Vector3 targetPos
void Update()
{
distance = cam.transform.position.x * parallax;
targetPos = new Vector3(startpos + distance, transform.position.y, transform.position.z)
transform.position = Vector3.SmoothDamp(transform.position, targetPos, ref velocity, smoothTime);
}

How to shoot ball to Touch X position Unity 3D?

I have a ball on a ground, and when touching the screen I want to shoot it to the X position of the Touch. Do you have any suggestions?
This is the code I have so far:
public Rigidbody Ball;
public float Speed = 50f;
void FixedUpdate () {
if(ClickDone == false){
if (Input.GetMouseButton(0)){
ClickDone = true;
Ball.velocity = transform.forward * Speed;
}
}
}
here is your new code :
using UnityEngine;
public class GoToTouch : MonoBehaviour
{
public Camera cam;//put your main camera here
public float speed;//Speed of movement
Vector3 LastTouch;
void Start()
{
LastTouch = Vector3.zero;
}
void Update()
{
//We check for new touches etch frame
if (Input.touchCount> 0)
LastTouch = Input.touches[0].rawPosition;
//We move towards the last touch
if(LastTouch != Vector3.zero)transform.position=
Vector3.Lerp(transform.position,cam.ScreenToWorldPoint(LastTouch),speed*Time.DeltaTime);
}
}
what is important for you to look at is the
ScreenToWorldPoint function LastTouch holds the actual pixel the user touched
after ScreenToWorldPoint you get the position that the pixel he touched represent in the
world. Good luck learning !

Unity3d - Drag and Drop object on RTS camera

I have this code to drag and drop 3d objects on a world:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpyAI : MonoBehaviour {
Animator anim;
private Vector3 screenPoint;
private Vector3 offset;
// Use this for initialization
void Start () {
anim = gameObject.GetComponent<Animator>();
}
// Update is called once per frame
void Update () {
}
void OnMouseDown()
{
anim.SetBool("drag", true);
screenPoint = Camera.main.WorldToScreenPoint(transform.position);
offset = transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z));
}
void OnMouseDrag()
{
Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z);
Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + offset;
transform.position = curPosition;
}
void OnMouseUp()
{
anim.SetBool("drag", false);
anim.SetBool("idle", true);
}
}
The problem is:
When im dragging the object, sometimes, depending on the mouse movement it goes undergound
How can I make the object to stay above the ground while dragging it?
The most obvious thing that should change is the z-value of curScreenPoint. Using the docs as reference, it should probably be:
Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, Camera.main.nearClipPlane);
Now for maybe a bit more fine-tuned behavior, you might want to make the object raise up above the ground if the ground has slopes or something with complex colliders on it like a chair or table. To do this, you likely want to do a sphere cast down towards the ground from a point somewhat above what's calculated in curPosition. Use the hitInfo to see how far down it goes, and adjust the y position of curPosition accordingly.

Unity3D NavMashAgent not moving -C# Code

I don't know this is a right place to ask this. Because this is a Game development ralated question. I post this question in here (gamedev.stackexchange.com -https://gamedev.stackexchange.com/questions/109190/navmashagent-not-moving) but still no responce. And also post thin in Unity forum (http://answers.unity3d.com/questions/1075904/navmashagent-not-moving-in-unity3d-5.html). Any one here to help me.
Ill post my question here again
Im trying to move a Cube to CheckPoints. FindClosestTarget() method gives closest Checkpoint. When Cube hit the CheckPoint, ChackPoint will be Set as Inactive. When the Collision happens FindClosestTarget() call again and get the new closest CheckPoint. Thing is Cube not moving. It Look at the closest check point but not moving.
using UnityEngine;
using System.Collections;
public class EnimyAI03N : MonoBehaviour {
NavMeshAgent agent;
Transform Target;
private float rotationSpeed=15.0f;
void Start () {
agent = GetComponent<NavMeshAgent>();
Target = FindClosestTarget ().transform;
}
void Update ()
{
LookAt (Target);
MoveTo (Target);
}
// Turn to face the player.
void LookAt (Transform T){
// Rotate to look at player.
Quaternion rotation= Quaternion.LookRotation(T.position - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime*rotationSpeed);
//transform.LookAt(Target); alternate way to track player replaces both lines above.
}
void MoveTo (Transform T){
agent.SetDestination(T.position);
}
void OnCollisionEnter (Collision col)
{
if(col.gameObject.name.Contains("CheckPoint"))
{
Target = FindClosestTarget ().transform;
}
}
GameObject FindClosestTarget() {
GameObject[] gos;
gos = GameObject.FindGameObjectsWithTag("CheckPoint");
GameObject closest=null;
float distance = Mathf.Infinity;
Vector3 position = transform.position;
foreach (GameObject go in gos) {
Vector3 diff = go.transform.position - position;
float curDistance = diff.sqrMagnitude;
if (curDistance < distance) {
closest = go;
distance = curDistance;
}
}
return closest;
}
}
Make sure the SetActive(false); is happening before you search for the new target, by just putting both lines in the same area.
void OnCollisionEnter (Collision col)
{
if(col.gameObject.name.Contains("CheckPoint"))
{
col.gameObject.SetActive(false);
Target = FindClosestTarget ().transform;
}
}

Unity calculate 3D Mouse position

I'm trying to make a C# script for a free throw ball game and need to get the mouse position in the world, and it should be in 3D to be able to throw in all 3 axes. I'm kinda new to scripting and the script I wrote works, but not right. I am not sure how to get the depth or the y axis working, because the screen is only 2d .
using UnityEngine;
using System.Collections;
public class ShootBall : MonoBehaviour {
private Rigidbody rb;
private RaycastHit hit;
private Vector3 com;
private Vector3 shootDirection;
void Start () {
rb = GetComponent<Rigidbody>();
}
void Update () {
}
void OnMouseDown (){
com = rb.worldCenterOfMass;
Debug.Log (com);
}
void OnMouseDrag (){
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Debug.Log(ray);
Physics.Raycast(ray, out hit);
}
void OnMouseUp (){
shootDirection = com - hit.point;
rb.AddForce (shootDirection * 100);
}
}
The distance from the camera needs to be set on the z-value of the vector being passed into ScreenPointToRay. The reason why Input.mousePosition works as a parameter for ScreenPointToRay is because Vector2 can be implicitly cast to Vector3. So try doing something like this:
float distanceFromCamera = Vector3.Distance(ballGameObject.transform.position, Camera.main.transform.position);
Vector3 inputPosition = new Vector3(Input.mousePosition.x, Input.mousePosition.y, distanceFromCamera);
Ray ray = Camera.main.ScreenPointToRay(inputPosition);
ballGameObject is the gameObject reference to the ball that will be thrown.

Categories