Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Move sprite with mouse click Unity2D

Discussion in 'Getting Started' started by Middrel, Apr 16, 2017.

  1. Middrel

    Middrel

    Joined:
    Oct 19, 2016
    Posts:
    72
    Hi,

    I'm reading tutorials for use Unity, in 2D. It very well explained but I have a dude with move a sprite with mouse click to specific position.

    For example, I need move my sprite (player) with mouse click from point to point, but the sprite has to move as seen in the picture below:



    You can see the image rotate around 45 degrees in direction to mouse click and it is positioned correctly on the grid.

    I know that here you can get help for this, but I would not like to start my project without researching a little.

    So if you could orient me to get this I would appreciate it.

    On the other hand, if you do not understand my english well, I offer you an apology.

    Greetings and thanks for your time!
     
  2. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    There are several ways to tackle this, each with their pros and cons.

    But what I suspect you want is something like this. On each frame (i.e., in Update), do:

    1. Turn towards the target position, using Mathf.MoveTowardsAngle.
    2. Move forward a bit (in the direction of transform.right in 2D, or in 3D, transform.forward).
    3. When you get close enough to the target, stop.

    The problem with this procedure is that your sprite is moving like a vehicle, with a certain turn radius. It can't turn any tighter than that. So, if the target is too close to the vehicle, it may circle it forever and never reach it.

    But give it a try and experiment. There are certainly other ways to do it, including calculating how tight your turn radius should be based on the start position/angle and the end point, but this simple procedure is a good starting point.
     
    Middrel likes this.
  3. Middrel

    Middrel

    Joined:
    Oct 19, 2016
    Posts:
    72
    Hi Joe, thanks for your answer!

    Yep, you are very suspicious, it is a vehicle ^.^

    But it don't aproach to target. It can only move in your area and shoot at a distance to target (for now I will work in the movement, later in the shots).

    If I use the script for movement in tutorials, I can move following the mouse, not by a mouse click. And, my sprite move without rotate :(

    For example:

    void FixedUpdate() {

    float moveHorizontal = Input.GetAxis("Mouse X");
    float moveVertical = Input.GetAxis("Mouse Y");


    Vector3 movement = new Vector3(moveHorizontal, moveVertical);

    rb2d.AddForce(movement * speed);

    }

    In this script my sprite follow mouse in vertical u horizontal direction, without mouseclick.
     
  4. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Oh dear, you're using physics. That makes things a bit harder. So let's address that first.

    Do you really need physics? Are you planning to be crashing into things, and expect those things to bounce around according to physics?
     
  5. Middrel

    Middrel

    Joined:
    Oct 19, 2016
    Posts:
    72
    No. Ok, I will try to explain it better...

    I have two boards to 10x10 squares each (for exmaple, the board can be bigger). In one of these is my player, in other the enemies.

    This is the game mechanic:

    I can move in my board, the enemies only in your board.
    I can attack to the enemies from my board (shooting projectiles) and the enemies attack me from your board.
    I can't pass to enemie's board and the enemies can't pass to my board.

    It is the mechanic. In this moment only I try to move correctly in my board my main player. The movement must be as the image upload in this post.

    You can see it here:



    White side is a player's board, gray side is a enemie's board.
     
  6. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    OK, great. So start be removing any Rigidbody components from your game objects. Also stop using FixedUpdate; put your per-frame code in Update instead.

    Now, try to implement the algorithm in my first reply above. But I guess we need to add some additional steps:
    1. Detect a click on the game board. I would probably do this by just checking Input.GetMouseButtonDown in the Update event, and then casting a ray from the camera to see where on the board it hit. Print out this position hit with Debug.Log. Make sure you've got this before moving on to the next step.
    2. Store the position clicked in a property called "target".
    3. Figure out the angle between the sprite's current position and the target position, using Mathf.Atan2. Print this out with Debug.Log too. Check it manually to make sure it's right.
    4. Now, make your sprite turn toward the position clicked using Mathf.MoveTowardsAngle.
    5. Next, make your sprite move forward at a steady rate.
    6. Finally, add code to stop moving when the distance to the target is less than some minimum value.
    Take these step by step. If you get stuck, ask for help, or go do some Unity tutorials — if you don't know how to declare a property on a script, for example, then you really need to back up and work through some tutorials before attempting to make your own game.

    But hang in there, and you will absolutely be able to do this sooner or later!
     
    Middrel likes this.
  7. Middrel

    Middrel

    Joined:
    Oct 19, 2016
    Posts:
    72
    Ok Joe...

    I will follow step by step what you suggest to me.

    If I have a doubt, I look at tutorials for know how apply the functions. I will show the results.

    Thanks for your help! :D
     
  8. Middrel

    Middrel

    Joined:
    Oct 19, 2016
    Posts:
    72
    Ok, I'm try with it:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class Playercontroller : MonoBehaviour {
    7.  
    8.     public Camera camera;
    9.     public float target = 270.0F;
    10.     public float speed = 45.0F;
    11.  
    12.  
    13.     private void Start()
    14.     {
    15.  
    16.         RaycastHit hit;
    17.         Ray ray = camera.ScreenPointToRay(Input.mousePosition);
    18.  
    19.         if (Physics.Raycast(ray, out hit))
    20.         {
    21.             Transform objectHit = hit.transform;
    22.  
    23.             Debug.Log("Position: " + ray);
    24.         }
    25.  
    26.         Debug.Log("Position: " + hit);
    27.     }
    28.  
    29.     private void Update()
    30.     {
    31.  
    32.      
    33.        if (Input.GetMouseButtonDown(0)) {
    34.  
    35.             float angle = Mathf.MoveTowardsAngle(transform.eulerAngles.x, target, speed * Time.deltaTime);
    36.             transform.eulerAngles = new Vector3(0, angle, 0);
    37.             Debug.Log("Left");
    38.         }
    39.  
    40.         if (Input.GetMouseButtonDown(1)) {
    41.  
    42.             float angle = Mathf.MoveTowardsAngle(transform.eulerAngles.y, target, speed * Time.deltaTime);
    43.             transform.eulerAngles = new Vector3(0, angle, 0);
    44.             Debug.Log("Right");
    45.         }          
    46.  
    47.     }
    48.  
    49. }
    I'm trying to know the behavior of the variables, based on steps 1 and 2.

    Now, I have some doubts:

    1. I should work on RaycastHit2D instead of RaycastHit? In the same way in Ray2D?
    2. How can print to hit position? When I try to print I get a object.
    3. If target is a public variable, how can store the position in it?
    I continue studying and working. Regards!!
     
    Last edited: Apr 19, 2017
  9. Middrel

    Middrel

    Joined:
    Oct 19, 2016
    Posts:
    72
    Ok, verifying information and tutorials on the forums. I think i'm going the right way ... maybe

    Code (CSharp):
    1. void Update()
    2.     {
    3.      
    4.        if (Input.GetMouseButtonDown(0)) {
    5.  
    6.             RaycastHit hit;
    7.             Ray ray = camera.ScreenPointToRay(Input.mousePosition);
    8.  
    9.             if (Physics.Raycast(ray, out hit))
    10.             {
    11.                 Transform objectHit = hit.transform;
    12.  
    13.                 Debug.Log("Hit something Left");
    14.             }
    15.             Vector3 target = transform.position;
    16.             transform.position = target;
    17.  
    18.             Debug.Log("Right" + ray + " target:" + target);
    19.  
    20.         }
    21.  
    22.         if (Input.GetMouseButtonDown(1)) {
    23.  
    24.             RaycastHit hit;
    25.             Ray ray = camera.ScreenPointToRay(Input.mousePosition);
    26.  
    27.             if (Physics.Raycast(ray, out hit))
    28.             {
    29.                 Transform objectHit = hit.transform;
    30.  
    31.                 Debug.Log("Hit something Right");
    32.             }
    33.  
    34.             Vector3 target = transform.position;
    35.             transform.position = target;
    36.             Debug.Log("Right " + ray + " target:" + target);
    37.         }          
    38.  
    39.     }  
    But, I still have doubts:

    I should work on RaycastHit2D instead of RaycastHit? In the same way in Ray2D?
     
  10. Middrel

    Middrel

    Joined:
    Oct 19, 2016
    Posts:
    72
    Ok, I could move the sprite and rotate it as I need it.

    Based on what JoeStrout recommend and looking for additional information in Inetrnet, I got this:

    Code (CSharp):
    1. public class PlayerController : MonoBehaviour {
    2.  
    3.     public float speed;
    4.     private Vector3 target;
    5.     private Vector3 target_rot;
    6.  
    7.     private bool sprite;
    8.  
    9.     void Start()
    10.     {
    11.         target = transform.position;
    12.  
    13.     }
    14.    
    15.     void Update()
    16.     {
    17.         sprite = true;
    18.  
    19.         if (Input.GetMouseButtonDown(0))
    20.         {
    21.             if (sprite)
    22.             {
    23.                 target = Camera.main.ScreenToWorldPoint(Input.mousePosition);
    24.                 target.z = transform.position.z;
    25.                 target_rot = Camera.main.ScreenToWorldPoint(Input.mousePosition);
    26.             }
    27.         }
    28.         transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);
    29.         var angle = Mathf.Atan2(target_rot.y - transform.position.y, target_rot.x - transform.position.x) * Mathf.Rad2Deg;
    30.         transform.rotation = Quaternion.Euler(0, 0, angle + 90);
    31.  
    32.     }
    33. }
    But If I don't use a Rigidbody2D, the sprite move around all board without restriction. If I use Rigidbody2D, it does not happen.