Advance Car Game Tutorials Unity 3D

Flat Tutorials

Flat Tutorials On Youtube

The Car Series

I can’t add all the videos over Here … Because of the forum rules … Here is all of my videos CLICK HERE

Code :
Here is the CarControlScript up to Episode #20 :

#pragma strict
var centerOfMass : Vector3;
var wheelFL : WheelCollider;
var wheelFR : WheelCollider;
var wheelRL : WheelCollider;
var wheelRR : WheelCollider;
var wheelFLTrans : Transform;
var wheelFRTrans : Transform;
var wheelRLTrans : Transform;
var wheelRRTrans : Transform;
var lowestSteerAtSpeed : float = 50;
var lowSpeedSteerAngel : float = 10;
var highSpeedSteerAngel : float = 1;
var decellarationSpeed : float = 30;
var maxTorque : float  = 50;
var currentSpeed : float;
var topSpeed : float = 150;
var maxReverseSpeed : float = 50;
var backLightObject : GameObject;
var idleLightMaterial : Material;
var brakeLightMaterial : Material;
var reverseLightMaterial : Material;
private var braked : boolean = false;
var maxBrakeTorque : float = 100;
private var mySidewayFriction : float;
private var myForwardFriction : float;
private var slipSidewayFriction : float;
private var slipForwardFriction : float;
var speedOMeterDial : Texture2D;
var speedOMeterPointer : Texture2D;

var gearRatio : int[];
function Start () {
rigidbody.centerOfMass=centerOfMass;
SetValues();
}
function SetValues (){
myForwardFriction  = wheelRR.forwardFriction.stiffness;
mySidewayFriction  = wheelRR.sidewaysFriction.stiffness;
slipForwardFriction = 0.05;
slipSidewayFriction = 0.085;
}

function FixedUpdate () {
Controle ();
HandBrake();
}
function Update(){
wheelFLTrans.Rotate(wheelFL.rpm/60*360*Time.deltaTime,0,0);
wheelFRTrans.Rotate(wheelFR.rpm/60*360*Time.deltaTime,0,0);
wheelRLTrans.Rotate(wheelRL.rpm/60*360*Time.deltaTime,0,0);
wheelRRTrans.Rotate(wheelRR.rpm/60*360*Time.deltaTime,0,0);
wheelFLTrans.localEulerAngles.y = wheelFL.steerAngle - wheelFLTrans.localEulerAngles.z;
wheelFRTrans.localEulerAngles.y = wheelFR.steerAngle - wheelFRTrans.localEulerAngles.z;
BackLight ();
WheelPosition();
ReverseSlip();
EngineSound();
}
function Controle (){
currentSpeed = 2*22/7*wheelRL.radius*wheelRL.rpm*60/1000;
currentSpeed = Mathf.Round(currentSpeed);
if (currentSpeed < topSpeed  currentSpeed > -maxReverseSpeed  !braked){
wheelRR.motorTorque = maxTorque * Input.GetAxis("Vertical");
wheelRL.motorTorque = maxTorque * Input.GetAxis("Vertical");
}
else {
wheelRR.motorTorque =0;
wheelRL.motorTorque =0;
}
if (Input.GetButton("Vertical")==false){
wheelRR.brakeTorque = decellarationSpeed;
wheelRL.brakeTorque = decellarationSpeed;
}
else{
wheelRR.brakeTorque = 0;
wheelRL.brakeTorque = 0;
}
var speedFactor = rigidbody.velocity.magnitude/lowestSteerAtSpeed;
var currentSteerAngel = Mathf.Lerp(lowSpeedSteerAngel,highSpeedSteerAngel,speedFactor);
currentSteerAngel *= Input.GetAxis("Horizontal");
wheelFL.steerAngle = currentSteerAngel;
wheelFR.steerAngle = currentSteerAngel;
}
function BackLight (){
if (currentSpeed > 0  Input.GetAxis("Vertical")<0!braked){
backLightObject.renderer.material = brakeLightMaterial;
}
else if (currentSpeed < 0  Input.GetAxis("Vertical")>0!braked){
backLightObject.renderer.material = brakeLightMaterial;
}
else if (currentSpeed < 0  Input.GetAxis("Vertical")<0!braked){
backLightObject.renderer.material = reverseLightMaterial;
}
else if (!braked){
backLightObject.renderer.material = idleLightMaterial;
}
}
function WheelPosition(){
var hit : RaycastHit;
var wheelPos : Vector3;

//FL

if (Physics.Raycast(wheelFL.transform.position, -wheelFL.transform.up,hit,wheelFL.radius+wheelFL.suspensionDistance) ){
wheelPos = hit.point+wheelFL.transform.up * wheelFL.radius;
}
else {
wheelPos = wheelFL.transform.position -wheelFL.transform.up* wheelFL.suspensionDistance; 
}
wheelFLTrans.position = wheelPos;

//FR

if (Physics.Raycast(wheelFR.transform.position, -wheelFR.transform.up,hit,wheelFR.radius+wheelFR.suspensionDistance) ){
wheelPos = hit.point+wheelFR.transform.up * wheelFR.radius;
}
else {
wheelPos = wheelFR.transform.position -wheelFR.transform.up* wheelFR.suspensionDistance; 
}
wheelFRTrans.position = wheelPos;

//RL

if (Physics.Raycast(wheelRL.transform.position, -wheelRL.transform.up,hit,wheelRL.radius+wheelRL.suspensionDistance) ){
wheelPos = hit.point+wheelRL.transform.up * wheelRL.radius;
}
else {
wheelPos = wheelRL.transform.position -wheelRL.transform.up* wheelRL.suspensionDistance; 
}
wheelRLTrans.position = wheelPos;

//RR

if (Physics.Raycast(wheelRR.transform.position, -wheelRR.transform.up,hit,wheelRR.radius+wheelRR.suspensionDistance) ){
wheelPos = hit.point+wheelRR.transform.up * wheelRR.radius;
}
else {
wheelPos = wheelRR.transform.position -wheelRR.transform.up* wheelRR.suspensionDistance; 
}
wheelRRTrans.position = wheelPos;
}
function HandBrake(){
if (Input.GetButton("Jump")){
braked = true;
}
else{
braked = false;
}
if (braked){
if (currentSpeed > 1){
wheelFR.brakeTorque = maxBrakeTorque;
wheelFL.brakeTorque = maxBrakeTorque;
wheelRR.motorTorque =0;
wheelRL.motorTorque =0;
SetRearSlip(slipForwardFriction ,slipSidewayFriction); 
}
else if (currentSpeed < 0){
wheelRR.brakeTorque = maxBrakeTorque;
wheelRL.brakeTorque = maxBrakeTorque;
wheelRR.motorTorque =0;
wheelRL.motorTorque =0;
SetRearSlip(1 ,1); 
}
else {
SetRearSlip(1 ,1); 
}
if (currentSpeed < 1  currentSpeed > -1){
backLightObject.renderer.material = idleLightMaterial;
}
else {
backLightObject.renderer.material = brakeLightMaterial;
}
}
else {
wheelFR.brakeTorque = 0;
wheelFL.brakeTorque = 0;
SetRearSlip(myForwardFriction ,mySidewayFriction); 
}
}
function ReverseSlip(){
if (currentSpeed <0){
SetFrontSlip(slipForwardFriction ,slipSidewayFriction); 
}
else {
SetFrontSlip(myForwardFriction ,mySidewayFriction);
}
}

