Search Unity

Resolved Rotate towards mouse position

Discussion in 'Input System' started by Snakebearer, Jun 6, 2022.

  1. Snakebearer

    Snakebearer

    Joined:
    Feb 9, 2013
    Posts:
    26
    My google-fu has let me down. I've found a bunch of examples and tutorials, but there seem to be some slight issue with trying to implement them for myself.

    I'm slapping together a diabloesuqe clone. But with WASD controls, but with mouse used for aiming.
    I've currently arrived at this:

    Code (csharp):
    1.  
    2. //Input Handler Script.
    3.     public void OnRotationInput(InputAction.CallbackContext context)
    4.     {
    5.         Rotation = Mouse.current.position.ReadValue();
    6.     }
    7.  
    8. //Controller Script
    9.         mouseAim = player.mainCamera.ScreenToWorldPoint(player.InputHandler.Rotation) - player.transform.position;
    10.        
    11.         float angle = Mathf.Atan2(mouseAim.y, mouseAim.x) * Mathf.Rad2Deg;
    12.         Quaternion rotation = Quaternion.AngleAxis(angle, Vector3.up);
    13.         player.Rotate(rotation);
    14.  
    15.  
    16. //Called function
    17.         public void Rotate(Quaternion rotation)
    18.     {
    19.         transform.rotation = Quaternion.Slerp(transform.rotation, rotation, 10f *Time.deltaTime);
    20.     }
    21.  
    It's not working. Some of the tutorials and other forum posts I've found approaches this through either 2d or completely top-down. So I might have misunderstood something from that translation..
    But if I were discribe what's happening, and guess what's wrong it'd be this:

    1. The rotation centers around something other than the game object. It seems to center at something far beneath the gameobject. I was suspecting it trying to center it at the base of where the camera would be, maybe.
    2. It seems to rotate the object reversed. Aiming it upwards when the mouse is at the top. Sometimes it doesn't align at all.

    I'm guessing that maybe something is off with my camera settings. If I tried to turn off Orthographic on the camera, the script stopped worked completely. Any one recognize what I'm describing, and seeing any fault in my code? <.<
     
  2. coffeelisk

    coffeelisk

    Joined:
    Feb 19, 2021
    Posts:
    5
    This worked for me

    Code (CSharp):
    1. Ray ray = mainCamera.ScreenPointToRay(context.ReadValue<Vector2>());
    2.             if (Physics.Raycast(ray, out RaycastHit raycastHit))
    3.             {
    4.                 transform.LookAt(new Vector3(raycastHit.point.x, transform.position.y, raycastHit.point.z));
    5.             }
    6.         }
     
  3. Snakebearer

    Snakebearer

    Joined:
    Feb 9, 2013
    Posts:
    26
    This worked. Kind of.
    It does exactly what I want.
    BUT, it only updates the mouse position when actually physically moving the mouse.
    If my player moves, while the mouse is not moving, it starts to rotate to where I last moved the mouse.
    Anyone got any suggestions or ideas how to solve this?
    My last restort will be to simply prevent any rotation at all while moving, but I think that might create issues down the line when adding animations. >.<
     
    coatline likes this.
  4. naknuknik

    naknuknik

    Joined:
    Mar 14, 2021
    Posts:
    19
    Do you only call it inside "OnRotationInput".If you want to rotate the player towards a point while hes moving,you probably want to call "LookAt" in that case(when he changed his position) as well.

    Edit to clarify what I mean - Im asssuming that:
    -OnRotationInput is probably called when your mouse is moving.
    -You have another other places in code where the character is moving which changes his position relative to the mouse, therefore changes where you want him to look but that place isn't doing anything to adjust his actual rotation.
     
    Last edited: Jun 6, 2022
  5. Snakebearer

    Snakebearer

    Joined:
    Feb 9, 2013
    Posts:
    26
    Kind of, maybe?...
    I'm not 100% on how the OnRotationInput is called. What I mean by that is. It seems it doesn't update for it's position unless it's moving..? But I was figuring maybe some kind of if statement to freeze the rotation unless new input is given.
    But I'm not confident where to put it and how to formulate it. :S
     
  6. Snakebearer

    Snakebearer

    Joined:
    Feb 9, 2013
    Posts:
    26
    Ok, I got it to where I wanted now!
    I'm posting it here, if anyone else is going to google this. ^^

    Thanks to both coffeelisk and naknuknik.
    Using worldtopoint like almost every google search led to just can't do this easily. A raycast was the way to go here. :)
    And like naknuknik lead me to understand, I needed to declare a ray in an update to make it continous, instead of just declaring it on input.

    Code (csharp):
    1.  
    2.  
    3. // snippet from PayerInput Script
    4.  
    5. public void OnRotationInput(InputAction.CallbackContext context)
    6.     {
    7.         mousePos = context.ReadValue<Vector2>();      
    8.     }
    9.  
    10.  
    11. //snippet from PlayerController Script, in Update.
    12.  
    13.         Ray ray = Camera.main.ScreenPointToRay(player.InputHandler.mousePos);
    14.  
    15.         if (Physics.Raycast(ray, out RaycastHit raycastHit))
    16.         {
    17.             dotherotate = new Vector3(raycastHit.point.x, player.transform.position.y, raycastHit.point.z);
    18.             player.Rotate(dotherotate);
    19.         }
    20.  
    21.  
    22. //snippet from Player Script
    23.  
    24.     public void Rotate(Vector3 rotation)
    25.     {
    26.         transform.LookAt(rotation);
    27.     }
    28.  
    29.  
     
  7. naknuknik

    naknuknik

    Joined:
    Mar 14, 2021
    Posts:
    19
    I will honestly admit that I now understand less of this problem. As long as it works I guess :D

    Edit, after rereading:
    Im guessing youre calling this code:
    Code (CSharp):
    1.   Ray ray = Camera.main.ScreenPointToRay(player.InputHandler.mousePos);
    2.         if (Physics.Raycast(ray, out RaycastHit raycastHit))
    3.         {
    4.             dotherotate = new Vector3(raycastHit.point.x, player.transform.position.y, raycastHit.point.z);
    5.             player.Rotate(dotherotate);
    6.         }
    inside Update() which is an option as well. What I meant was more along the lines of only calling this when conditions change- player position changed, mouse position changed. But I guess calling it inside Update like you did is easier.
    If youd like - although not required, you could actually call
    Code (CSharp):
    1.   ray = Camera.main.ScreenPointToRay(player.InputHandler.mousePos);
    inside "OnRotationInput" which Im still assuming is only called when your mouse position changes(if so,Id recommend renaming it), and cache the ray inside a private field.
    To actually find out where its called from, just search the method name and see where youre using it(something like "myinput.myactionformouse.performed += OnRotationInput ").
    I highly recommend learning a bit of the C# language and its features(in this case youre probably interested in delegates and events). MSDN is a website by microsoft that can introduce you to the language quite well,and theres tons of tutorials on the internet.
     
    Last edited: Jun 6, 2022