Move Object / Chatacter To Mouse Click / Touch Position - Unity

This will be a very short post, in fact, one which was requested by one of our friends. In this post we will learn how to move a GameObject (which of course, can be extended to any Player / Character) to a touched position on a touch screen device or a clicked position of the mouse on a non-touch device. This will be mostly used in Role-Playing Games (RPG), wherein we tap on the screen and the Player moves to that position with a constant speed.
Of course it's a Unity tutorial, a Unity Byte as we call it.

The Result: Move To Mouse Click / Touch Position - Unity



To get started create a New Scene and name it whatever you want to. Add a Terrain to this scene or instead, you could add a Plane, it's left to you. Position it a (0, 0, 0). Add some material to it so that you can get a better picture of it’s.

Make sure that this Plane / Terrain that you have created has a Collider component attached to it.

Now add a GameObject of any kind, I'm adding a Sphere, because I'm partial to them. Position it at (0, 0.5, 0). Add a material of a different color to this Sphere.

Add a Directional Light to lighten up the scene.

Set the Main Camera Position to (0, 10, 0), Rotation to (90, 0, 0). Once you are done with that, the setup should look something like:

Move to Tap (Touch) Position / Mouse Click Position - Setup
Move to Tap (Touch) Position / Mouse Click Position - Setup
Create a new C# script named TapToMove. Attach it to the GameObject you've just created. Save the scene and open the script.

Add the below code to it:

using UnityEngine;
using System.Collections;

public class TapToMove : MonoBehaviour {
 //flag to check if the user has tapped / clicked. 
 //Set to true on click. Reset to false on reaching destination
 private bool flag = false;
 //destination point
 private Vector3 endPoint;
 //alter this to change the speed of the movement of player / gameobject
 public float duration = 50.0f;
 //vertical position of the gameobject
 private float yAxis;

 void Start(){
  //save the y axis value of gameobject
  yAxis = gameObject.transform.position.y;
 }
 
 // Update is called once per frame
 void Update () {

  //check if the screen is touched / clicked   
  if((Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began) || (Input.GetMouseButtonDown(0)))
  {
   //declare a variable of RaycastHit struct
   RaycastHit hit;
   //Create a Ray on the tapped / clicked position
   Ray ray;
   //for unity editor
   #if UNITY_EDITOR
   ray = Camera.main.ScreenPointToRay(Input.mousePosition);
   //for touch device
   #elif (UNITY_ANDROID || UNITY_IPHONE || UNITY_WP8)
   ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
   #endif

   //Check if the ray hits any collider
   if(Physics.Raycast(ray,out hit))
   {
    //set a flag to indicate to move the gameobject
    flag = true;
    //save the click / tap position
    endPoint = hit.point;
    //as we do not want to change the y axis value based on touch position, reset it to original y axis value
    endPoint.y = yAxis;
    Debug.Log(endPoint);
   }
   
  }
  //check if the flag for movement is true and the current gameobject position is not same as the clicked / tapped position
  if(flag && !Mathf.Approximately(gameObject.transform.position.magnitude, endPoint.magnitude)){ //&& !(V3Equal(transform.position, endPoint))){
   //move the gameobject to the desired position
   gameObject.transform.position = Vector3.Lerp(gameObject.transform.position, endPoint, 1/(duration*(Vector3.Distance(gameObject.transform.position, endPoint))));
  }
  //set the movement indicator flag to false if the endPoint and current gameobject position are equal
  else if(flag && Mathf.Approximately(gameObject.transform.position.magnitude, endPoint.magnitude)) {
   flag = false;
   Debug.Log("I am here");
  }
  
 }
}

The script is thoroughly commented and it hardly needs any explanation. However, there is one line which does need some kind of clarity.

gameObject.transform.position = Vector3.Lerp(gameObject.transform.position, 
                                             endPoint, 
                                             1/(duration*(Vector3.Distance(gameObject.transform.position, endPoint))));
}