function SetRearSlip (currentForwardFriction : float,currentSidewayFriction : float){
wheelRR.forwardFriction.stiffness = currentForwardFriction;
wheelRL.forwardFriction.stiffness = currentForwardFriction;
wheelRR.sidewaysFriction.stiffness = currentSidewayFriction;
wheelRL.sidewaysFriction.stiffness = currentSidewayFriction;
}
function SetFrontSlip (currentForwardFriction : float,currentSidewayFriction : float){
wheelFR.forwardFriction.stiffness = currentForwardFriction;
wheelFL.forwardFriction.stiffness = currentForwardFriction;
wheelFR.sidewaysFriction.stiffness = currentSidewayFriction;
wheelFL.sidewaysFriction.stiffness = currentSidewayFriction;
}
function EngineSound(){
for (var i = 0; i < gearRatio.length; i++){
if(gearRatio[i]> currentSpeed){
break;
}
}
var gearMinValue : float = 0.00;
var gearMaxValue : float = 0.00;
if (i == 0){
gearMinValue = 0;
}
else {
gearMinValue = gearRatio[i-1];
}
gearMaxValue = gearRatio[i];
var enginePitch : float = ((currentSpeed - gearMinValue)/(gearMaxValue - gearMinValue))+1;
audio.pitch = enginePitch;
}

function OnGUI (){
GUI.DrawTexture(Rect(Screen.width - 300,Screen.height-150,300,150),speedOMeterDial);
var speedFactor : float = currentSpeed / topSpeed;
var rotationAngle : float;
if (currentSpeed >= 0){
  rotationAngle = Mathf.Lerp(0,180,speedFactor);
  }
  else {
  rotationAngle = Mathf.Lerp(0,180,-speedFactor);
  }
GUIUtility.RotateAroundPivot(rotationAngle,Vector2(Screen.width-150,Screen.height));
GUI.DrawTexture(Rect(Screen.width - 300,Screen.height-150,300,300),speedOMeterPointer);

}

