- Home /
Input.MousePosition creating weird Z axis object translation
Hello All! I have been messing around with getting an object to follow my mouse position on mouse down. I have this working alongside input.touch as well, but for the sake for debugging, I would like to be able to use the mouse as well to check values when playing to ensure it is working as desired. There is a really odd thing that happens when I use the code below that I can't put my finger on. When i click on the object, it moves correctly in the x and y axis, but for some reason it jumps forward a specific number (~9.7) in the z. I have went over my code and I can't find anything that would influence the object in the z axis....and I'm about to go insane :-)
I really appreciate anybody who takes the time out to scan the code below to find any possible reasons why an object would be translated in the Z. Thank you very much in advance!
attached to main camera
sing System.Security.Cryptography.X509Certificates;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class TouchManager : MonoBehaviour
{
public LayerMask touchInputMask;
private RaycastHit hit;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update ()
{
#if UNITY_EDITOR
if (Input.GetMouseButton(0) || Input.GetMouseButtonUp(0) || Input.GetMouseButtonDown(0))
{
Ray ray = camera.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, touchInputMask)) //if the raycast hits an objects collider within the layermask
{
GameObject recipient = hit.transform.gameObject;
if (Input.GetMouseButtonDown(0)) //if a finger has just been put down on the object
{
//mark the object as selected
//set position of object to touch.position
Debug.Log("Get Mouse Button Down called!!");
float distance_to_screen = Camera.main.WorldToScreenPoint(gameObject.transform.position).z;
Vector3 position = camera.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0 ));
hit.transform.position = position;
//recipient.SendMessage("OnTouchDown", position, SendMessageOptions.DontRequireReceiver);
}
/*if (Input.GetMouseButtonUp(0)) //if a finger has just been put down on the object
{
//mark the object as not selected
//make sure the object continues in the direction it was headed at the same speed when the finger is lifted off the screen
recipient.SendMessage("OnTouchUp", SendMessageOptions.DontRequireReceiver);
}
if (Input.GetMouseButton(0)) //if a finger has just been put down on the object
{
recipient.SendMessage("OnTouchStay", Input.mousePosition, SendMessageOptions.DontRequireReceiver);
}*/
}
}
#endif
if (Input.touchCount > 0)
{
foreach (Touch touch in Input.touches) //for every screen touch to the screen
{
Ray ray = Camera.main.ScreenPointToRay(touch.position);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, touchInputMask)) //if the raycast hits an objects collider within the layermask
{
GameObject recipient = hit.transform.gameObject;
if (touch.phase == TouchPhase.Began) //if a finger has just been put down on the object
{
//mark the object as selected
//set position of object to touch.position
recipient.SendMessage("OnTouchDown", hit.point, SendMessageOptions.DontRequireReceiver);
}
if (touch.phase == TouchPhase.Moved) //if a finger has just been put down on the object
{
//mark the object as selected
//move the object by touch.DeltaPosition
recipient.SendMessage("OnTouchMoved", hit.point, SendMessageOptions.DontRequireReceiver);
}
if (touch.phase == TouchPhase.Ended) //if a finger has just been put down on the object
{
//mark the object as not selected
//make sure the object continues in the direction it was headed at the same speed when the finger is lifted off the screen
//float speed = touch.deltaPosition.magnitude/touch.deltaTime;
recipient.SendMessage("OnTouchUp", touch.deltaPosition, SendMessageOptions.DontRequireReceiver);
}
if (touch.phase == TouchPhase.Canceled) //if a finger has just been put down on the object
{
//mark the object as not selected
//make sure the object continues in the direction it was headed at the same speed when the finger is lifted off the screen
}
}
}
}
}
}
Attached to Object
using System;
using UnityEngine;
using System.Collections;
public class Movement : MonoBehaviour
{
// Use this for initialization
public float defaultSpeed;
public float currentSpeed; //change to private once testing is completed.
public bool selected = false; //change to false when testing is completed.
public GroundController groundController;
private void Awake()
{
CheckIsSlow();
groundController = GetComponent<GroundController>();
}
private void Update()
{
if (!selected)
{
transform.Translate(0.0f, -currentSpeed*Time.deltaTime, 0.0f, Space.World);
}
}
private void CheckIsSlow()
{
Debug.Log("CheckIsSlow Called");
if (EventManager.isSlow)
{
Debug.Log("Event Manager Is Slow enabled");
currentSpeed = EventManager.slowModifier;
}
else
{
Debug.Log("Event Manager Is Slow is not enabled");
currentSpeed = defaultSpeed;
}
}
private void OnCollisionEnter(Collision otherObject)
{
if (otherObject.gameObject.tag == "floor")
{
currentSpeed = 0;
rigidbody.isKinematic = true;
groundController.SetToGround();
}
else if (otherObject.gameObject.tag == "orb" || otherObject.gameObject.tag == "powerup")
{
if (otherObject.gameObject.GetComponent<GroundController>().isGrounded)
{
currentSpeed = 0;
rigidbody.isKinematic = true;
groundController.SetToGround();
}
}
}
private void OnTouchDown(Vector3 position)
{
selected = true;
gameObject.transform.position = new Vector3(position.x, position.y, 0);
}
private void OnTouchStay(Vector3 position)
{
selected = true;
gameObject.transform.position = new Vector3(position.x, position.y, 0);
}
private void OnTouchMoved(Vector3 position)
{
selected = true;
gameObject.transform.position = new Vector3(position.x, position.y, 0);
}
private void OnTouchUp(Vector3 force)
{
//newSpeed = currentSpeed;
rigidbody.AddForce(force.x, force.y, 0);
selected = false;
}
}
There is some code that is commented out, but I was back tracking from getting an object to move with the same speed and in the same direction after touchpase.ended or mouseup, but that is a completely separate beast.
Again, I really appreciate any amount of time that you take to help me out :-)
Thanks,
A brain fried coder
Answer by robertbu · Apr 28, 2014 at 12:01 AM
Your problem is likely on this line:
Vector3 position = camera.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0 ));
The 'z' parameter of a Vector3 passed to ScreenToWorldPoint() needs to be set to the distance in front of the camera. You are setting the value to 0, so your world position is coming back as the position of the camera or the near clip plane. I'm assuming you have an Orthographic camera, or this code would not work at all.
A quick solution is to insert at line 43:
position.z = hit.transform.position;
Note the use of ScreenToWorldPoint() like you have here assumes the camera has a rotation of (0,0,0).
robertbu and Jeff,
I took the advice of both of you.
Robertbu, I had it set to the position of hit.z before and it continued to jump forward in the z, always that same 9.297 number. I did put it back to that though because that just makes sense and ensures that no matter where it is, it will never move in the z.
Jeff, I have no idea why hit.transform.position = position;
was in there at all. I took it out.
I changed the code a bit, but the only difference is that my Touch$$anonymous$$anager uses Send$$anonymous$$essage to call the function OnTouchDown on the object to move its position and mark it as selected.
Touch$$anonymous$$anager Code:
#if UNITY_EDITOR
if (Input.Get$$anonymous$$ouseButton(0) || Input.Get$$anonymous$$ouseButtonUp(0) || Input.Get$$anonymous$$ouseButtonDown(0))
{
Ray ray = camera.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, touchInput$$anonymous$$ask)) //if the raycast hits an objects collider within the layermask
{
GameObject recipient = hit.transform.gameObject;
if (Input.Get$$anonymous$$ouseButtonDown(0)) //if a finger has just been put down on the object
{
//mark the object as selected
//set position of object to touch.position
Debug.Log("Get $$anonymous$$ouse Button Down called!!");
float distance_to_screen = Camera.main.WorldToScreenPoint(gameObject.transform.position).z;
Vector3 position = camera.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y,recipient.transform.position.z));
recipient.Send$$anonymous$$essage("OnTouchDown", position, Send$$anonymous$$essageOptions.DontRequireReceiver);
}
$$anonymous$$ovement Code on Object: public class $$anonymous$$ovement : $$anonymous$$onoBehaviour {
// Use this for initialization
public float defaultSpeed;
public float currentSpeed; //change to private once testing is completed.
public bool selected = false; //change to false when testing is completed.
public GroundController groundController;
private void Awake()
{
CheckIsSlow();
groundController = GetComponent<GroundController>();
}
private void Update()
{
if (!selected)
{
transform.Translate(0.0f, -currentSpeed*Time.deltaTime, 0.0f, Space.World);
}
}
private void CheckIsSlow()
{
Debug.Log("CheckIsSlow Called");
if (Event$$anonymous$$anager.isSlow)
{
Debug.Log("Event $$anonymous$$anager Is Slow enabled");
currentSpeed = Event$$anonymous$$anager.slow$$anonymous$$odifier;
}
else
{
Debug.Log("Event $$anonymous$$anager Is Slow is not enabled");
currentSpeed = defaultSpeed;
}
}
private void OnCollisionEnter(Collision otherObject)
{
if (otherObject.gameObject.tag == "floor")
{
currentSpeed = 0;
rigidbody.is$$anonymous$$inematic = true;
groundController.SetToGround();
}
else if (otherObject.gameObject.tag == "orb" || otherObject.gameObject.tag == "powerup")
{
if (otherObject.gameObject.GetComponent<GroundController>().isGrounded)
{
currentSpeed = 0;
rigidbody.is$$anonymous$$inematic = true;
groundController.SetToGround();
}
}
}
private void OnTouchDown(Vector3 position)
{
selected = true;
gameObject.transform.position = new Vector3(position.x, position.y,position.z);
}
Thanks again!
You still have the same problem.
You are setting your object's Z to the Z position of the mouse click on the screen.
Don't do that.
$$anonymous$$eep its current Z.
Eg this...
private void OnTouchDown(Vector3 position)
{
selected = true;
gameObject.transform.position = new Vector3(position.x, position.y,position.z);
}
Should be this:
private void OnTouchDown(Vector3 position)
{
selected = true;
position.z = gameObject.Transform.position.z;
gameObject.transform.position = new Vector3(position.x, position.y,position.z);
}
So, to do that in the code have able would look like this more or less.
Note that there are more efficient ways to organize this but not without changing the OPs code structure.
He should NOT transform the mouse position to world coords in the sender, but pass it straight to this code in screen coords.
private void OnTouchDown(Vector3 mousePos)
{
selected = true;
Vector3 objInScreenSpace =
camera.WorldToScreenPoint(gameObject.transform.position);
gameObject.transform.position =
camera.ScreenToWorldPoint(new Vector3(mousePos.x, mousePos.y,
` objInScreenSpace.z);
}
Sure,
So, in this case we are having to transform the object's position to screen space to get the Z every time we call this. But if what if you are looking for is a drag or drag like effect, then by definition the Z isn't going to change through multiple moves.
So, we could cache the transformed point "objInScreenSpace" to a global. . The trick is to know when the Z has changed. If its a drag we can cache it until drag end, If its a series of taps then its trickier, but you could also save the untransformed Z of the object and only recalculate when that Z changes, if that makes sense.
For the first version, this guy does a good job with his code;
http://answers.unity3d.com/questions/12322/drag-gameobject-with-mouse.html
enter code hereusing UnityEngine;
using System.Collections;
[RequireComponent(typeof($$anonymous$$eshCollider))]
public class GizmosController : $$anonymous$$onoBehaviour
{
private Vector3 screenPoint;
private Vector3 offset;
void On$$anonymous$$ouseDown()
{
screenPoint = Camera.main.WorldToScreenPoint(gameObject.transform.position);
offset = gameObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z));
}
void On$$anonymous$$ouseDrag()
{
Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z);
Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) +offset;
transform.position = curPosition;
}
}
For the latter, I can write you a code patch when i have a few more $$anonymous$$utes then right now...
Answer by Jeff-Kesselman · Apr 27, 2014 at 11:58 PM
What are you trying to accomplish? This looks very strange...
Vector3 position = camera.ScreenToWorldPoint(
new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0 ));
hit.transform.position = position;
What this code seems to be trying to do is move the clicked object to be on the plane of the screen. What you probably want is:
Vector3 position =
camera.ScreenToWorldPoint(
new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0 ));
position.z = hit.transform.z;
hit.transform.position = position;
Hey Jeff! I responded to you as well in my post to rebertbu below. Thanks for pointing that out.
@Jeff $$anonymous$$esselman deserves the credit for answering this one. He went beyond the editor specific code to take a look at the whole problem. Thumbs up Jeff.
Your answer
Follow this Question
Related Questions
Prefab teleporting on play mode ? 0 Answers
How can I Instantiate a prefab (projectile) consistently from the character? 0 Answers
Moving object with transform.position ignore other objects even if they collided 1 Answer
Need enemy to follow only active character 0 Answers
Drawing a (debug) line between anchored UI element and mouse? 0 Answers