

//script added to car:
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(Rigidbody))]
public class Controller : MonoBehaviour {
private Rigidbody rb;
public Transform FL, FR, BL, BR;
public float torque = 100;
public float maxAngle = 30;
// Use this for initialization
void Start () {
rb = GetComponent<Rigidbody> ();
rb.centerOfMass = new Vector3 (0, -.5f, 0);
}
// Update is called once per frame
void FixedUpdate () {
float forward = Input.GetAxis ("Vertical");
float steer = Input.GetAxis ("Horizontal");
Vector3 ff = (Vector3.forward * torque * forward);
//Vector3 ss = (Vector3.up * torque * 100 * steer);
rb.AddRelativeForce (ff);
//rb.AddRelativeTorque (ss);
if (FL & FR)
{
FR.localRotation = Quaternion.AngleAxis (steer * maxAngle, Vector3.up);
FL.localRotation = Quaternion.AngleAxis (steer * maxAngle, Vector3.up);
}
}
}
//script added for each wheel - raycast
using UnityEngine;
using System.Collections;
// Do test the code! You usually need to change a few small bits.
[RequireComponent(typeof(Rigidbody))]
public class RaycastWheel : MonoBehaviour {
// More advanced Vehicle Raycast wheel
public Transform graphic;
public float mass = 1.00f;
public float wheelRadius = 0.5f;
public float suspensionRange = 0.10f;
public float suspensionForce = 0.00f;
public float suspensionDamp = 0.00f;
public float compressionFrictionFactor = 0.00f;
public float sidewaysFriction = 0.00f;
public float sidewaysDamp = 0.00f;
public float sidewaysSlipVelocity = 0.00f;
public float sidewaysSlipForce = 0.00f;
public float sidewaysSlipFriction = 0.00f;
public float sidewaysStiffnessFactor = 0.00f;
public float forwardFriction = 0.00f;
public float forwardSlipVelocity = 0.00f;
public float forwardSlipForce = 0.00f;
public float forwardSlipFriction = 0.00f;
public float forwardStiffnessFactor = 0.00f;
public float frictionSmoothing = 1.00f;
public float usedSideFriction = 0.00f;
public float usedForwardFriction = 0.00f;
public float sideSlip = 0.00f;
public float forwardSlip = 0.00f;
public bool driven = false;
public bool brake = false;
public bool skidbrake = false;
public float speed = 0.00f;
private RaycastHit hit;
private Rigidbody parent;
private float wheelCircumference = 0.00f;
private bool grounded = false;
public bool IsGrounded
{
get
{
return grounded;
}
}
void Start ()
{
wheelCircumference = wheelRadius * Mathf.PI * 2;
parent = transform.root.GetComponent<Rigidbody>();
}
void FixedUpdate ()
{
// the object this script is attached to does not move. This ray is like imagining
// that the shock is compressed as much as possible, and then extends out as far as it can before it hits the ground.
// If it doesn't, then the wheel is fully extended.
Vector3 down = transform.TransformDirection(Vector3.down);
// if raycast from position downwards with range suspensionrange + wheelRadius
// and hit.collider != the parent (car)
// calculate the force of the shock as it pushes on the car and the earth due to compression.
// Since the earth does not move, this is an upward force on the car only
if(Physics.Raycast (transform.position, down, out hit, suspensionRange + wheelRadius) && hit.collider.transform.root != transform.root)
{
// how fast is the wheel moving relative to the ground, without taking the wheel's rotation into account
Vector3 velocityAtTouch = parent.GetPointVelocity(hit.point);
// calculate spring compression
// difference in positions divided by total suspension range
float compression = hit.distance / (suspensionRange + wheelRadius);
compression = -compression + 1;
// final force
Vector3 force = -down * compression * suspensionForce;
// velocity at point of contact transformed into local space
Vector3 t = transform.InverseTransformDirection(velocityAtTouch);
// local x and z directions = 0
// Here we set t equal to the speed at which the shock is contracting / expanding
t.z = 0;
t.x = 0;
// back to world space * -damping
// this force simulates the force exerted by the friction in the suspension.
Vector3 shockDrag = transform.TransformDirection(t) * -suspensionDamp;
// forwardDifference = local speed along the z axis
// the difference between the speed of the ground and the wheel taking rotation + the car's velocity into account.
// (in local space, that means, relative to the wheel. So if you were standing on the wheel surface,
// how fast would you percieve the ground moving? Either squashing you every time the wheel goes around
// (not skidding, absolute value close to zero) or scrapping you to bits (skidding, large absolute value))
float forwardDifference = transform.InverseTransformDirection(velocityAtTouch).z - speed;
// newForwardFriction = interpolated between forwardFriction (constant) and
// forwardSlipFriction. Interpolation is forwardSlip squared.
// so if forwardSlip = 1, newForwardFriction = forwardSlipFriction
//Ok, this next part is not related to real physics an any way whatsoever. Ummm... Basically the friction that the wheel has with
// the ground changes (using a lerp function over time) depending on the current friction force.
// I guess this simulates how once a car starts skidding, the friction goes down so it skids more.
// __________________z-friction__________________
// move the current working friction value toward the minimum about porportional to the "skidding-ness" squared
float newForwardFriction = Mathf.Lerp(forwardFriction, forwardSlipFriction, forwardSlip * forwardSlip);
// increase the current working friction value depending on how hard the shock is pressing the wheel against the ground
newForwardFriction = Mathf.Lerp(newForwardFriction, newForwardFriction * compression * 1, compressionFrictionFactor);
if(frictionSmoothing > 0)
usedForwardFriction = Mathf.Lerp(usedForwardFriction, newForwardFriction, Time.fixedDeltaTime / frictionSmoothing);
else
usedForwardFriction = newForwardFriction;
// calculate one component of the friction force: the difference between the wheel surface velocity and ground surface
// velocity times friction (not based on real physics AFAIK)
Vector3 forwardForce = transform.TransformDirection(new Vector3(0, 0, -forwardDifference)) * usedForwardFriction;
// calculate how much we be slippin (if the force is high, the tire will give and slip on the road)
forwardSlip = Mathf.Lerp(forwardForce.magnitude / forwardSlipForce, forwardDifference / forwardSlipVelocity, forwardStiffnessFactor);
float sidewaysDifference = transform.InverseTransformDirection(velocityAtTouch).x;
float newSideFriction = Mathf.Lerp(sidewaysFriction, sidewaysSlipFriction, sideSlip * sideSlip);
newSideFriction = Mathf.Lerp(newSideFriction, newSideFriction * compression * 1, compressionFrictionFactor);
if(frictionSmoothing > 0)
usedSideFriction = Mathf.Lerp(usedSideFriction, newSideFriction, Time.fixedDeltaTime / frictionSmoothing);
else
usedSideFriction = newSideFriction;
// ____________________________________
// this is much the same as the block above, but for the x-axis
// __________________x-friction__________________
Vector3 sideForce = transform.TransformDirection(new Vector3(-sidewaysDifference, 0, 0)) * usedSideFriction;
sideSlip = Mathf.Lerp(sideForce.magnitude / sidewaysSlipForce, sidewaysDifference / sidewaysSlipVelocity, sidewaysStiffnessFactor);
// this thing is totally made up. It's as if god's hand nudges the car back on course whenever it is moving sideways,
// by a factor of sidewaysDamp
t = transform.InverseTransformDirection(velocityAtTouch);
t.z = 0;
t.y = 0;
Vector3 sideDrag = transform.TransformDirection(t) * -sidewaysDamp;
// By the some of all you combined, I become CAPTAIN FORCE
parent.AddForceAtPosition(force + shockDrag - forwardForce + sideForce + sideDrag, transform.position);
// for every action there is an opposite reaction: the wheel adds a force on the ground, but the ground does not move,
// so that force is added to the car instead in the opposite direction (this lets the engine propel the thing forward).
// But!!! we also have to add a force on the engine, because otherwise we'd be adding force from nothing.
// The opposite reaction is this force on the motor. The motor is not a rigidbody, it is a made up thing in the Car.js script
if(driven)
{
//car.AddForceOnMotor (forwardDifference * usedForwardFriction * Time.fixedDeltaTime);
}
else
speed += forwardDifference;
graphic.position = transform.position + (down * (hit.distance - wheelRadius));
}
else
{
graphic.position = transform.position + (down * suspensionRange);
}
speed = parent.velocity.magnitude;
graphic.transform.Rotate(360 * (speed / wheelCircumference) * Time.fixedDeltaTime, 0, 0);
}
void OnDrawGizmosSelected ()
{
Gizmos.color = new Color(0,1,0,1);
Vector3 direction = transform.TransformDirection (-Vector3.up) * (this.wheelRadius);
Gizmos.DrawRay(transform.position,direction);
Gizmos.color = new Color(0,0,1,1);
direction = transform.TransformDirection (-Vector3.up) * (this.suspensionRange);
Gizmos.DrawRay(new Vector3(transform.position.x,transform.position.y - wheelRadius,transform.position.z),direction);
}
}