Here is the CarCameraScript :

#pragma strict
var car : Transform;
var distance : float = 6.4;
var height : float = 1.4;
var rotationDamping : float = 3.0;
var heightDamping : float = 2.0;
var zoomRacio : float = 0.5;
var DefaultFOV : float = 60;
private var rotationVector : Vector3;
function Start () {
}

function LateUpdate () {
var wantedAngel = rotationVector.y;
var wantedHeight = car.position.y + height;
var myAngel = transform.eulerAngles.y;
var myHeight = transform.position.y;
myAngel = Mathf.LerpAngle(myAngel,wantedAngel,rotationDamping*Time.deltaTime);
myHeight = Mathf.Lerp(myHeight,wantedHeight,heightDamping*Time.deltaTime);
var currentRotation = Quaternion.Euler(0,myAngel,0);
transform.position = car.position;
transform.position -= currentRotation*Vector3.forward*distance;
transform.position.y = myHeight;
transform.LookAt(car);
}
function FixedUpdate (){
var localVilocity = car.InverseTransformDirection(car.rigidbody.velocity);
if (localVilocity.z<-0.5){
rotationVector.y = car.eulerAngles.y + 180;
}
else {
rotationVector.y = car.eulerAngles.y;
}
var acc = car.rigidbody.velocity.magnitude;
camera.fieldOfView = DefaultFOV + acc*zoomRacio;
}

Here is the SkiddingScript :

#pragma strict
private var currentFrictionValue : float;
var skidAt : float = 1.5;
var soundEmition : float = 15;
private var soundWait : float;
var skidSound : GameObject;
var skidSmoke : GameObject;
var smokeDepth : float = 0.4;
var markWidth : float = 0.2;
var rearWheel : boolean;
private var skidding : int;
private var lastPos = new Vector3[2];
var skidMaterial : Material;
function Start () {
skidSmoke.transform.position = transform.position;
skidSmoke.transform.position.y -= smokeDepth;
}

function Update () {
var hit : WheelHit;
transform.GetComponent(WheelCollider).GetGroundHit(hit);
currentFrictionValue = Mathf.Abs(hit.sidewaysSlip);
var rpm = transform.GetComponent(WheelCollider).rpm;
if (skidAt <= currentFrictionValue  soundWait <= 0 || rpm < 300  Input.GetAxis("Vertical")>0  soundWait <= 0  rearWheel  hit.collider){
Instantiate(skidSound,hit.point,Quaternion.identity);
soundWait = 1;
}
soundWait -= Time.deltaTime*soundEmition;
if (skidAt <= currentFrictionValue || rpm < 300  Input.GetAxis("Vertical")>0  rearWheel  hit.collider){
skidSmoke.particleEmitter.emit = true;
SkidMesh();
}
else {
skidSmoke.particleEmitter.emit = false;
skidding = 0;
}
}

function SkidMesh(){

var hit : WheelHit;
transform.GetComponent(WheelCollider).GetGroundHit(hit);
var mark : GameObject = new GameObject("Mark");
var filter : MeshFilter = mark.AddComponent(MeshFilter);
mark.AddComponent(MeshRenderer);
var markMesh : Mesh = new Mesh();
var vertices = new Vector3 [4];
var triangles = new int[6];

if (skidding == 0){
vertices[0] = hit.point + Quaternion.Euler(transform.eulerAngles.x,transform.eulerAngles.y,transform.eulerAngles.z)*Vector3(markWidth,0.01,0);
vertices[1] = hit.point + Quaternion.Euler(transform.eulerAngles.x,transform.eulerAngles.y,transform.eulerAngles.z)*Vector3(-markWidth,0.01,0);
vertices[2] = hit.point + Quaternion.Euler(transform.eulerAngles.x,transform.eulerAngles.y,transform.eulerAngles.z)*Vector3(-markWidth,0.01,0);
vertices[3] = hit.point + Quaternion.Euler(transform.eulerAngles.x,transform.eulerAngles.y,transform.eulerAngles.z)*Vector3(markWidth,0.01,0);
lastPos[0] = vertices[2];
lastPos[1] = vertices[3];
skidding = 1;
}
else {
vertices[1] = lastPos[0];
vertices[0] = lastPos[1];
vertices[2] = hit.point + Quaternion.Euler(transform.eulerAngles.x,transform.eulerAngles.y,transform.eulerAngles.z)*Vector3(-markWidth,0.01,0);
vertices[3] = hit.point + Quaternion.Euler(transform.eulerAngles.x,transform.eulerAngles.y,transform.eulerAngles.z)*Vector3(markWidth,0.01,0);
lastPos[0] = vertices[2];
lastPos[1] = vertices[3];
} 

triangles = [0,1,2,2,3,0];
markMesh.vertices = vertices;
markMesh.triangles = triangles;
markMesh.RecalculateNormals();
var uvm: Vector2[] = new Vector2[4];
uvm[0] = Vector2(1,0);
uvm[1] = Vector2(0,0);
uvm[2] = Vector2(0,1);
uvm[3] = Vector2(1,1);
markMesh.uv = uvm;
filter.mesh = markMesh;
mark.renderer.material = skidMaterial;
mark.AddComponent(DestroyTimerScript);
}

