Search Unity

  1. Unity 2018.3 is now released.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. Want more efficiency in your development work? Sign up to receive weekly tech and creative know-how from Unity experts.
    Dismiss Notice
  4. Build games and experiences that can load instantly and without install. Explore the Project Tiny Preview today!
    Dismiss Notice
  5. Want to provide direct feedback to the Unity team? Join the Unity Advisory Panel.
    Dismiss Notice
  6. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice

[SOLVED] Moving GameObject along X and Z Axis by drag and drop using X and Y from ScreenSpace

Discussion in 'Scripting' started by Nothilvien, Aug 16, 2017.

  1. Nothilvien


    Jun 11, 2013

    I have a 3d space, with a camera that can have different angles to view at a plane.
    Now I want to be able to drag and drop a game object on the X- and Z-axis on the plane, with the y-axis (height) being locked, so that it looks like I move a chess piece on a board.

    Currently my game object starts to fly, but when locking the Y-axis the mouse is faster than the game object.

    What I want is what you can see in this example:

    I have searched this forum and stack overflow but I could not find a working example or an Idea how to make that happen.

    This post describes my problem, that my mouse is not staying on the object when moving my mouse on the y-axis(screen space), it moves faster than my object on the Z-axis (in world space)

    When the camera looks 90degree downwards on the plane, the translation is correct, so I assume I need to take the angle in account to calculate the correct z value in world space to align with my mouse position? Or a way to know the Z position where I want my object to drag to, but also not sure how to retrieve that.

    Is there any Idea how I could accomplish this?

    This is the current code I use with the Y-axis being locked to the dragging object

    Code (CSharp):
    2. private GameObject _drag;
    3. private Vector3 screenPosition;
    4. private Vector3 offset;
    6. private void Update()
    7.         {
    8.             if (_drag == null && Input.GetMouseButtonDown(0))
    9.             {
    10.                 RaycastHit hit;
    11.                 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    12.                 if (Physics.Raycast(ray, out hit, 100.0f))
    13.                 {
    14.                     if (gameObject == hit.transform.gameObject)
    15.                     {
    16.                         _drag = hit.transform.gameObject;
    17.                         screenPosition = Camera.main.WorldToScreenPoint(_drag.transform.position);
    18.                         offset = _drag.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPosition.z));
    19.                     }
    20.                 }
    21.             }
    23.             if (Input.GetMouseButtonUp(0))
    24.             {
    25.                 _drag = null;
    26.             }
    28.             if (_drag != null)
    29.             {
    30.                 Vector3 currentScreenSpace = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPosition.z);
    31.                 Vector3 currentPosition = Camera.main.ScreenToWorldPoint(currentScreenSpace) + offset;
    32.                 _drag.transform.position = new Vector3(currentPosition.x, _drag.transform.position.y, currentPosition.z);
    33.             }
    34.         }
    Last edited: Aug 16, 2017
  2. jeffreyschoch


    Jan 21, 2015
    Maybe something like this could work for you.
    Code (CSharp):
    1. float planeY = 0;
    2. Transform draggingObject = transform;
    4. Plane plane = new Plane(Vector3.up, Vector3.up * planeY); // ground plane
    6. Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    8. float distance; // the distance from the ray origin to the ray intersection of the plane
    9. if(plane.Raycast(ray, out distance))
    10. {
    11.     draggingObject.position = ray.GetPoint(distance); // distance along the ray
    12. }
    Last edited: Aug 10, 2018
  3. Nothilvien


    Jun 11, 2013
    Thank you that works perfect!

    And i don't even need anything else (e.g. WorldToScreenPoint, ScreenToWorldPoint multiple times), do I understand correctly that it will put the GameObject always at the position where the ray hits the plane?

    Would you suggest to do the Raycast every update or skip some frames, just curious if you know by any chance if there is any noticeable performance difference.

    And do you think a solution exists by calculating the Z-WorldPoint and how would it perform in comparison?

    Thank you again, very glad with your provided Solution!. I will mark this Thread as solved and if you or anyone reading by any chance know further answers to my question I'm very curious.
  4. jeffreyschoch


    Jan 21, 2015
    I think that for the best user experience, you should update the position with a raycast every frame that the user is dragging the object. You could add a check to make sure the mouse moved enough since last frame if you want some optimization, but it's a pretty cheap raycast because it's only checking against one Plane object that exists only as a logical object. You can create that plane and store it on Awake instead of creating it for every raycast, but I doubt you will see any impact whatsoever from those optimizations, but it's good practice i guess.

    I don't know of any other way except for a raycast. You have to query the position on the surface under the mouse somehow, and considering the angle of the camera etc, I don't see any other way.
    Nothilvien likes this.
  5. Ilirvg


    Jan 26, 2018
    I was looking for something else but after I saw this post I needed to changed my working code.
    Amazing and clean solution.
    jeffreyschoch likes this.