Basically this is the code for the entire car physics handling
using UnityEngine;
public class TopDownCarController : MonoBehaviour
{
[Header("Car settings")]
public float driftFactor = 0.95f;
public float accelerationFactor = 30.0f;
public float turnFactor = 3.5f;
public float maxSpeed = 20;
//local variables
float accelerationInput = 0;
float steeringInput = 0;
float rotationAngle = 0;
float velocityVsUp = 0;
//Components
Rigidbody2D carrigidbody2D;
void Awake()
{
carrigidbody2D = GetComponent<Rigidbody2D>();
}
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
}
// Update is called once per frame
void Update()
{
}
void FixedUpdate()
{
ApplyEngineForce();
KillOrthogonalVelocity();
ApplySteering();
}
void ApplyEngineForce()
{
//Calculate how fast we are going forwards in terms of the direction of our velocity
velocityVsUp = Vector2.Dot(transform.up, carrigidbody2D.linearVelocity);
//Limit so we cannot go faster than the speed limit in the forward direction
if (velocityVsUp > maxSpeed && accelerationInput > 0)
{
return;
}
//Limit so we cannot go faster than the speed limit while reversing
if (velocityVsUp < -maxSpeed * 0.5f && accelerationInput < 0)
{
return;
}
//Limit so we cannot go faster than the speed limit while accelearting
if (carrigidbody2D.linearVelocity.sqrMagnitude > maxSpeed * maxSpeed && accelerationInput > 0)
{
return;
}
//Apply linear damping if there is no accelerationInput so the car stops if the player lets go of the accelerator
if (accelerationInput == 0)
{
carrigidbody2D.linearDamping = Mathf.Lerp(carrigidbody2D.linearDamping, 3.0f, Time.fixedDeltaTime * 3);
}
else
{
carrigidbody2D.linearDamping = 0;
}
//Create a force for the engine
Vector2 engineForceVector = transform.up * accelerationInput * accelerationFactor;
//Apply force that push car forwards
carrigidbody2D.AddForce(engineForceVector, ForceMode2D.Force);
}
void ApplySteering()
{
//Limit car steering based on speed
float minSpeedBeforeAllowTurningFactor = (carrigidbody2D.linearVelocity.magnitude / 8);
minSpeedBeforeAllowTurningFactor = Mathf.Clamp01(minSpeedBeforeAllowTurningFactor);
//Update the rotation angle based on Input
rotationAngle -= steeringInput * turnFactor * minSpeedBeforeAllowTurningFactor;
//Apply steering by rotating the car object
carrigidbody2D.MoveRotation(rotationAngle);
}
public void KillOrthogonalVelocity()
{
Vector2 forwardVelocity = transform.up * Vector2.Dot(carrigidbody2D.linearVelocity, transform.up);
Vector2 rightVelocity = transform.right * Vector2.Dot(carrigidbody2D.linearVelocity, transform.right);
carrigidbody2D.linearVelocity = forwardVelocity + rightVelocity * driftFactor;
}
public void SetInputVector(Vector2 inputVector)
{
steeringInput = inputVector.x;
accelerationInput = inputVector.y;
}
}
and this is the result, the rotation is being kinda goofy (this recording was done after I disabled the speed factor before rotation so I can test rotation without moving)