Car Controller - Day 2



Wheel Collider
The first video I watched was (Simple Car Controller in Unity Tutorial) which creates a car controller using the Wheel Colliders. It functions by setting the motorTorque, brakeTorque and steerAngle of the wheel. This controller works fine, but doesn't give me much insight, since the real mechanics are hidden within the wheel collider.
Another video, which was probably better (I only skimmed through it) was here, this went into more details .

The settings of the wheel collider does look difficult and might need a lot of tweaking to get the "correct" numbers. I did find a video that linked to an EasySuspension code. This allows an easy way to update the wheel collider values.
Cuboid as the moving object - using suspensions
I saw this video which was interesting, as it introduced me to the idea of a cube being moved around. suspensions and drifting. However the video was not practically helpful to me as no code was shared. I watched the video that it referenced, which helped me understand how the concept of the suspension would be implemented.
I also saw this video which was really educational, a well made video. It had snippets of code so between all these sources I thought I should be able to get something working and have some understanding of the physics formulas involved. Unfortunately time being the factor I wasn't able to pursue this direction for long enough.
I got as far as having the object float and move forward - the code is given in Appendix b
Sphere as the moving object
The next video I saw used a sphere for the physics and then moved the car to match the spheres' position. I then watched another video that did the same thing.
Conclusion
I think using hand coded suspensions would've been the best route from a pure understanding point of view. Next best would've been to use the wheel collider, perhaps with a helper class of some sort. Both these methods give a more arcade bouncy feel and allow the wheels to move independently, or at least look like it.
The method I settled on using (given in Appendix A) was having a sphere roll around and the car "skin" follow it. This way I have a decent feel without lots of number tweaking, but I do have some numbers I can modify.
I also added a particle effect for smoke when the car moves. Line trail for the tire marks and a simple explosion effect when it hits an object.
I couldn't find any code highlighter that would convert this to something itch.io blog would accept. So here it is in a raw form
Resources
- Orange Car is from: Modern Cartoon Car Ferruccio (RCC Design)
- Ramp is from: Toon City Pack (Loading Games)
Appendix A - moving a sphere
using UnityEngine;
public class CarController_v2 : MonoBehaviour
{
public Rigidbody theRB;
public float forwardAccel = 8f; // Forward acceleration
public float reverseAccel = 4f; // Reverse acceleration
public float maxSpeed = 50f;
public float turnStrength = 180; // how quickly we can turn
public float gravitryForce = 10f; // When in the air, how much force is pulling the car down back to earth
public float dragOnGround = 3f; // How much drag when on the ground
public float dragInAir = .1f; // How much drag when we're int he air
private float speedInput, turnInput;
[Header("Ground Check")]
private bool isGrounded; // flag - are we on the ground
public LayerMask groundLayer; // defines what layer is regarded as the ground
public float groundRayLength = .5f; // how long ther ground-check ray is
public Transform groundRaypoint; // where in space we want our ray to be cast from
public float alighToGroundTime = 5f;
[Header("Wheels")]
public Transform WheelFL;
public Transform WheelFR;
public float maxWheelTurn = 25f;
[Header("Particle effects")]
public ParticleSystem[] dustTrailEffet;
public float dustTrailMaxEmissions = 25f;
private float dustTrailEmissionRate;
// TODO: Tire burn marks
public TrailRenderer[] tireTrails;
void Start()
{
// remove the sphere from being part of the car
theRB.transform.parent = null;
}
void Update()
{
// get inputs
var inputVert = Input.GetAxis("Vertical");
var inputHorz = Input.GetAxis("Horizontal");
// Are we going forward to backward
speedInput = (inputVert > 0 ? forwardAccel : reverseAccel) * inputVert * 1000f;
// turning amount
turnInput = inputHorz;
// rotate object
if (isGrounded) // Only turn when on the ground
transform.rotation = Quaternion.Euler(transform.rotation.eulerAngles + new Vector3(0f , turnInput * turnStrength * Time.deltaTime * inputVert, 0f));
// turn front wheels
//WheelFL.localRotation = Quaternion.Euler(WheelFL.localRotation.eulerAngles.x, (turnInput * maxWheelTurn) - 180, WheelFL.localRotation.eulerAngles.z); // Might need to rotate wheel by 180, depending on how the car wheels are setup
WheelFL.localRotation = Quaternion.Euler(WheelFL.localRotation.eulerAngles.x, (turnInput * maxWheelTurn), WheelFL.localRotation.eulerAngles.z);
WheelFR.localRotation = Quaternion.Euler(WheelFR.localRotation.eulerAngles.x, (turnInput * maxWheelTurn) , WheelFR.localRotation.eulerAngles.z);
// set position
transform.position = theRB.transform.position;
// Ground check
RaycastHit hit;
isGrounded = Physics.Raycast(groundRaypoint.position, -transform.up, out hit, groundRayLength, groundLayer);
// Smoothly rotate object to alight to ground
Quaternion toRotateTo = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;
transform.rotation = Quaternion.Slerp(transform.rotation, toRotateTo, alighToGroundTime * Time.deltaTime);
// Update drag
theRB.linearDamping = isGrounded ? dragOnGround : dragInAir;
//
// Effects
//
// initial value of dust effect
dustTrailEmissionRate = 0f;
foreach (var trail in tireTrails)
trail.emitting = false;
// set value for tire trail and dust effect
if (isGrounded && Mathf.Abs(speedInput) > 0)
{
dustTrailEmissionRate = dustTrailMaxEmissions;
foreach (var trail in tireTrails)
trail.emitting = true;
}
// setup the dust effect
foreach (var trailParticleSystem in dustTrailEffet)
{
var emissionModule = trailParticleSystem.emission;
emissionModule.rateOverTime = dustTrailEmissionRate;
}
}
private void FixedUpdate()
{
if (isGrounded)
{
// move car using AddForce
if (Mathf.Abs(speedInput) > 0)
{
theRB.AddForce(transform.forward * speedInput);
}
}
else
{
// Add extra gravity push downwards
theRB.AddForce(Vector3.up * -gravitryForce * 100 , ForceMode.Force);
}
}
}
Appendix B - floating cuboid with suspensions
using UnityEngine;
// ref: https://www.youtube.com/watch?v=CdPYlj5uZeI
public class testSuspension : MonoBehaviour
{
public Rigidbody carRB;
public Transform[] tires;
public float suspensionRestDist;
public float springStrength;
public float springDamper;
public LayerMask groundLayer;
public float rayLength = 1f;
public float forwardAccel = 8f; // Forward acceleration
public float reverseAccel = 4f; // Reverse acceleration
void Start()
{
}
void Update()
{
var inputVert = Input.GetAxis("Vertical");
float speedInput = (inputVert > 0 ? forwardAccel : reverseAccel) * inputVert * 1000f;
carRB.AddForce(transform.forward * speedInput);
}
void FixedUpdate()
{
// If grounded
foreach (Transform t in tires)
ApplyForce(t);
}
public void ApplyForce(Transform tireTransform)
{
RaycastHit tireRay;
var rayDidHit = Physics.Raycast(tireTransform.position, Vector3.down, out tireRay, rayLength, groundLayer);
if (!rayDidHit) return;
// worldspace direction of the spring force
Vector3 springDir = tireTransform.up;
Vector3 tireWorldVel = carRB.GetPointVelocity(tireTransform.position);
// calculate offset from raycast
float offset = suspensionRestDist - tireRay.distance;
float vel = Vector3.Dot(springDir, tireWorldVel);
float force = (offset * springStrength) - (vel * springDamper);
// apply the force at the location of this tuire, in the direction of the suspension
carRB.AddForceAtPosition(springDir * force, tireTransform.position);
}
}
I used the following values:
TinyTown
TinyWorld game made for a GameJam
More posts
- Post mortem9 days ago
- Resources10 days ago
- DevLog - Day 610 days ago
- Dev Log - Day 512 days ago
- Pickup and drop off - Day 412 days ago
- Building a Town - Day 314 days ago
- First Entry - Research16 days ago
Leave a comment
Log in with itch.io to leave a comment.