Search Unity

Question Tilt in Direction of movement + Look at cursor (with Slerp)

Discussion in 'Scripting' started by Xocket, May 23, 2023.

  1. Xocket

    Xocket

    Joined:
    May 11, 2023
    Posts:
    2
    Been with this problem for 3 days now and can't seem to grasp how to solve it.

    It's definitely because my lack of understanding of world and local coordinates and rotations, quaternions and so on, but honestly I've tried everything and what might be something insurmountable for me might be easy for others.

    I want to tilt an object in the direction of movement. That's it, the problem is that I also want it to face the cursor.
    Here's where the problem arises, regardless of orientation the tilt should be relative to the global corrdinates, meaning if i move forward and i face the right, the object should tilt towards its local left, if i face backwards, it should tilt towards its back, if i face the left it should tilt towards its local right, and so on. All of this with slerp. I mention it because I managed it to work without slerp, albeit it still behaves jittery.

    Here's what I mean, tilt towards movement: https://i.imgur.com/lnIlHhk.gif

    look at: https://i.imgur.com/IPboqDW.gif

    and i want to combine them so when combining them though, this happens: https://i.imgur.com/6ovxmQl.gif

    As of now my object is structured this way https://i.imgur.com/0oFnZwv.png

    Player ShipMovement / ShipPointer Scripts
    Ship ShipTilt Script​

    Here's the code for each script.
    Ship Movement:
    Code (CSharp):
    1. public class ShipMovement : MonoBehaviour
    2. {
    3.     public static float movementSpeed = 15f;
    4.  
    5.     private void Update()
    6.     {
    7.         float moveX = Input.GetAxisRaw("Horizontal");
    8.         float moveZ = Input.GetAxisRaw("Vertical");
    9.  
    10.         Vector3 movement = new Vector3(moveX, 0f, moveZ).normalized;
    11.         movement *= movementSpeed * Time.deltaTime;
    12.         transform.Translate(movement, Space.World);
    13.     }
    14.  
    15.     public static Vector3 returnMovement()
    16.     {
    17.         float moveX = Input.GetAxisRaw("Horizontal");
    18.         float moveZ = Input.GetAxisRaw("Vertical");
    19.         Vector3 movement = new Vector3(moveX, 0f, moveZ).normalized;
    20.         movement *= movementSpeed * Time.deltaTime;
    21.  
    22.         return movement;
    23.     }
    24. }
    Ship Pointer

    Code (CSharp):
    1. public class ShipPointer : MonoBehaviour
    2. {
    3.     private Camera _mainCamera;
    4.  
    5.     void Start()
    6.     {
    7.         _mainCamera = Camera.main;
    8.     }
    9.  
    10.     void Update()
    11.     {
    12.         // Get the mouse position in screen coordinates
    13.         Vector3 mousePosition = Input.mousePosition;
    14.  
    15.         // Convert the mouse position to world coordinates
    16.         Ray ray = _mainCamera.ScreenPointToRay(mousePosition);
    17.         Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
    18.         float rayDistance;
    19.  
    20.         if (groundPlane.Raycast(ray, out rayDistance))
    21.         {
    22.             // Calculate the point where the ray intersects the ground plane
    23.             Vector3 targetPoint = ray.GetPoint(rayDistance);
    24.  
    25.             // Calculate the direction to the target point
    26.             Vector3 direction = targetPoint - transform.position;
    27.             direction.y = 0f; // Make sure the object stays upright in the top-down view
    28.  
    29.             // Rotate the object to face the target point
    30.             transform.rotation = Quaternion.LookRotation(direction);
    31.         }
    32.     }
    33. }
    Code (CSharp):
    1. public class ShiptTilt : MonoBehaviour
    2. {
    3.     public float angleTilt = 15f;
    4.     public float tiltSpeed = 7f;
    5.  
    6.     void Update()
    7.     {
    8.         Vector3 movement = ShipMovement.returnMovement();
    9.         Vector3 crossVector = Vector3.Cross(Vector3.up, movement);
    10.         Quaternion targetRotation = Quaternion.AngleAxis(angleTilt, crossVector);
    11.  
    12.         Debug.Log(movement);
    13.         Debug.Log(transform.rotation.ToString());
    14.         Debug.Log(transform.localRotation.ToString());
    15.         Debug.Log(targetRotation.ToString());
    16.  
    17.         transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, tiltSpeed * Time.deltaTime);
    18.     }
    19. }
    If I remove Slerp, changing
    Code (CSharp):
    1. Quaternion targetRotation = Quaternion.AngleAxis(angleTilt, crossVector);
    2. transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, tiltSpeed * Time.deltaTime);
    to
    Code (CSharp):
    1.    transform.rotation = Quaternion.AngleAxis(angleTilt, crossVector);
    it works somewhat, but still jittery. https://i.imgur.com/7KoYHls.mp4

    I'm guessing some things come at play here, as I've tested with the Debug.Log, first of all the movement Vector3 is equal to Vector3.Zero when there's no movement and I'm still creating a cross vector to use and tilt the object, the problem is that (I'm guessing) it defaults to 0,0,1 or something like that so the
    Code (CSharp):
    1. transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, tiltSpeed * Time.deltaTime);
    forces the object to face forward, I tested this by putting an if so it doesn't execute when there's no movement and the object faces the cursor correctly.

    The second thing is that, and as you can see in the code, what I thought about doing was simply using a cross vector between the movement direction and the Vector3.up to get the vector i have to rotate over. So far so good. Problem is as I've seen with Debug.Log, is that everytime the object is supposed to rotate to face the cursor, this quaternion changes completely to equal the targeted one

    https://i.imgur.com/8mIqiql.mp4 Like in this example I've recorded. I don't know if I'm explaining it good enough. Basically what I want is the quaternion to "remain in place" so I can rotate over the cross vector relative to the global coordinates no matter how I'm rotating the object.

    Thanks.
     
  2. Andrew3371

    Andrew3371

    Joined:
    Mar 27, 2023
    Posts:
    23
    It looks like jittery happens because script tries to rotate the object and returns rotation to previous one at the same time.

    Btw you say you can do it separately but not together? Why don't you try to rotate the object in the parent object (empty gameobject) and tilit visual part as a child inside parent?
     
  3. Xocket

    Xocket

    Joined:
    May 11, 2023
    Posts:
    2
    That's what I'm doing. It's okay tho as I think the problem lies with understanding global and local positions. Thanks anyway.