Search Unity

Question Move camera towards mouse in 2D

Discussion in '2D' started by Antoine_L, Apr 10, 2021.

Thread Status:
Not open for further replies.
  1. Antoine_L

    Antoine_L

    Joined:
    Jul 13, 2017
    Posts:
    5
    Hi, I am trying to move the camera towards the player's mouse using a cinemachine camera in 2D.



    I tried to use a 2d cinemachine virtual camera with a confiner that is parented to the player, so the camera will stay near the player. I have a target game object that the virtual camera follows. I'm currently setting the target game object's position to

    Code (CSharp):
    1. Camera.main.ScreenToWorldPoint (Input.mousePosition);
    The problem with this is that the camera will constantly move in the direction of the mouse, rather than stopping when it gets to the target position.

    Does anyone know how to make the camera behave like in the above video, and stop when it reaches the mouse's position? Thanks!
     
  2. japhib

    japhib

    Joined:
    May 26, 2017
    Posts:
    65
    I think what you need to do is have another gameobject that is always updated to be at the midpoint position between the character and the mouse. Then center the camera around that gameobject.
     
    unluckyboi112 and Gregoryl like this.
  3. Antoine_L

    Antoine_L

    Joined:
    Jul 13, 2017
    Posts:
    5
    Hi, I tried that but it didn't work camera is constantly moving in the direction of the cursor no matter how far it is from the player.

    Code (CSharp):
    1.  
    2. screenRect = new Rect (0f, 0f, Screen.width, Screen.height);
    3. if (screenRect.Contains (Input.mousePosition))
    4. {
    5.     relativeMousePosition = playerTransform.position + (Input.mousePosition - new Vector3 (Screen.width * 0.5f, Screen.height * 0.5f));
    6.     transform.position = Vector2.Lerp (playerTransform.position, relativeMousePosition, sensitivity);
    7. }
    8.  
    I managed to achieve the effect, but when the player moves the camera lags behind.

    Any idea how to fix this?

    Thanks
     
  4. japhib

    japhib

    Joined:
    May 26, 2017
    Posts:
    65
    No idea, without more information on how you implemented it and what exactly you mean by “lag behind” (like a screenshot)
     
  5. Antoine_L

    Antoine_L

    Joined:
    Jul 13, 2017
    Posts:
    5
    Hi, I implemented it by using the following code

    Code (CSharp):
    1. screenRect = new Rect (0f, 0f, Screen.width, Screen.height);
    2. if (screenRect.Contains (Input.mousePosition))
    3. {
    4.     relativeMousePosition = playerTransform.position + (Input.mousePosition - new Vector3 (Screen.width * 0.5f, Screen.height * 0.5f));
    5.     transform.position = Vector2.Lerp (playerTransform.position, relativeMousePosition, 0.002f);
    6. }
    The code is in the update function of a script attached to a gameobject that is assigned as the follow target of a cinemachine virtual camera.
    relativeMousePosition is the mouse position in worldspace compared to the player.
    The second line is lerping between the player's position and the mouse position by a small decimal value because even if the mouse moves a few pixels on the screen, the change will be much larger than it should be in the world.

    Right now there are two problems with this, the first one is that when the player moves the camera no longer aims to the same position. For example, if my mouse is on the right of the screen, and the player is moving right, the camera won't be as far to the right as if the player is not moving. Also, if the screen is bigger, the player will be able to see more than if it's a small screen. The target aspect ratio is currently 16:9, and assume it's kept in that ratio. Even in the same ratio, the screen size can change

    Thanks!
     
  6. japhib

    japhib

    Joined:
    May 26, 2017
    Posts:
    65
    I'm guessing it's because you're missing a conversion between screen coordinates and the player position.

    When you get the mouse coordinates from Input.mousePosition, it comes in screen coordinates, from (0,0) to (Screen.width, Screen.height). To get into world coords, you need to do something like Camera.main.ScreenToWorldCoords. Then you can do arithmetic relative to the transforms of game objects.

    Otherwise the mouse coords you're using are in pixel coordinates, which are way bigger so your script ends up thinking your mouse is a LOT further away from the camera than it actually is.

    Then you can probably also change the 3rd param in your Vector2.Lerp from 0.002f to 0.5f.
     
    Antoine_L likes this.
  7. Antoine_L

    Antoine_L

    Joined:
    Jul 13, 2017
    Posts:
    5
    Hi, after changing the original code I completely forgot about converting the mouse position to world space. Now that I have, the aiming is working now, so it reveals the same distance regardless of screen size. Instead of 0.5, I'm using 0.15 or the camera moves too far.

    For when the player is moving, I'm offsetting the camera when the player moves in a certain direction.

    Code (CSharp):
    1.     [SerializeField] private float sensitivity = 0.15f;
    2.     private Vector2 targetPosition = Vector2.zero;
    3.     private Rect screenRect = Rect.zero;
    4.     [Space (8)]
    5.     [SerializeField] private float movementOffset = 10f;
    6.     [SerializeField] float offsetMoveSpeed = 25f;
    7.     private Vector3 cameraOffset = Vector2.zero;
    8.     private float targetOffsetX = 0f;
    9.  
    10.     private PlayerController playerController = null;
    11.     private Transform playerTransform = null;
    12.  
    13.     private void Start ()
    14.     {
    15.         playerController = FindObjectOfType <PlayerController> ();
    16.         playerTransform = playerController.transform;
    17.     }
    18.  
    19.     private void Update ()
    20.     {
    21.         screenRect = new Rect (0f, 0f, Screen.width, Screen.height);
    22.  
    23.         targetOffsetX = playerController.moveDirection != PlayerController.Direction.none ? (playerController.moveDirection == PlayerController.Direction.right ? movementOffset : -movementOffset) : 0f;
    24.         cameraOffset.x = Mathf.MoveTowards (cameraOffset.x, targetOffsetX, offsetMoveSpeed * Time.fixedDeltaTime);
    25.  
    26.         if (screenRect.Contains (Input.mousePosition))
    27.             targetPosition = Camera.main.ScreenToWorldPoint (Input.mousePosition) + cameraOffset;
    28.            
    29.         transform.position = Vector2.Lerp (playerTransform.position, targetPosition, sensitivity);
    30.     }
    Thanks!
     
  8. japhib

    japhib

    Joined:
    May 26, 2017
    Posts:
    65
    Np, glad you got it working! :)
     
    Antoine_L likes this.
  9. hdahafzeeran

    hdahafzeeran

    Joined:
    Jun 5, 2020
    Posts:
    1
    Mate Cud you tell me how you made it work.
     
  10. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,497
    Cud? ;) They posted the code of their solution above.
     
  11. unluckyboi112

    unluckyboi112

    Joined:
    Jan 17, 2022
    Posts:
    4
    Thank it work, that is a big brain answer.
     
Thread Status:
Not open for further replies.