This post explains the custom vehicle controller I created for this game. Because this game has hovering cars that move at high speed the default vehicle controller was in no way suitable.
After some research I could see two feasible methods for getting the desired results in Unity. Both of these use methods use ray cast fired down from the car towards the ground to test for distance and adjust the cars position accordingly.
There are some differences in the approaches I found however, the first method uses four ray cast and Unity’s inbuilt physics engine to apply reactive forces. Thus keeping the car floating above the ground, this is illustrated below.
This method produces very realistic looking results, however using the physics engine makes it very hard to control the cars hover and makes it very unpredictable. Another undesirable result of this method is that if the player crashes the car at high speed the physics engine struggles to produce realistic looking results.
The second method I found during my research uses just one ray cast and directly sets the position of the car using its transform instead of Unity’s physics engine. Again this method is illustrated below.
This method again has its advantages and dis-advantages. The ‘hover’ motion of this solution is much more stable and controllable than previously described solution, but it is less reactive to bumps and therefore bottoms out more often on un-even terrain or hills. This is because the ground is only sampled in one position and if the car rotates the front or back of the car can be lower than the sampled position,
Because both of the solutions have there pro’s and con’s my final solution is a hybrid of the two and again is illustrated below.
The later ‘hybrid’ method uses four ray casts, to produce a relative ‘force’ which applied directly through the physics engine, but as an acceleration. Accelerations in Unity ignore all physics and simply moves the transform. This gives the best of both worlds, because it is very controllable while at the same time it has four sample points which helps negates the problems with bumps and uneven terrain.
Finally the cars rigid body rotations are frozon so that physics do not effect them
The flow graph below explains how the logic flows for the cars hover suspension .
Finally, I moved onto create the final code.
private void HoverSuspension()
for (int i = 0; i &amp;amp;lt; RayCastPoints.Length; i++)
if (Physics.Raycast(RayCastPoints[i].position, -transform.up, out hit, suspensionRange))
if (hit.collider.tag == "Driveable" || hit.collider.tag == "Road")
distances[i] = hit.distance;
curNormals[i] = hit.normal;
vectors[i] = hit.point;
groundedArray[i] = true;
distances[i] = 999f; // Debug Value to bypass later code
groundedArray[i] = false;
//If any ray has hit, then we are grounded.
if(groundedArray == true || groundedArray == true || groundedArray == true || groundedArray == true)
grounded = true;
//No rays hit, we are flying!
grounded = false;
float minDistance = Mathf.Min(distances, distances, distances, distances);
int index = System.Array.IndexOf(distances, minDistance);
Vector3 minPoint = vectors[index];
//Find velocity at hit point
Vector3 _velocityAtTouch = rigid.GetPointVelocity(minPoint);
//Create compression varible
float _compression = minDistance / hoverHeight;
_compression = -_compression + 1;
//Create counterForce vector
Vector3 _counterForce = (transform.up * _compression) * suspensionForce;
//Create a stabalising drag force
Vector3 t = transform.InverseTransformDirection(_velocityAtTouch);
//Remove X and Z
t.z = t.x = 0;
//Create a Y drag force
Vector3 _shockDrag = rigid.transform.TransformDirection(t) * -suspensionDamp;
//Apply The Force, Use the physics engine, but apply it as an acceleration
rigid.AddForce(_counterForce + _shockDrag, ForceMode.Acceleration);
Terrain and Steering Rotation
Now the car can hover, I move onto programming its ability to align its self with terrain below. Because my hover solution adds a single force to the cars transform it can not deal with rotations, for this reason I need a second method which can.
After some research I once again found a solution, available to view here.
Unity Hover Car Terrain Align Solution
The solution is posted by ‘aldonaletto‘ uses only one ray trace to sample the normal angle of the terrain below relative to the car, this value is then used to adjust the cars rotation accordingly.
Because my car has four race traces aldonaletto’s solution can be adapted and made more accurate for my needs. Once again a flow chart shows the logic,
The flow chart above describes how the car will align itself with the terrain below, but does not allow the player to steer the car. How this is done is shown below,
Final code for the vehicles ability to align its self with the terrain and steer is below,
//Steerting and floor aignment
private void TerrainAlignSteer(float _horizontalInput)
//Average the normals
Vector3 averageCurNormal = (curNormals + curNormals + curNormals + curNormals) / 4;
//Check how fast we are going relative to top speed
float speedRange = Mathf.InverseLerp(0, topSpeed, currentSpeed);
//Use speedrange value to adjust the cars turn rate
float adjustedTurnFoce = Mathf.Max(minTurnForce, maxTurnForce * 1 - speedRange);
float turn = (adjustedTurnFoce * _horizontalInput * Time.fixedDeltaTime);
curDir = (curDir + turn) % 360; // rotate angle modulo 360 according to input
//Smooth the terrain normal
curNormal = Vector3.Lerp(curNormal, averageCurNormal, 5 * Time.fixedDeltaTime);
//Find the difference between up and required normal
Quaternion grndTilt = Quaternion.FromToRotation(Vector3.up, curNormal);
//Multiply the input with terrain align and apply
Quaternion newRot = grndTilt * Quaternion.Euler(0, curDir, 0);
transform.rotation = newRot;