I am Not Really Active On this forum … But You can ask about your problem on facebook[/SIZE]

If you like to get notified about my uploads on youtube then be sure to SUBSCRIBE me on youtube

1 Like

Ive just got one problem that my car flipping around when im driving and stering. Then is rears when get full throttle like a bike :frowning: Try to fix it but it dousent work at all

1 Like

Awsome !!! Bookmarked :smile:

I watched all your tutorial and its really very nice. Keep it up.

Thanks.

hi, i have a problem!

why when i have adding the final script my wheels are crazy?:face_with_spiral_eyes:

Camera LookScript problem

var car : Transform;
var distance : float = 6.4;
var height : float = 1.4;
var rotationDamping : float = 3.0;
var heightDamping : float = 2.0;
var zoomRacio : float = 0.5;
private var rotationVector : Vector3;

function Update () {
var wantedAngle = car.eulerAngles.y;
var wantedHeight = car.position.y + height;
var myAngle = transform.eulerAngles.y;
var myHeight = transform.position.y;
myAngle = Mathf.Lerp(myAngle , wantedAngle , rotationDamping * Time.deltaTime);
myHeight = Mathf.Lerp(myHeight , wantedHeight , heightDamping * Time.deltaTime);
var currentRotation = Quaternion.Euler(0 , myAngle , 0);
transform.position = car.position;
transform.position -= currentRotation * Vector3.forward * distance;
transform.position.y = myHeight;
transform.LookAt(car);
}

i got same problem with the wheel from episode #5, it rotate like the windmill. seem the point of rotation is not at center of the object. if we change from the Unity GUI for x axis rotate only for a random value, it have the same problem. i believe the root cause of this is because of the wheel mesh imported. Anyone know how to fix this?

1 Like

I have not read all through so I may be wrong…

I would guess you used a cylinder for your wheel that you rotate to get the flat parts vertically.
But I would also guess the script is rotating the wheel model on the x axis the horizontal one which is now vertical for you since you rotate.

His goes fine probably because he is using a model made on a modeling software which allows you to model properly from the start.

Is that so?

But I am having another issue with the code:

if (currentSpeed < topSpeed currentSpeed > -maxReverseSpeed !braked){
wheelRR.motorTorque = maxTorque * Input.GetAxis(“Vertical”);
wheelRL.motorTorque = maxTorque * Input.GetAxis(“Vertical”);
}else {
wheelRR.motorTorque =0;
wheelRL.motorTorque =0;
}

if (Input.GetButton(“Vertical”)==false){
wheelRR.brakeTorque = decellarationSpeed;
wheelRL.brakeTorque = decellarationSpeed;
}else{
wheelRR.brakeTorque = 0;
wheelRL.brakeTorque = 0;
}

Apart from those lines, I do not see where the brake is applied. It seems the negative value of the GetAxis is used to apply an opposite force to the motorTorque which according to most users and Unity docs is to be avoided. Unity - Scripting API: WheelCollider.motorTorque

Am I missing a part?

Awesome sauce, I need to move this to teaching though.

i have same problem like arkex my wheel is sping high need help

and i watched the movies over and over and i guss i didn’t mistake need realy help this my project for collage :frowning:

very good tutorial, But the model can not be downloaded now.

You’re responding to a thread of a person who dropped a single post on this forum, said he’d be on Facebook, and never came back.

hai dude when will you start the AI serious? waiting for that eagerly…:wink:

The flipping is probably due to the position of the centerOfMass… I usually create an empty game object that i move around and use its position as centerOfMass. It has to be quite low and maybe a bit forward

Thank you for sharing this code. I will try this at home. I’m done watching all tutorials you have shared and its very cool and interesting.

Hi, this is a very nice script! BUT I have tried to use it for a Bike setup but am struggling a bit, have you got any ideas or advise on how to convert this for a bike?

i hve also problem in wheel transform

in bike

@Cxlaced I want it! Post it please. Thanks!