Search Unity

  1. We've closed the job boards. If you're looking for work, or looking to hire check out Unity Connect. You can see more information here.
    Dismiss Notice
  2. We're running great holiday deals on subscriptions, swag and Asset Store packages! Take a peek at this blog for more information!
    Dismiss Notice
  3. Check out our Unite Austin 2017 YouTube playlist to catch up on what you missed. More videos coming soon.
    Dismiss Notice
  4. Unity 2017.2 is now released.
    Dismiss Notice
  5. The Unity Gear Store is here to help you look great at your next meetup, user group or conference. With all new Unity apparel, stickers and more!
    Dismiss Notice
  6. Introducing the Unity Essentials Packs! Find out more.
    Dismiss Notice
  7. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice
  8. Unity 2017.3 beta is now available for download.
    Dismiss Notice

Basic to Advanced Car or Vehicle Tutorial

Discussion in 'Scripting' started by bigmisterb, Apr 22, 2011.

  1. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    I see this all the time. Some one posts a piece of code asking how to make Trasform.Translate or whatever work for a car.. make it believable. I say BUPKIS. Controlling a vehicle by code is about the most difficult thing to do, and make it look right. Does that mean you shouldn't, no. It means there is an easier way...

    I am going to attempt to go from scratch to a working vehicle in a tutorial in this multi-part tutorial. The best thing is, I am going to do 90% of it with stuff found here in THIS forum. It's all here, I have done it before. Let's do it again.

    The Basics:

    First things first, we are not going to use anything that Unity doesn't have to start with. We will get to making a car and importing it and doing whatever later.

    We start with a nice NEW scene. Into this scene we are going to add the following packages:

    Character Controller.unityPackage
    Projectors.unityPackage
    Scripts.unityPackage
    Skyboxes.unityPackage

    NOTE: Not a single one of these it totally nessecary, they will be used later on in the more advanced areas. The only thing I usually import is the Scripts, because it contains the SmoothFollow script.

    $tut1-001.jpg


    OK with a new scene, lets create a box, name it Ground. set its scale to 500,1,500 and it's position to 0,0,0. Being the ground, this is of course what we are going to be driving on, so were making it nice and big.

    Next, we are going to create a box, and name it Car. Set its scale to 3,1,5 and its position to 0,5,0. This is the building block of the car.

    OK, we have 3 pieces in our scene, Car, Ground and Main Camera.

    From the Standard Assets folder, we are going to the Scripts folder and the Camera Scripts folder in that. We find a SmoothFollow script in there. Drag that onto the Main Camera in the Hierarchy view.

    In the Hierarchy view, click on the Main Camera, and in the Inspector, scroll down to the Smooth Follow (Script). The Target is None (Transform). We need to drag the Car from the Hierarchy view onto the None (Transform) label there.
    $tut1-002.jpg

    Now, we are going to add a Rigidbody to the mix. So with the Car selected, goto Component/Physics/Rigidbody.

    Scroll down to the Rigidbody in the inspector and change the Mass to 1000;

    The next thing we are going to add, is a Directional Light. (GameObject/CreateOther/Directional Light) Rotate it some in the screen so that not everything looks so bland.

    Now we can play it, and you will see the camera moving some, and a block, it falls, hits the ground, and it's still pretty bland.

    OK, lets create some wheels. (GameObject/CreateOther/Sphere)

    Create one, and we want the Scale to be 1,0.2,1. We will need to rotate it, and move it to a location where a wheel should be. The rotation should be 0,0,90 and the position should be about 1.5, 4.5, 1.8. This is all in how you look at it though.

    OK, next, we are going to set this wheel up. First, we need to parent the wheel to the car, and label it... In my case I am going to label the wheel FrontRight. Next, delete the Sphere Collider from the wheel. (Click on the Gear beside the Sphere Collider in the Inpsector and click Remove Component.) Now Add a WheelCollider to the Wheel. (Component/Physics/Wheel Collider)

    OK, now we have a basic wheel collider attached to one wheel. NOTICE how the radius of the wheel collider is 0.5. This is because the Scale of the original scale of the wheel is 1. This will be very important in later tutorials.

    OK, now if we run it, it is going to drop, hit the ground, but will hobble on the one wheel we set up.

    If you are along with me, then we can go to the next step.

    Click on the wheel we just set up, duplicate it (Ctrl-D) and move it to the back. (the measurements have changed, now we are in the local measurements, so it is 0.5, -0.5, -0.366) Rename this one, RearRight

    Select Both wheels, and duplicate them. Then move them over to the other side. (move them over, then change thier X values to -0.5) Rename them repsectively FrontLeft and RearLeft.

    OK, now with everything in place, we run it, it falls to the ground, but has no springs, so it sits there.


    So lets build up some suspension on it. This is what is going to make it react like a car.

    For each wheel, we need to set 6 values. The Spring Distance (All wheels should be 0.25), the Suspension Spring.Spring (1500 for the front wheels, 1000 for the rear), the Suspension Spring.Damper (All wheels are 2), the Suspension Spring.Target Position (All wheels should be 0.25), the Forward Friction.Stiffness Factor (All wheels should be 0.02) and the Sideways Friction.Stiffness Factor(All wheels should be 0.02)

    This means, that a 1000 KG car takes 5000 (or five times the mass) units of force to keep it springy.

    Now for a simple piece of code to make it all work:

    Code (csharp):
    1.  
    2. //CarController1.js
    3. var wheels : Transform[];
    4.  
    5. var enginePower=150.0;
    6.  
    7. var power=0.0;
    8. var brake=0.0;
    9. var steer=0.0;
    10.  
    11. var maxSteer=25.0;
    12.  
    13. function Start(){
    14.     rigidbody.centerOfMass=Vector3(0,-0.5,0.3);
    15. }
    16.  
    17. function Update () {
    18.     power=Input.GetAxis("Vertical") * enginePower * Time.deltaTime * 250.0;
    19.     steer=Input.GetAxis("Horizontal") * maxSteer;
    20.     brake=Input.GetKey("space") ? rigidbody.mass * 0.1: 0.0;
    21.    
    22.     GetCollider(0).steerAngle=steer;
    23.     GetCollider(1).steerAngle=steer;
    24.    
    25.     if(brake > 0.0){
    26.         GetCollider(0).brakeTorque=brake;
    27.         GetCollider(1).brakeTorque=brake;
    28.         GetCollider(2).brakeTorque=brake;
    29.         GetCollider(3).brakeTorque=brake;
    30.         GetCollider(2).motorTorque=0.0;
    31.         GetCollider(3).motorTorque=0.0;
    32.     } else {
    33.         GetCollider(0).brakeTorque=0;
    34.         GetCollider(1).brakeTorque=0;
    35.         GetCollider(2).brakeTorque=0;
    36.         GetCollider(3).brakeTorque=0;
    37.         GetCollider(2).motorTorque=power;
    38.         GetCollider(3).motorTorque=power;
    39.     }
    40. }
    41.  
    42. function GetCollider(n : int) : WheelCollider{
    43.     return wheels[n].gameObject.GetComponent(WheelCollider);
    44. }
    45.  
    Save the code, drag it to the Car and let it rip.

    What you have, the car falls to the ground, allows you to drive it. (if you click on the Car, and click the Gizmos in the top of the Game sceen screen, you can see what it basically sees in physics.)



    Two things I want to add here, for your use.... One.. add some textures so that things aren't so bland.. And you could use the MouseOrbit script, instead of the SmoothFollow. This allows you to see things happening a little better.

    $tut1-003.jpg

    I hope this at least gets some of you started. I will be adding onto this later. There is alot more to cars and vehicles than a simple box.

    You can see an example of this here.
     
    Last edited: Apr 27, 2011
    Irfan_06 likes this.
  2. carking1996

    carking1996

    Joined:
    Jun 15, 2010
    Posts:
    2,432
    Nice tutorial. :) Any chances of putting up a webplayer?
     
  3. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    Last edited: Jul 1, 2011
  4. Rush Rage Games

    Rush Rage Games

    Joined:
    Sep 9, 2010
    Posts:
    1,998
  5. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    The next part is taking a little longer... and people keep bugging me a little more to actually work at work. So for today, we will discuss a couple of concepts which will be implemented into the newer scripts and why.

    GetComponentsInChildren:
    This is a very interesting method that allows you to get a type of component from all of the children attached to a game object. This will be very useful in setups where we will be able to define an object with children and get all of them in one shot.

    As from my research it returns Component[] where upon the documentation gives something different. Here is some test code:
    Code (csharp):
    1.  
    2. function Start(){
    3.     var x : Component[]=gameObject.GetComponentsInChildren(MeshFilter);
    4.     print(x);
    5.     for(y in x)print(y);
    6. }
    7.  
    Note that GetComponentsInChildren also returns the object with it's children.


    WheelCollider:
    OK, this is a simple component. My discussion here is more to do with the MeshFilter component. The WheelCollider can be added to a mesh with a MeshFilter, it just so happens to take on the size from the MeshFilter's bounds. This is a good thing. It makes creating the collider about 5 steps shorter.

    The purpose for this is that you could copy a wheel, put a MeshCollider on it and it would then have the size needed for what you needed. Oh to do things the easy way. This will of course NOT be how we are going to do things.

    Instantiate:
    I bring this up after doing some research. Instantiate is very powerful. Perhaps more powerful than I need for what I am doing. Instantiate will not only copy an object, but all of it's children with it. Then it will restart any scripts attached to it. So that kind of sucks if you for some of the purposes that I need it for here. Great for other things.

    This test was done to see if you could copy something and re use it. But this also shall not be used. ;)

    Til Tommorrow.
     
  6. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    The Model:

    About 10 years ago I built a little test car that I could drop into a game to test how to, well get cars into that game. It's seen many little rinky dink games in the past and will see our tutorial next...

    View attachment $TestCar.zip
    $tut1-004.jpg

    OK, as you can see I have sized it in 3ds max to roughly 50 units That is 5 units in Unity.... this equates to 5 Meters, or roughly 5 yards or 15 feet. (its all in about sizes, lol)

    The first thing we should notice about this file is that it has some weir thing going on with it's wheels. flCol, frCol and the rest. This will make sense later on. The datchas is the main collider that we are going to use for our car.

    Bring the model into Unity, set it on the box and lets get started with the real part of what this tutorial is about.



    Rebuilding from the ground up:

    Yes, rebuilding... As of the last tutorial, we had a script that would make it run... today were going to build a few scripts that make it work! So the bulk of this tutorial is redoing tutorial 1 with a few extra perks. And this tutorial is almost all about scripts.

    We first need to create 2 specific objects. They are named: GC and EC. In the inspector for each, make sure that their position is all zeros. this is a MUST! These objects will also remain when we open new levels. So we are going to reserve some names for our game. GameController and EnvironmentController. (in other words, don't use those names for any other objects)

    All Code is will be kept up to date HERE


    These are just basic scripts right now. We will be updating them as we add new features.

    Now we are going to relook at our controller. We had our wheels and vehicle all in the same controller. And where this would work in the grand scheme if every vehicle had 4 wheels and the first two steered the other two did not would be perfect. We are going for versatility here though, so we are going to make two scripts: One to control the vehicle, the second to control the wheels. These are integrated so you can't just shove a wheel script on something and have it work. You can, however drop a vehicle controller on something, but with no wheels it wont work.

    So to begin, lets look at the model that I provided here. It has a body, a couple of pieces to the body, a collision mesh, then four wheel colliders with a wheel mesh attached to each. It is all sized and all of the transforms are set to the center of the world in max save the wheels which are centered to themselves. Where it is important to do the centering of the wheels to themselves it is by no means completely necessary. A little extra code to set them up and bind them is possible.

    So basically we are dealing with the following two scripts:
    All Code is will be kept up to date HERE

    Of these, you will notice that only part of the code still remains from the previous post. We are now doing alot of setup work on the vehicle. This is so that we don't have to do it in editor. Also, alot of numbers here are derived from the mass and size of the wheels, so we don't have to worry about alot of information that we could miss while setting up.

    To use these scripts you need to import a vehicle. That vehicle needs to have a few things specified:

    At least one collision mesh. It works on a parented structure, so we only define one collision mesh, the rest are children of it and are picked up automatically.

    Each wheel needs to start with a collision mesh of it's own and all the visible pieces of that wheel are children of it. (Look at the TestCar.3ds I provided for an example)

    Two scripts: VehicleController.js and WheelController.js (Mind the spelling and capitol letters)

    OK, The rest is simple, Drag the VehicleController script onto the TestCar base, set it's mass and power. Check the isPlayer field. Leave the rest alone for now.

    Drag the WheelController onto Each of the wheel collider meshs (the parents) You need to set 1.0 for steering wheels on the steering and 1.0 for driving wheels on the driving wheels. (kind of simple, yeah) The script controls the rest of the factors of the wheels.

    For the moment, if you did everything right you now have a basic car up and running again. There is one thing I added to this that was not in the previous one; The wheel vis updates. This is the part that makes a wheel look like it's turning and shifting and such.



    WORKING DEMO
     
    Last edited: Jul 1, 2011
  7. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    OK, now to the discussion of tweaking. This actually has to be added because you may not like the way the car handles. There are various places that you can tweak things. The easiest places are things like mass, maxSteering and enginePower. These are very self explanitory and easy to use. They don't do much for handling though.

    The centerOfMass is a big way to control how the vehicle reacts. In the script, I do not add that number to the existing center of mass, I replace it. So the center of mass is 1 forward of the center of the world in 3ds max. (which is below the frame of the vehicle) This is actually why this interpretation is very stable. The center of mass is about 2 feet below where it should be. Center of mass is not reset during game time using the script, you can adjust it in the rigidbody during runtime. Once you find a good center of mass, just jot the numbers down and feed them in the script while not running.

    Engine power is my interpretation of what the car's real BHP is. I know the 2001 Z-28 HP rating was 240 and it weighs about 2600 lbs, so All I had to do was to make the mass about right, and the engine power about right, then make it drive kind of what a Camaro of that year drives like. Tweak as you must to make whatever you are working on right. The best test here is to have two different cars with different weights and HP ratings and make them both work correctly off of the same script. The number you are looking for is in the Update function. it reads:
    Code (csharp):
    1.  
    2. power *= enginePower * Time.deltaTime * 2500.0;
    3.  
    A few lines down is the brake multiplier. Adjust it if you want different braking characteristics.

    While we are here, I wish to show you one of the features that will be in this script later on. You will notice that there is a if(isPlayer){ line. This simply means that if you are not a player, you can't push a key to operate the vehicle. Later there will be an if(isAI){ line. ;)

    Wheels:
    Wheels are where all the actual tweaking is done, drive and steer are only there to handle the multiplication done according to the wheel its self, but even here there is opportunity to make things differently. A steering value of -1.0 will cause the wheel to steer backwards. As well a drive value of -1.0 would cause the wheel to rotate backwards. This can be used to create rear steering or other effects. (this would not be possible in the previous tutorial)

    In the Setup of the wheels you will find everything in this section:
    Code (csharp):
    1.  
    2.     var FB=obj.transform.localPosition.z - VC.centerOfMass.z;
    3.    
    4.     col=obj.AddComponent(WheelCollider);
    5.     col.radius=radius;
    6.     col.mass=bounds.size.y * bounds.size.x * 20;
    7.     col.suspensionSpring.spring=VC.mass * 1.5 + (VC.mass * FB * 0.05);
    8.    
    9.     col.forwardFriction.stiffness=0.02;
    10.     col.sidewaysFriction.stiffness=0.01;// + (FB<0 ? 0.01 : 0.0);
    11.  
    Almost everything there adjustable. The mass of the wheel is based off of it's size, bigger wheels are heavier. In testing, I worked heavily with the spring multiplier (1.5 here) and the sideways friction. You will notice that FB is based off of the center of mass in the VehicleController (VC).

    Well, that does it for this issue. We accomplished alot and hopefully you guys will take some time to look at the code instead of just using it without realizing what it does.

    Remember to check out the demo.
     
    Last edited: Jul 1, 2011
  8. zappapa

    zappapa

    Joined:
    Dec 12, 2010
    Posts:
    59
    Very helpful. I'm looking forward to the if(isAI){ line.

    Please make the terrain less flat so we can see how the car behaves while on a bumpy terrain. Also, it took me some time to figure out how to move the camera above the ground (click 'n drag inside the boundaries of the screen). I think a default smoothfollow camera is more intuitive.

    Anyway, thanks a lot!
     
    Last edited: Apr 26, 2011
  9. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    All I have slated for today is more testing and tuning. I can make a unity terrain, that would give the best interpretation of what you are looking for. The reasoning for the mouse orbit is to be able to see how the suspension works. I could actually put both in, and just have a key to swap. ;)
     
  10. PrimeDerektive

    PrimeDerektive

    Joined:
    Dec 13, 2009
    Posts:
    3,039
    I've had it on my "list of things I want to do in Unity" to try and create a simple homage to the original Halo 1 warthog, which had hilariously unrealistic physics and was not a realistic car simulation at all. But it was FUN.

    Having no experience with Unity's wheel colliders and whatnot, and with every other car/vehicle example out there being overzealously realistic simulations with crazy gear ratios and a million different tweaking variables, this tutorial is exactly what the doctor ordered.

    Thanks BMB!
     
  11. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    Today, were doing more tuning. Adding some things into the script that will help with it. We are also going to show you guys the beginning of the GameController I use for this. This will allow us to do some car swapping, camera swapping and game pausing. By virtue, you would not want to do these things on any individual car.

    OK, lets start off with the GameController. This is actually a serious piece of little code. It is designed to NOT be duplicated. To start: Create a new GameObject, name it GC and make sure it is at world zero. (Yes, bolded and in VERY important that you do NOT name it GameController) Now apply this code to it:


    All Code is will be kept up to date HERE
    //GameController.js

    You will need to fulfill the requirements for it. Drag the main camera to it. Adjust the cars number to the number of vehicles that you want to control. and it should be OK.

    The other things that you MUST have is the Standard Assests/Scripts. You need both the SmoothFollow script and the MouseOrbit script. You don't have to assign any of them though.

    What this does is allow you to use the P key to pause, the C key to swap cars and the V key to swap views.

    OK, onto the main feature Tweaking... More tweaking than you can imagine. To do this I actually had to setup more than one vehicle with different properties for each so that I could test and make sure that things were going smoothly. So in the demo that we will be looking at I have added two new vehicles. Unfortunately I wont be sharing them, but they are there so that you understand that if you are building a vehicle controller for more than one type of vehicle, you need to test it on the types of vehicles that you are using.

    The Code:
    // VechicleController.js

    I noted the "notable" changes in red. There probably were some other minor things. The big thing was adding the overall suspension information into the Vehicle script then referencing it in the Wheel script. With these values you can force the suspension to be very specific in nature. In the case of the Tractor that was added to the scene has relative suspension amount of zero. A solid axle. Now this isn't entirely accurate for the tractor, and I am sure that it handles like crap because of it on non smooth surfaces. But having large iron wheels bouncing up and down would kind of make it more unbelievable. How to solve this, will be in a later episode.

    A important notation is the drawing of the gizmos for the wheels. This will be important later on as we will use the numbers generated there to figure out if our wheel is slipping sideways and if we should do skid marks and smoke.

    Next episode we will cover two very big factor in racing and driving... Realistic suspension and gearing.

    For now, enjoy the show

    Edit: Seems like it was bombing because I did not set the power, steering and brake to zero when swapping cars. fixed now.
     
    Last edited: Jul 1, 2011
  12. carking1996

    carking1996

    Joined:
    Jun 15, 2010
    Posts:
    2,432
    Cool!! Your car changer script crashes my pc a lot of times.

    Edit: Thanks! Btw. Select Extrapolate in the RigidBody settings to make the cars' camera not shake/shutter. ;)
     
    Last edited: Apr 27, 2011
  13. zappapa

    zappapa

    Joined:
    Dec 12, 2010
    Posts:
    59
    Thanks again. But what's wrong with all these camera scripts? The classic "SmoothFollow" has been with us for years now, but I think it's not good enough. Also in this example - when going uphill- the camera jitters like crazy and, like all other camera scripts, it goes through walls/terrain. A descent camera script for cars seems to be really hard. Even the 'official' unity car tutorial has a bad camera script (CarCamera). When you stop the car in the Unity car tutorial (almost impossible by the way) the camera keeps flipping back 'n forth.

    I can only hope that you, BigMisterB, will show us how to achieve a nice, smooth car-following camera in all circumstances (even when the camera collides with the terrain or other objects - allthough that might be beyond the scope of this tutorial).

    Speaking of which; just how advanced is this tutorial going to be? Will you be teaching us how to create car / track selection menu's, replay, ghost car, timer, highscore list/leaderboard etc. etc. - or will you mainly focus on the car physics?

    For now I'm really enjoying your show. Just curious; who's paying you to do this?
     
    Last edited: Apr 27, 2011
  14. zappapa

    zappapa

    Joined:
    Dec 12, 2010
    Posts:
    59
    Are you serious? Does this prevent the camera shake or as I called it: the camera 'jitter'? Never tried it, but now I will! thanks carking!
     
  15. carking1996

    carking1996

    Joined:
    Jun 15, 2010
    Posts:
    2,432
    Yes. It helps a lot. :)
     
  16. zappapa

    zappapa

    Joined:
    Dec 12, 2010
    Posts:
    59
    Okay then, this one's for Google :)

    unity3d. To prevent camera shake shutter jitter SmoothFollow, set rigidbody interpolate to extrapolate.
     
  17. aspiration

    aspiration

    Joined:
    Aug 31, 2010
    Posts:
    153
    this is awesome..... something i have been loooking for since much time.... it would be great if you can show some implementation of the AI too after this one is done....
     
  18. Quietus2

    Quietus2

    Joined:
    Mar 28, 2008
    Posts:
    2,061
    Laudable effort, BigMisterB. This will make a great addition to the wiki!

    I got a chuckle with the wizard driving the tractor.
     
  19. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    OK my friends.

    This is probably going to be the last big handling post that I do. (Past this post we will be concentrating on other areas. Any handling will be mentioned but not be a primary subject.)

    For my first part, I will have to backtrack here for a second as it was brought to my attention that some variables were left open, thus confusing some people on what they were for. We will take steps to ensure that never happens again.

    I have added a bit of administration to the script so that people can't do dumb things to mess it up. (well, they can do dumb things, but not some dumb things)

    I cleaned up the Collision requirements. If you use a bunch of boxes for the collision, you will still have to parent them to one of the boxes, but since they contain colliders, it will not override them anymore.

    You MUST fulfill the colliderBase variable. This is primary for telling how the car collides with things. DON'T FORGET

    I also cleaned up the Wheel definition. If there is only one mesh, it will now assume that that is the vis mesh and not the collision mesh. Thus not making it invisible.



    Handling:

    I will start this by pointing out one major fact. Almost all vehicle handling revolves around how the wheels react to the ground that they are on. What I am going to present here is only one interpretation of it. The fact still remains, If you want a vehicle to react to the ground, you HAVE to control how fast that reaction is. When a person drives your vehicle for the first time, in ten seconds he will either quit playing or continue. Nine seconds of that, is handling.

    One second of control, which is the first second.... is center of mass. Up til now we have been working with whatever the model designed deemed as the center of the car. Modelers are seldom if ever right. In my case, the whole car was standing on Y zero. (Z zero in max) For sure this isn't right. Well, Unity can save us in this instance. Once you have applied all of your collision objects, it sets the center of mass to all of those bounds averaged. Now this isn't perfect either but it is an equitable starting point. From here we simply adjust the center of mass to what we need. In the case of what we want now, we will just assume that the new center of mass is Vector3(0,0,1.0). Meaning that the engine causes enough weight difference to cause the rotation of the vehicle to be closer to it.

    We need to first fiddle with the relativeSuspensionAmount. This is defaulted to 0.25. Raise the value to give the whole car a bit of lift if you need it. You can test it by simply starting your car in the air, and letting it drop. If it springs up some and bounces just a little. That is what you want. If it hits the ground, and doesn't bounce, it will have very bad handling from the start.

    Next, we test the car with the default settings for everything else. Adjust the center of mass. Start it, if its not right, stop it rinse and repeat. Getting this number right is 90% of the actual work for tuning a car, so take your time here and don't get confused with the other settings. Center of mass is how the car rotates.

    Next, we have to get control of a few things. Power, drag and suspension stiffness. These 3 elements tell how the vehicle responds to events.

    The first thing we are going to do is to limit the speed. For this, we are going to use a simple maxSpeed variable. This variable will be used in all of our speed based calculations. How we figure that number is simple: We expose a variable that I use called relativeVeloctiy, Then drive the car around a bit, keep tabs on what seems like a good stable speed, then assign it as the max. MaxSpeed is based on drag in this instance. The closer we get to it, the more drag the vehicle has. Also, maxSpeed is units per second. (or meters per second) not MPH, not KPH.. but you can calculate them from it.

    The next number we need is a consistent relative max speed. This is the number that we are going to base all of the variables that need to be tuned to an overall value. Things like steering, suspension and drag.

    For the actual Power, Drag and Stiffness, we are going to start using a object in Unity called AnimationCurve. For everything we could try to achieve with all kinds of math, these curves do it the easiest and quickest of everything. So much so, that I wish that they were a Unity prefab object that you could just drag and place where you wanted it.

    Drag:
    Drag is a simple curve that gives a value between zero on 0.5. It is based off of the current forward speed / maxSpeed. The point with Drag is that you don't want to use it, until near the very end. Then you ramp it up and don't let the car exceed that speed.

    Power:
    The power curve is very simple, it is the amount of power that can be used from the enginePower at the speed we are going. Again, derived from speed / maxSpeed.

    SidewaysStiffness:
    This is a special curve that denotes how much side grip our tires have at speed / 100. I use 100 here because you don't want a vehicle that is going 20 (maxSpeed) to slide all over the place. 100 seemed nice.

    There will be more curves that we will add as time goes on, but these are the most important.

    OK, the last change, is an addition. The original post is HERE It is an Anti Roll script. This script will augment the rest of the stuff and help to keep the vehicle level as you drive. I have seen where this script will cause problems in off road type of games where slight jostling of the corners of the vehicles will have odd results. I give it because it is a must for relating actual physics of an antiroll bar in a vehicle.
     
    Last edited: May 1, 2011
  20. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    The Code:

    All Code is will be kept up to date HERE
     
    Last edited: Jul 1, 2011
  21. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    All Code is will be kept up to date HERE
     
    Last edited: Jul 1, 2011
  22. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    The new demo is available HERE

    I did not take as much time tuning, so it is a bit wonky. Mostly because I wont be using this scene again. ;)

    The big thing I wanted to get out there are the tools to make a real physics/game run vehicle. Remember, anytime that you try to develop a vehicle with any script. You are going to spend hours tuning it. I spent hours writing code and this writeup. ;)
     
  23. aspiration

    aspiration

    Joined:
    Aug 31, 2010
    Posts:
    153
    the previous demo with 3 vehicles was with quite stable physics. The physics seem to have got problematic here. My car keeps on rolling again and again...
     
  24. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    consider lowering the center of mass. The real difference between the previous and this version is only the center of mass. ;)
     
  25. the_Simian

    the_Simian

    Joined:
    Mar 13, 2011
    Posts:
    33
    thanks man!
     
  26. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    Hey guys, sorry for the lack of posting, this is a heavy week for me at work, I usually can play more.

    I have updated the DEMO with what I am going to cover here real quick. Make sure that you press C to control the Truck, and V to go into MouseLook to see what is presented here.

    I found some quick errors I need to make right. In the GameController, I mistakenly added a second SmoothFollow instead of a MouseLook controller onto the camera. This will be corrected in the code above.

    In the There will be moderate updates to the VehicleController and Wheel controller to outfit a suspensionBias variable. This variable will control the spring bias between the front and back of the vehicle. This will allow you to set the spring rates with a simple number.

    Suspension:
    No, not the suspension we have been talking about. This is real.. visible suspension parts. There are 3 scripts below that will control visible suspension parts. Including, a solid axle, springs and a-arms. I am contemplating a drive shaft later. Please remember these are game scripts, they do not do well on large suspension parts. So if you are planning a monster truck, this may not be the best solution. (not that using a single ray wheel is either.)


    SusAxle.js

    This piece of code is put onto a solid axle. You then drag the left wheel to it's spot in the script, and the right one to the right spot. It does the rest. The truck in the demo will have this script attached to all 3 axles.

    Code (csharp):
    1.  
    2. // SusAxle.js
    3. private var doScript=false;
    4.  
    5. var wheelLeft : Transform;
    6. var wheelRight : Transform;
    7.  
    8. private var leftPoint : Transform;
    9. private var rightPoint : Transform;
    10.  
    11.  
    12. function Start(){
    13.     if(!wheelLeft) return;
    14.     if(!wheelRight) return;
    15.     if(!transform.parent) return;
    16.    
    17.     leftPoint=GameObject(this.name + "_LeftPoint").transform;
    18.     rightPoint=GameObject(this.name + "_RightPoint").transform;
    19.     leftPoint.parent=transform.parent;
    20.     rightPoint.parent=transform.parent;
    21.     leftPoint.position=wheelLeft.position;
    22.     rightPoint.position=wheelRight.position;
    23.    
    24.    
    25.     doPosition();
    26.     transform.parent=leftPoint;
    27.    
    28.    
    29.     doScript=true;
    30. }
    31.  
    32. function LateUpdate () {
    33.     if(!doScript) return;
    34.     doPosition();
    35.    
    36. }
    37.  
    38. function doPosition(){
    39.     leftPoint.position=wheelLeft.position;
    40.     rightPoint.position=wheelRight.position;
    41.    
    42.     leftPoint.LookAt(rightPoint.position, transform.parent.up);
    43.     //wheelLeft.localEulerAngles.z=transform.localEulerAngles.z;
    44.     //wheelRight.localEulerAngles.z=transform.localEulerAngles.z;
    45. }
    46.  
    SusAArm.js

    This code is placed on an AArm mesh. You must define the chassis connection point and the suspension connection point. I strongly suggest using dummies or empty game objects for these.

    Remember that the suspension connection point needs to be parented to a solid axle. For independent AArms, create a empty game object and assign it an SusAxle.js

    Code (csharp):
    1.  
    2. //SusAAarm.js
    3. private var doScript=false;
    4.  
    5. var chassisPoint : Transform;
    6. var connectionPoint : Transform;
    7.  
    8.  
    9. function Start(){
    10.     if(!chassisPoint) return;
    11.     if(!connectionPoint) return;
    12.     if(!transform.parent) return;
    13.    
    14.    
    15.     doPosition();
    16.     transform.parent=chassisPoint;
    17.    
    18.    
    19.     doScript=true;
    20. }
    21.  
    22. function LateUpdate () {
    23.     if(!doScript) return;
    24.     doPosition();
    25. }
    26.  
    27. function doPosition(){
    28.     chassisPoint.LookAt(connectionPoint.position, transform.parent.up);
    29. }
    30.  
    SusSpring.js

    This script is applied to a spring object. It requires a chassis connection and a suspension connection. I strongly suggest using dummies or empty game objects for these.

    Remember that the suspension connection point needs to be parented to a solid axle. For independent AArms, create a empty game object and assign it an SusAxle.js

    Code (csharp):
    1.  
    2. //SusSpring.js
    3. private var doScript=false;
    4.  
    5. var chassisPoint : Transform;
    6. var connectionPoint : Transform;
    7.  
    8. private var defaultSpringDistance=0.0;
    9.  
    10. function Start(){
    11.     if(!chassisPoint) return;
    12.     if(!connectionPoint) return;
    13.     if(!transform.parent) return;
    14.    
    15.     defaultSpringDistance=Vector3.Distance(chassisPoint.position, connectionPoint.position);
    16.     doPosition();
    17.     transform.parent=chassisPoint;
    18.    
    19.    
    20.     doScript=true;
    21. }
    22.  
    23. function LateUpdate () {
    24.     if(!doScript) return;
    25.     doPosition();
    26. }
    27.  
    28. function doPosition(){
    29.     chassisPoint.LookAt(connectionPoint.position, transform.parent.up);
    30.     var zScale=Vector3.Distance(chassisPoint.position, connectionPoint.position)/defaultSpringDistance;
    31.     chassisPoint.localScale.z=zScale;
    32. }
    33.  
    And yes, I thought of this on the way home and had it all done and tested in about an hour. ;)

    All Code is will be kept up to date HERE
     
    Last edited: Jul 1, 2011
  27. ersaurabh101

    ersaurabh101

    Joined:
    Oct 8, 2010
    Posts:
    403
    why the car rools down, when i try to turn ??? what the best way to learn the car thing ??
     
  28. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    Goto the start of this thread, there is a small tutorial on building a simple box and getting started. This gives you the basics. ;)
     
  29. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    OK guys and girls... sorry I havent had alot of time to work on this, and needless to say this is a pretty big section.

    Environment (Because without it, we are nothing)

    I have updated the DEMO

    OK, I have to change the way I am doing some stuff. So I am putting all the code into a zip file with some other stuff as it is getting a little big for what I need it for.

    All Code is will be kept up to date HERE

    I added alot of stuff having to deal with the environment, and started the fully realized EnvironmentController. I created an empty GameObject called EC and drug the Environment controller script to it.

    There are a bunch of things that we have to fulfill to make the environment work. We have to have a base Track object. So in my case, I just had a terrain, so that was it. I made some cubes in the demo that have different properties and attached them to the terrain.

    The properties are tags. So I created 5 tags; pavement, dirt, grass, mud and ice. Each block in the demo has a tag for what it is.. they should be pretty obvious.

    The Track Base object in the environment controller goes through all the colliders in the track (or stuff attached to it) and makes all of the physics materials for it.

    Next, we have to fulfil the different types of effects objects, whiteSmoke, brownSmoke, grassSmoke and mudSmoke. These are just basic particle emitter objects with miminal changes to get the effects. You can go as far as you want with this.

    The point of these effects is to give you an example of what to do in the situation. If you specifically wanted a dirt effect with multi-part emitters, just created it, and add whatever into the code. You will find a doSmoke function which is fairly simply designed. Go make it as complicated as you want.

    Next, we need to fulfill the Default Skid Texture. I actually provided a skid texture in the zip file linked above, as well as a dual skid for things like the back end of the desil tractor in the demo. Again, basic, do whatever you feel like you want.

    OK, how all this works together. I have uncommented out the EC lines in the start of the Vehicle and Wheel Controllers. This will let the game go in and get the scripts associated with it. This is necessary to get started adding effects from the vehicles to the environment. I then added some code in the late update to get the information across to the EC for skids and smoke.

    The last thing I did was to have the wheel collect the data from the Physics Material and calculate it into the side and front stiffness. This means that when you drive over ice. you have very little control over it. I also added in to half the radius of the wheel when driving over mud. This is probably the worst way to do it, but it satisfies the effect.

    The Math

    The math is probably controversial, but it does give the effect I was after. It all resides in a few lines of code in the LateUpdate of the WheelCollider. It determines drive slip, side slip and brake slip and feeds those into the skid and smoke creators. There each type of environmental tag asks some questions of each if not all the types of slip that are there.

    Perhaps to be a little more advanced, we could create a specific function to set the forward and side stiffness according to the type of material that we are on. This way we aren't arbitrary on how we do some of these things. Mud would be hard to drive forward in, but should not let you slide side to side easily.

    The Skidmarks.js comes from the Unity demo project for vehicles and was modified to suit the needs of this setup.

    The cars have been adjusted where they operate more to normal parameters, so it will make for a bit more fun to horse around with.

    Check out the zip file HERE to get the latest. Remember next time I update, I will simply update that zip file. ;)

    Next on the chopping block, Pseudo gears, road noise and engine sounds. It should be thrilling if not loud.
     
    Last edited: Jul 1, 2011
  30. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    Other scripts that will be incorporated into the next demo:

    Inverted Camera for mirrors:
    http://www.unifycommunity.com/wiki/index.php?title=InvertCamera

    MiniMap instructions: (same camera setup to do the mirrors above)
    http://www.moddb.com/games/caredu/tutorials/how-to-make-a-minimap

    MiniMap mod: I posted this in another thread because the MiniMap tutorial was ganky
    http://forum.unity3d.com/threads/88943-rear-view-window?p=575145&viewfull=1#post575145

    All 3 combine to make mini maps and mirrors for our car.
     
  31. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    Pseudo Gears:

    In working on this script we developed a method of limiting the overall speed, and controlling the overall power of the vehicle. Now we must figure out a way to create a gearing system based in that realm. This roughly means that our gears really would have nothing to do with the speed or power our car produces.

    What we will layout here will be the basics of how to accomplish this with little overhead.

    Lets assume that we are driving a vehicle who's max speed is 80 mps (178.84 MPH) and we have 4 gears. (reverse is always 25% of the speed of max forward if you were paying attention)

    OK so lets make up some numbers for our gears. Lets say that 80 mps is 100% speed and our top gear is 60% + the number of gears that we have, so 64%. 1st gear is always 0%. So now we have to define what the internal gears are. So lets arbitrarily say that 2nd is 21.33% and 3rd is 42.66%. (33% and 66% of the 64% remaining for the gears)

    This now gives us shift points at 0 mps, 17.064 mps, 34.128 mps and 51.2 mps. With the max reverse speed of 20 mps. So with this knowledge we can easily develop a small array that keeps those numbers and all we have to do is figure out what speed our gear is.

    Next, we need to figure out what the wind is for the engine. So we will assume the stall for our vehicle is 1900 rpm, and the max is 4000 rpm. So, at 0 to 17 mps, we wind out from 1900 to 4000 then at 18mps we swap back to 1900 and wind up to 4000 to 34mps, and so on.

    OK, so with all this taken into account, here is the actual code that makes the gearing work.

    Code (csharp):
    1.  
    2. var numberOfGears=4;
    3. var idleRPM=1000.0;
    4. var stallRPM=1900.0;
    5. var peakRPM=4000.0;
    6. var mps=0.0;
    7. var RPM=0.0;
    8. var MPH=0.0;
    9. var KPH=0.0;
    10. var GEAR=0;
    11. private var gears : Array;
    12.  
    13. var maxSpeed=80.0;
    14. var power=0.0;
    15.  
    16. private var gears : Array;
    17.  
    18. function Start(){
    19.     // gears can only be 3-10.. make sure of it.
    20.     numberOfGears=Mathf.Clamp(numberOfGears, 3, 10);
    21.    
    22.     gears=Array();
    23.     gears.Add(0);// gear 1 is always zero
    24.     var max : float=(60.0 + numberOfGears)/100.0;
    25.     for(i=1; i< numberOfGears-1; i++){
    26.         gears.Add(i * (max/(numberOfGears)) * maxSpeed);
    27.     }
    28.     gears.Add(max * maxSpeed);
    29.     gears.Add(maxSpeed);
    30. }
    31.  
    32. function LateUpdate(){
    33.     if(!doScript) return;
    34.     if(!isPlayer  !isAI) return;
    35.     mps=relativeVelocity.z;
    36.     MPH = Mathf.Round(mps * 3600 / 1610.3*1000)/1000;
    37.     KPH = Mathf.Round(mps * 3600 / 1000*1000)/1000; // check math
    38.    
    39.     GEAR=0;
    40.     var min=0.0;
    41.     var max=0.0;
    42.     for(var i=0; i<gears.length; i++){
    43.         if(gears[i]<mps){
    44.             min=gears[GEAR];
    45.             GEAR++;
    46.             max=gears[GEAR];
    47.         }
    48.     }
    49.     if(mps < 0.0){
    50.         GEAR=-1;
    51.         max=maxSpeed/4;
    52.     }
    53.    
    54.     RPM=(Mathf.Abs(mps) - min) / (max - min) * (peakRPM - stallRPM) + stallRPM;
    55.    
    56.     if(power==0.0){
    57.         RPM +=(RPM - stallRPM) / (peakRPM - stallRPM) * .25;
    58.        
    59.         if(Mathf.Abs(mps) < gears[1] * 0.5) RPM=idleRPM;
    60.     }
    61.     if(RPM<idleRPM)RPM=idleRPM;
    62. }
    63.  
    As you can see, I have open variables to tell what the RPM, MPH, KPH and mps are as well as what gear we are in. The only thing I actually had to add to the mix was the max mps into the gearing mix, since I am using it to determine the actual rpm from the speed.

    I provide all of this so that you can make some pseudo gears, however, if you are building a vehicle with actual gears, this is of course, NOT the way you would do it. ;)
     
  32. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    Sounds:

    OK guys, next up on the chopping block is sounds. We had to have the gearing working before this to get numbers for the pitch volumes on the sounds. (There are some test sounds in the zip file, all were obtained through http://SoundDogs.com and are low quality)

    Working Demo
    All Code is will be kept up to date HERE

    As you can see in this demo, we have engine and tire squealing sounds on dirt and pavement. The biggest thing I can say about this is that you may or may not have the greatest sounds guys working on your game. I created a Sound class that handled pitch variations and volume variations as well as other smaller things. This also made it easier to create sounds and effects as I went along. If you will have a look at the EnvironmentalController, you will see where I added in the doSkidSound function and it operates much the same as the other funcitons in the area by clipping the sounds out that need to be played. In this case it creates a new object to play the sound at the location where it happened, then destroys that sound when it's done.

    Also while we are here, have a look at the Sound class. It will help to explain some of it's features. The pitch and volume (setPitch and setVolume) handle pretty much all the controls your environment will need for various things. The doppler is there, though I always set it to zero because I don't really like the effect it gives. Note the volume and pitch adjustments. This is for people like me who are NOT sound guys. ;)

    To use them, just state something is a Sound, and drag a clip to it. You really don't have to do anything else, unless you want it to loop. ;)


    Physics Additions:

    OK, here are a bit more in the way of physics. I added in a front and rear down force to the vehicles. In the case of the Camaro, there is more down force applied the faster you go. The tractor and truck have very little down force. You can use higher values to keep stability on the vehicle and prevent it from looking like the front end is going to lift off at any second.

    Hope this helps a bit more for you guys.

    Next up on the chopping block: Basic AI control. (Which everyone seems to be asking for but it is really not that complex.)
     
    Last edited: Jul 1, 2011
  33. carking1996

    carking1996

    Joined:
    Jun 15, 2010
    Posts:
    2,432
  34. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    Last edited: Jul 1, 2011
  35. PrimeDerektive

    PrimeDerektive

    Joined:
    Dec 13, 2009
    Posts:
    3,039
    BMB, how come when you drift/fishtail the car jitters a bit?
     
  36. TheRaider

    TheRaider

    Joined:
    Dec 5, 2010
    Posts:
    2,180
    totally awesome tutorial.

    You should be congratulated on doing this.

    I haven't done it but I plan too since I always struggled with cars.
     
  37. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    Probably due to the side slip variance at speeds. I will probably address this in a follow up in the end, but for now I am going to let it slide. After all this is a tutorial, not a finished product. ;) I want people to work to make it perfect, not supply them with something perfect to start.
     
  38. PrimeDerektive

    PrimeDerektive

    Joined:
    Dec 13, 2009
    Posts:
    3,039
    hah!
     
  39. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    It does too.. slides alot... I will address it by using a different physics model. Either break down and convert the Pacejka model over or use the CarPakke2 thing I found on the web for Unity, once you get either in, you are dealing with a more advanced model that helps you define what the tires do rather than just a reaction to movement as the WheelColliders seem to be.
     
  40. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,183
    WayPaths:

    OK, the first thing about AI is generally that we want to follow a track, or a set of way points around or ping ponged or whatever. Each of these sets of waypoints is called a WayPath. In this manner we can simply make a series of points around the track and let our vehicle follow one. (Were going to get a touch more advanced than that, but that is it in a nutshell)

    Each WayPath is of course made up of waypoints, each waypoint can have whatever data that you want to put in it to transfer to the AI that is running the course. I have seen this done many ways and what I propose is only one method. So lets look at where we begin:

    Code (csharp):
    1.  
    2. class Waypoint{
    3.     var start : Waypoint;
    4.     var next : Waypoint;
    5.     var last : Waypoint;
    6.     var checkpoint : float;
    7.    
    8.     var gameObject : GameObject;
    9.     var transform : Transform;
    10.    
    11.     function Waypoint(trans : Transform){
    12.         transform=trans;
    13.         gameObject=trans.gameObject;
    14.     }
    15.    
    16.     function Distance(obj : Transform){
    17.         return Vector3.Distance(obj.position, transform.position);
    18.     }
    19.    
    20.     function RaceDistance(obj : Transform, lap : int){
    21.         return lap * 100000 + checkpoint * 1000 + Distance(obj);
    22.     }
    23. }
    24.  
    Everything revolves around these Waypoints. Each point tells what is first, what is next and what is last. Using this method we can figure out where we are and where we are going. There are a couple of functions worth mentioning in here. The Distance function would give you the distance to the waypoint from the current distance of the transform that we give it. The RaceDistance is a amalgam of a principle I discussed a while back. It gathers distance based on the lap, checkpoint number and the distance to the waypoint. This can be used for distance checking on races.

    OK, the next piece of code we are going to look at is the builder:
    Code (csharp):
    1.  
    2. var wayPaths : Transform;
    3. private var waypaths : Array;
    4.  
    5. function setupWaypoints(wayMaster : Transform){
    6.     waypaths=Array();
    7.     var shaderText="Shader \"Simple Transparent\" {\n"+
    8.         "Properties {\n"+
    9.         "   _Color (\"Main Color\", COLOR) = (1,1,1,1)\n"+
    10.         "}\n\n"+
    11.         "SubShader {\n"+
    12.         "   Tags { \"Queue\" = \"Transparent\" }\n"+
    13.         "   Pass {\n"+
    14.         "       Material {Diffuse [_Color]}\n"+
    15.         "       Blend One SrcAlpha\n"+
    16.         "       Lighting On\n"+
    17.         "   }\n"+
    18.         "}}";
    19.     for(var wayObj : Transform in wayMaster){
    20.         waypaths.Add(Array());
    21.         var c=Color(Random.value, Random.value, Random.value, 0.5);
    22.         var start : Waypoint;
    23.         var last : Waypoint;
    24.         var i=0;
    25.         for(var way : Transform in wayObj){
    26.             var wp : Waypoint = Waypoint(way);
    27.             wp.checkpoint=i;
    28.             if(i==0)
    29.                 start=wp;
    30.             wp.start=start;
    31.             if(last)last.next=wp;
    32.             last=wp;
    33.             waypaths[waypaths.length-1].Add(wp);
    34.             i++;
    35.             if(way.collider) Destroy(way.collider);
    36.             if(way.renderer){
    37.                 way.renderer.material = new Material( shaderText );
    38.                 way.renderer.material.color = c;
    39.                 way.renderer.material.color=c;
    40.                 way.renderer.enabled=false;
    41.             }
    42.         }
    43.         waypaths[waypaths.length-1][0].last=wp;
    44.        
    45.         var script = wayObj.gameObject.AddComponent(Waypath);
    46.         script.waypoints=waypaths[waypaths.length-1];
    47.     }
    48. }
    49.  
    The basic principle of this is to loop through the children of an object and store them into a waypath for use in the game. As you can see it has a shader and render check that we will use later in our environment controller to display all the waypaths that we have in our scene.

    We destroy the collider as we are not going to use it in this method. We also create the start, next and last waypoints in our equation.

    (In hind site, I may convert the waypoints into spheres of the size needed to show the trigger. This will help in placing waypaths in the game.)

    The last thing we do in this script is assign a script to the WayPath object, and fill it's variable as we might need use it later.
    Code (csharp):
    1.  
    2. //Waypath.js
    3. var waypoints : Array;
    4.  
    5. function Update(){
    6. }
    7.  
    The next part is the part that will be more interesting to the AI people...
    Code (csharp):
    1.  
    2. function getNewWayPath(obj : Transform) : Waypoint{
    3.     if(waypaths.length==0) return null;
    4.     // must find a waypoint closests that is visible and in front.
    5.     for(var i=0; i<5; i++){
    6.         var path=waypaths[Random.value * waypaths.length];
    7.         var distance=Mathf.Infinity;
    8.         var ret : Waypoint;
    9.         for(var j=0; j<path.length; j++){
    10.             if(isVisible(obj, path[j].transform, 5.0)  isInFront(obj, path[j].transform)){
    11.                 var d=Vector3.Distance(obj.position, path[j].transform.position);
    12.                 if(d<distance){
    13.                     distance=d;
    14.                     ret=path[j];
    15.                 }
    16.             }
    17.         }
    18.         if(ret) return ret;
    19.     }
    20. }
    21.  
    22. function isVisible(fromObject : Transform, toObject : Transform, vOffset : float){
    23.     var hit : RaycastHit;
    24.     if(Physics.Linecast(fromObject.position + Vector3.up * vOffset,
    25.         toObject.position + Vector3.up * vOffset, hit)){
    26.         if(toObject.collider)
    27.             if(hit.collider==toObject.collider) return true;
    28.         return false;
    29.     }
    30.     return true;
    31. }
    32.  
    33. function isInFront(fromObject : Transform, toObject : Transform){
    34.     return Vector3.Dot(Vector3.forward, fromObject.InverseTransformPoint(toObject.position));
    35. }
    36.  
    In this code we check for a new waypath. We randomly pick a path, and find the nearest, visible node that is in front of us. We either return the Waypoint or nothing. The key is that if we return nothing long enough, we just reset ourselves back to the last Waypoint and continue on. (this will all make sense once we actually get to the AI stuff)

    There are two functions here that are incredibly useful later on down the road in any event. isVisible tests the from object to the to object and a vertical offset. This would clear things like ramps and stuff. By default I am looking for 5.0 units above the current object.

    The other function is isInFront. This tests the two object to see if it is in front... Yes it is only a Vector3.Dot, but I am lazy.

    NOTE: from my last check, none of this code gives error however, it may not work until everything is properly setup.
     
  41. Muzzn

    Muzzn

    Joined:
    Jan 23, 2011
    Posts:
    406
    Your code links aren't working...click on a few to check for yourself. Otherwise, great tutorial!
     
  42. LastBulliet

    LastBulliet

    Joined:
    Apr 4, 2011
    Posts:
    91
    Can someone team viewer me my car wont move at all and i followed it perfectly. Can someone help me out :(
     
  43. LastBulliet

    LastBulliet

    Joined:
    Apr 4, 2011
    Posts:
    91
    What am i doing wrong :(

    Here is the picture of the car I'm using ( lambo) and the wheel collier's

    [​IMG]

    Camera Settings

    [​IMG]

    My Errors

    [​IMG]
     
  44. carking1996

    carking1996

    Joined:
    Jun 15, 2010
    Posts:
    2,432
    try adding some power, brake, and steer.
     
  45. LastBulliet

    LastBulliet

    Joined:
    Apr 4, 2011
    Posts:
    91
    It is saying its moving... but its not???
     
  46. LastBulliet

    LastBulliet

    Joined:
    Apr 4, 2011
    Posts:
    91
    anyone at all?
     
  47. BloodGreen Studio

    BloodGreen Studio

    Joined:
    Dec 16, 2010
    Posts:
    48
    All the wheels need the WheelController script to be identified by the VehicleController
    That should work because your wheels arent powered by the input
     
  48. LastBulliet

    LastBulliet

    Joined:
    Apr 4, 2011
    Posts:
    91
    What do you mean? cause i dont get that you mean i need to put under wheels 4 then drag each wheel onto the element
     
  49. Rozik

    Rozik

    Joined:
    Nov 13, 2009
    Posts:
    3
    You have to make each wheel known to the Vehicle Contoller.
    There is an Array called Wheels. Just put all 4 Wheels in there.
     
  50. LastBulliet

    LastBulliet

    Joined:
    Apr 4, 2011
    Posts:
    91
    Okay one sec ill try it... one second.