This is part of an ongoing mission to explore making a simple controlled vehicle using the Unity Wheel Collider. See the introduction for a chapter list.
When I posted my first wheel collider demo to the Unity forum I got some really good feedback. So now I updated my scene and script to iron out odd behaviours and add new features. I have posted the scene in a web player and the complete updated script again.
For completeness sake here is the updated script.
var rearWheel1 : WheelCollider; var rearWheel2 : WheelCollider; var frontWheel1 : WheelCollider; var frontWheel2 : WheelCollider; var wheelFL : Transform; var wheelFR : Transform; var wheelML : Transform; var wheelMR : Transform; var wheelRL : Transform; var wheelRR : Transform; var steer_max = 20; var motor_max = 40; var brake_max = 100; var steerSpeed = 20; private var steer = 0; private var forward = 0; private var back = 0; private var brakeRelease = false; private var motor = 0; private var brake = 0; private var reverse = false; private var speed = 0; function Start() { rigidbody.centerOfMass = Vector3(0, -0.05, 0); } function FixedUpdate () { speed = rigidbody.velocity.sqrMagnitude; steer = Input.GetAxis("Horizontal"); forward = Mathf.Clamp(Input.GetAxis("Vertical"), 0, 1); back = -1 * Mathf.Clamp(Input.GetAxis("Vertical"), -1, 0); if(speed == 0 && forward == 0 && back == 0) { brakeRelease = true; } if(speed == 0 && brakeRelease) { if(back > 0) { reverse = true; } if(forward > 0) { reverse = false; } } if(reverse) { motor = -1 * back; brake = forward; } else { motor = forward; brake = back; } if (brake > 0 ) { brakeRelease = false; }; rearWheel1.motorTorque = motor_max * motor; rearWheel2.motorTorque = motor_max * motor; rearWheel1.brakeTorque = brake_max * brake; rearWheel2.brakeTorque = brake_max * brake; if ( steer == 0 && frontWheel1.steerAngle != 0) { if (Mathf.Abs(frontWheel1.steerAngle) <= (steerSpeed * Time.deltaTime)) { frontWheel1.steerAngle = 0; } else if (frontWheel1.steerAngle > 0) { frontWheel1.steerAngle = frontWheel1.steerAngle - (steerSpeed * Time.deltaTime); } else { frontWheel1.steerAngle = frontWheel1.steerAngle + (steerSpeed * Time.deltaTime); } } else { frontWheel1.steerAngle = frontWheel1.steerAngle + (steer * steerSpeed * Time.deltaTime); if (frontWheel1.steerAngle > steer_max) { frontWheel1.steerAngle = steer_max; } if (frontWheel1.steerAngle < -1 * steer_max) { frontWheel1.steerAngle = -1 * steer_max; } } frontWheel2.steerAngle = frontWheel1.steerAngle; wheelFL.localEulerAngles.y = frontWheel1.steerAngle; wheelFR.localEulerAngles.y = frontWheel2.steerAngle; wheelFR.Rotate(0, 0, frontWheel1.rpm * -6 * Time.deltaTime); wheelFL.Rotate(0, 0, frontWheel2.rpm * -6 * Time.deltaTime); wheelMR.Rotate(0, 0, rearWheel1.rpm * -6 * Time.deltaTime); wheelML.Rotate(0, 0, rearWheel2.rpm * -6 * Time.deltaTime); wheelRR.Rotate(0, 0, rearWheel1.rpm * -6 * Time.deltaTime); wheelRL.Rotate(0, 0, rearWheel2.rpm * -6 * Time.deltaTime); }
What’s changed?
The truck tended to launch itself into space when going over jumps. Lots of fun but not very realistic. To address this I did two things.
First I scaled the truck down in size so it is about three meters long. In the first version it was over eleven meters long and nine meters tall – it was the size of a small two storey apartment. Using the correct scale is vitally important when using physics. The correct scale is 1:1 with the real world.
Second I increased the drag on the truck. This slows it down faster and makes it feel generally heavier.
I have added smoothing to the steering. Now when you turn left and right the wheels turn smoothly until they reach the maximum steering angle. When you release the steering controls the wheels rotate back to centered.
I changed the way the truck switches into and out of reverse. If you use the brake to stop the truck moving you have to release the brake key and then press it again to have the truck change into reverse (or forward) gear.
I got the middle set of wheels to rotate. I know I said I was not going to do that, but it bugged me that they did not move.
Finally I changed the wrap mode on the skybox textures from repeat to clamp. This got rid of the visible seams between the skybox textures. (Thanks to NickAVV on the forum for that one).
So what do you think? See anything else that could do with improving? If so let me know in the comments.
FIX:
1) car turns left or right without pushing A or D… something wrong with physics…
2) Steer must work faster i think…
@badbii
I have not seen the truck turn without steering… Not sure what is going on there.
The steering can be made to work faster by increasing the steerSpeed variable. In the script above it is set to rotate at 20 degrees per second. If it were increased to 40 the steering would respond twice as fast.
In this case the vehicle is a truck so I am happy with it's steering being sluggish. If it were a race car I would want it more responsive.
My truck also drifts to the left when moving forward. I am at a loss on how to fix this. Also my front wheels seem to flip 180 degrees on the z axis every few frames.
help?
@Julie: Are you able to export the project to webplayer and put it somewhere we can see it.
Could you send me your demo source code so that I learn it step by step.
Thanks in advance.
Can you post the Unity project, I have followed your instructions with my own car model, and it all worked in part 1, but once I added script it is not working like your truck.
Would be great if you post project. Thanks for great wheel collider tutorial.
Greg
Very nice,
Thank U very much for sharing your script.
Could you also share the WheelCollider end rigidBody settings please.
I am new to unity3D, and i can't figure out the suspension on my car… other then that my car is moving smooooth, unity Rocks !!!
Umm, this is ok, but the truck doesn't really turn as a real truck would. it turns more like a go-kart!
Also, you might want to set your skybox textures to 'clamp' rather than 'repeat', i can see seems showing :/
Thanks guys, this is EXACTLY what I was looking for. Great help for a noob like me 😉 JCar did my head in (I have no idea what any of that C# stuff means – lol).
I have some problems with the direction detection by using this script:
If car turns ~360 on the slope (moving forward), back move don't work with the "back" button.
If car turns ~360 on the slope (moving backwards), forward move don't work with the "forward" button.
I think, it's something with using 'rigidbody.velocity.sqrMagnitude'…
ps
sorry for the bad english.
To those who are having trouble in steering( car moving automatically to left/veering): i think the following link may help you
http://forum.unity3d.com/viewtopic.php?p=288420