In the above line of code, we are basically moving the gameobject to the touched / clicked position at a constant speed. The first argument in the Lerp function is the source, second is the destination and third is the amount of time it should take to reach the destination from the source.
Greater the duration value, lesser the speed, and vice versa.
We have also multiplied the distance between the source and destination to this duration to make sure that the speed remains constant regardless of the distance between the two points.

(NOTE: Try removing Vector3.Distance(gameObject.transform.position, endPoint) and see how the speed is non uniform, but reaches the destination in a same time regardless of the distance between start point and end point)

Save the script and return to unity. If you test this your object should move to the touched / clicked position at a constant speed.

See you around.
Share on Google+

About Sujit Horakeri

Sujit Horakeri is a game freak just like any other next door guy you would come across. He is a Web Developer by Profession, Game Developer by Choice.
Connect with him on:
    Blogger
    Facebook

30 comments:

  1. Thank you! Do you know how to do the same thing in 2D?

    ReplyDelete
    Replies
    1. Should be fairly simple. Just replace Vector3 by Vector2 in the code and also set the scene in 2D mode and add 2D sprites instead of sphere. The scene setup might change a bit, but the code shouldn't change apart from the Vector2 thing..

      Delete
    2. Thanks for this script, works well on my project, but how do I rotate the object on their y axis when changing heading to make the movement more realistic.?

      Delete
    3. And what about one more object, mean two objects in scene..how to get both objects go to direfent locations?

      Delete
  2. I want to drag the game object where i drag my finger on mobile. This code is moving the game object suddenly. How can i drag it with touch?

    ReplyDelete
    Replies
    1. just replace
      if((Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began) || (Input.GetMouseButtonDown(0)))

      to

      if ((Input.touchCount > 0 ) || (Input.GetMouseButton(0)))

      Delete
  3. Hey there, thanks for the wonderful explanation, it really work! I did try to add this just before the line that move the game object:
    transform.LookAt(endPoint);
    It worked, but i was not able to put another variable, and manage to control the time for rotation. However i am learning, so i will figure it out eventually. However this gave me a little bug, when i click a lot, the object seems to start its movement from different and seemingly random positions. Can you advice me, way maid this occur?
    Thanks in advance!

    ReplyDelete
  4. The compiler is popping an error while building: "use of unassigned local variable"
    So I had to set manually:
    //Create a Ray on the tapped / clicked position
    Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

    ReplyDelete
    Replies
    1. I have this error, did you get the solution >

      Delete
  5. Error building Player: NullReferenceException: Object reference not set to an instance of an object


    i get this error

    ReplyDelete
    Replies
    1. Set your camera tag to main camera.

      Delete
    2. what do you mean by that ??
      I got the same error and still don"t know what to do with this

      Delete
  6. Hi, how we can apply this to a character with walk animation and rotation ?

    ReplyDelete
    Replies
    1. Maybe you should just check a tutorial about animating and another one about rotating right? ;)

      Delete
  7. So thanks its helped to me my MonoGame game project!

    ReplyDelete
  8. So thanks its helped to me my MonoGame game project!

    ReplyDelete
  9. This is great, but how do I get the character to follow the mouse/finger while still clicking. Right now it will move towards where I click until I let go of the mouse button, but it travels in the same direction even if I move the mouse.

    How do I get the player character to follow the mouse?

    ReplyDelete
  10. Also, I already have wasd movement set up, but I'd like players to have a choice between using the keys/arrows, and click to move. Problem is that you can cheat, and go twice as fast by using both. How do I prevent this?

    ReplyDelete
  11. error CS0165: Use of unassigned local variable `hit'.

    could you help?

    ReplyDelete
  12. Not working with me, I am using 2d object, and I changed vector3 to vector2 !!

    ReplyDelete

  13. what do do with this error ???
    ray = Camera.main.ScreenPointToRay(Input.mousePosition);

    ReplyDelete