1

I am trying to rotate a 2d player car using Joystick but its not rotating smoothly. How can i do this. Any help?

What I want is: Click Here

This is happening Click Here

public class RightJoystickPlayerController : MonoBehaviour
{
    public RightJoystick rightJoystick;
    public Transform rotationTarget;
    private Vector3 rightJoystickInput;
    public bool flipRot = true;
    public static float angle;

    private float horizontal;
    private float vertical;

    private void Update()
    {
        rightJoystickInput = rightJoystick.GetInputDirection();
        horizontal = rightJoystickInput.x;
        vertical   = rightJoystickInput.y;
        angle      = Mathf.Atan2(horizontal, vertical) * Mathf.Rad2Deg;
        angle      = flipRot ? -angle : angle;
        rotationTarget.rotation = Quaternion.Euler(new Vector3(0, 0, angle));
    }
}
Jamshaid Alam
  • 515
  • 1
  • 9
  • 24
  • 1
    https://docs.unity3d.com/ScriptReference/Quaternion.Lerp.html – Jinjinov Jul 30 '18 at 11:52
  • You are setting the angle it is facing directly. If you want to rotate smoothly, you need to find the current angle, find the intended angle, then calculate a dampened / smoothed position between those two angles based on how long it should take to rotate and how different the angle is – JMadelaine Jul 31 '18 at 12:00
  • how do i find the intended angle? I tried it but not working. @JMad – Jamshaid Alam Jul 31 '18 at 12:23
  • @JamshaidAlam The intended angle is the angle you want the car to face. Right now you are setting the angle of the car at the intended angle. You should be setting the car at an angle somewhere between its current angle and the intended angle, dependent on velocity / rotation speed and sensitivity – JMadelaine Aug 01 '18 at 13:50

2 Answers2

1

I recommend you to keep track of the last 4, 8 or 16 rotations in an array and use Quaternion.Lerp to set the rotation to the average of those 4, 8 or 16 rotations.

Here is an example that smoothes between 16 rotations(which is extreme smoothing):

private List<Quaternion> lastRotations = new List<Quaternion>();

Quaternion quatA = lastRotations[0];
Quaternion quatB = lastRotations[1];
Quaternion quatC = lastRotations[2];
Quaternion quatD = lastRotations[3];
Quaternion quatE = lastRotations[4];
Quaternion quatF = lastRotations[5];
Quaternion quatG = lastRotations[6];
Quaternion quatH = lastRotations[7];
Quaternion quatI = lastRotations[8];
Quaternion quatJ = lastRotations[9];
Quaternion quatK = lastRotations[10];
Quaternion quatL = lastRotations[11];
Quaternion quatM = lastRotations[12];
Quaternion quatN = lastRotations[13];
Quaternion quatO = lastRotations[14];
Quaternion quatP = lastRotations[15];

Quaternion quatAB = Quaternion.Lerp(quatA, quatB, 0.5f);
Quaternion quatCD = Quaternion.Lerp(quatC, quatD, 0.5f);
Quaternion quatEF = Quaternion.Lerp(quatE, quatF, 0.5f);
Quaternion quatGH = Quaternion.Lerp(quatG, quatH, 0.5f);
Quaternion quatIJ = Quaternion.Lerp(quatI, quatJ, 0.5f);
Quaternion quatKL = Quaternion.Lerp(quatK, quatL, 0.5f);
Quaternion quatMN = Quaternion.Lerp(quatM, quatN, 0.5f);
Quaternion quatOP = Quaternion.Lerp(quatO, quatP, 0.5f);

Quaternion quatABCD = Quaternion.Lerp(quatAB, quatCD, 0.5f);
Quaternion quatEFGH = Quaternion.Lerp(quatEF, quatGH, 0.5f);
Quaternion quatIJKL = Quaternion.Lerp(quatIJ, quatKL, 0.5f);
Quaternion quatMNOP = Quaternion.Lerp(quatMN, quatOP, 0.5f);

Quaternion quatABCDEFGH = Quaternion.Lerp(quatABCD, quatEFGH, 0.5f);
Quaternion quatIJKLMNOP = Quaternion.Lerp(quatIJKL, quatMNOP, 0.5f);

Quaternion quatABCDEFGHIJKLMNOP = Quaternion.Lerp(quatABCDEFGH, quatIJKLMNOP, 0.5f);

And apply "quatABCDEFGHIJKLMNOP" to the rotation of your car.

Every frame you receive a new joystick input add it to the list. if the list count is larger than 16, remove the last rotation with lastRotations.RemoveAt(0);

Initialy, fill the list with 16 same rotations(perhaps Quaternion.identity) declaring the initial rotation of your car.

Update: Complete example with euler angles approach instead of quaternions:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RightJoystickPlayerController : MonoBehaviour
{
    public RightJoystick rightJoystick;
    public Transform rotationTarget;
    private Vector3 rightJoystickInput;
    public bool flipRot = true;
    public static float angle;

    private float horizontal;
    private float vertical;

    private List<float> lastRotations = new List<float>();

    private void Start()
    {
        for (int i = 0; i < 16; i++)
        {
            lastRotations.Add(0f);
        }
    }

    private void Update()
    {
        rightJoystickInput = rightJoystick.GetInputDirection();
        horizontal = rightJoystickInput.x;
        vertical = rightJoystickInput.y;
        angle = Mathf.Atan2(horizontal, vertical) * Mathf.Rad2Deg;
        angle = flipRot ? -angle : angle;

        lastRotations.Add(angle);
        while (lastRotations.Count > 16)
        {
            lastRotations.RemoveAt(0);
        }

        float rotA = lastRotations[0];
        float rotB = lastRotations[1];
        float rotC = lastRotations[2];
        float rotD = lastRotations[3];
        float rotE = lastRotations[4];
        float rotF = lastRotations[5];
        float rotG = lastRotations[6];
        float rotH = lastRotations[7];
        float rotI = lastRotations[8];
        float rotJ = lastRotations[9];
        float rotK = lastRotations[10];
        float rotL = lastRotations[11];
        float rotM = lastRotations[12];
        float rotN = lastRotations[13];
        float rotO = lastRotations[14];
        float rotP = lastRotations[15];

        float rotAB = Mathf.LerpAngle(rotA, rotB, 0.5f);
        float rotCD = Mathf.LerpAngle(rotC, rotD, 0.5f);
        float rotEF = Mathf.LerpAngle(rotE, rotF, 0.5f);
        float rotGH = Mathf.LerpAngle(rotG, rotH, 0.5f);
        float rotIJ = Mathf.LerpAngle(rotI, rotJ, 0.5f);
        float rotKL = Mathf.LerpAngle(rotK, rotL, 0.5f);
        float rotMN = Mathf.LerpAngle(rotM, rotN, 0.5f);
        float rotOP = Mathf.LerpAngle(rotO, rotP, 0.5f);

        float rotABCD = Mathf.LerpAngle(rotAB, rotCD, 0.5f);
        float rotEFGH = Mathf.LerpAngle(rotEF, rotGH, 0.5f);
        float rotIJKL = Mathf.LerpAngle(rotIJ, rotKL, 0.5f);
        float rotMNOP = Mathf.LerpAngle(rotMN, rotOP, 0.5f);

        float rotABCDEFGH = Mathf.LerpAngle(rotABCD, rotEFGH, 0.5f);
        float rotIJKLMNOP = Mathf.LerpAngle(rotIJKL, rotMNOP, 0.5f);

        float rotABCDEFGHIJKLMNOP = Mathf.LerpAngle(rotABCDEFGH, rotIJKLMNOP, 0.5f);

        rotationTarget.rotation = Quaternion.Euler(new Vector3(0, 0, rotABCDEFGHIJKLMNOP));
    }
}
Cambesa
  • 456
  • 1
  • 4
  • 15
  • I have no idea how i am going to deal with... I dont understand @Cambesa – Jamshaid Alam Jul 31 '18 at 11:14
  • I added a complete example script at the bottom of the answer above, try it out and if you need less smoothing you need to remove quatA until quatP and decrease the list size to 8 and apply all list indexes to quatAB until quatOP in the similar way I applied the indexes to quatA until quatP, hope this helps – Cambesa Jul 31 '18 at 11:27
  • Assets/TouchJoysticks/Scripts/RightJoystickPlayerController.cs(66,23): error CS1502: The best overloaded method match for `System.Collections.Generic.List.Add(UnityEngine.Quaternion)' has some invalid arguments – Jamshaid Alam Jul 31 '18 at 11:30
  • Error in this line - lastRotations.Add(rightJoystick.GetInputDirection()); – Jamshaid Alam Jul 31 '18 at 11:31
  • I don't have the joystick class but if the function returns an euler angle, convert it to quaternions – Cambesa Jul 31 '18 at 11:32
  • Ok I canverted in Quaternion and the error is gone, but nothing is happening because "angle" is not used and "angle" is only way to rotate the car – Jamshaid Alam Jul 31 '18 at 11:39
  • Aha okay then we can replace the complete smoothing system by angle lerping. So instead of adding the joystick directly to the list, replace the list with a list of floats and add the angles from your angle calculation to the list and lerp them with Mathf.LerpAngle instead of Quaternion.Lerp. I will update the answer with the euler angle approach – Cambesa Jul 31 '18 at 11:53
  • I cant find any difference even i did it with 8 size :( – Jamshaid Alam Jul 31 '18 at 12:09
  • An interesting approach. Note that this will smooth not only the turning of the car, but also the steering input, making the car slightly slow to respond (depending on framerate), which may or may not be what you want. At 60FPS it will take a quarter of a second for the car to fully respond. – Henrik L. Schou-Pedersen Jul 31 '18 at 12:09
  • With 4 or 8 iterations instead of 16, the smoothing can be enough and still quite fast. Is 4 working better? – Cambesa Jul 31 '18 at 12:13
  • Is there no difference at all? Can you make a video with different smoothings? – Cambesa Jul 31 '18 at 13:37
  • No difference at all. – Jamshaid Alam Aug 01 '18 at 05:05
  • That should not be possible unless something is terribly wrong. Can you try to log the content of the lastRotations list and see if they work as intended? – Cambesa Aug 02 '18 at 10:05
0

It is not rotating smoothly, because you are setting Transform.rotation directly. The naming is slightly confusing. Transform.rotation does not cause it to rotate - it defines the direction it is facing.

In stead try this:

rotationTarget.Rotate(new Vector3(0, 0, angle * Time.deltaTime * ROTATION_SPEED));

Time.deltaTime is necessary to make the rotation smooth regardless of framerate

ROTATION_SPEED should be a const float you define yourself, depending on how fast you want your car to turn.

EDIT based on your clarification: To make your car rotate towards a given direction, try converting horizontal/vertical to a quaternion using Quaternion.LookRotation and then, as others have suggested, use Lerp to smoothly transition transition rotationTarget.rotation towards the target rotation. And multiply by Time.deltaTime and a speed constant.