Creating a Physic Vehicle.

How to create a physics based vehicle.

Requirements.


Physic model requirements.

The vehicle physic model is responsible for making an item move in a way similar to that of a car. This model works on a single item, it is enabled and configured on the car main item and that item is defined by convention as the vehicle chassis.

Assets requirements.


The bare minimum for a wheeled vehicle.

In order to display your vehicle you need at least a geometry for its chassis. For a wheeled vehicle you will also need a geometry for each of the vehicle wheels. If the front and rear wheel geometries are identical you can save space by reusing the front wheel geometries for the rear wheels.

For the sake of this tutorial Christophe Desse was kind enough to share one of his marvelous car models. François Gutherz also took the time to import and reduce its polygon count as the original is an offline model not meant to be used in realtime.

Scene Setup.


First download the base project for this tutorial by clicking the following link.

Download the tutorial base project.

Once downloaded, unzip the project files to your hard-drive, any place will do.
Launch the editor and open the provided project. Create a new 3D scene by going into the File menu of the editor, let's call it "Vehicle".


The New Scene wizard, click Finish to create the new scene.

After you click on finish the new scene is created and automatically opened.

Setting up the scene.

The first thing we need to do is instantiate the vehicle chassis in the scene. To do that we can simply drag'n'drop the file 'meshes/frozen_car_body.nmg' from the project explorer to the scene viewport. Make sure that the Geometry filter icon above the project explorer tree is clicked or you will not see any geometry file.


Click the geometry then drag it over the scene viewport.

Once you release your mouse button and drop the geometry over the viewport GameStart loads it, creates an item and assigns the geometry to this newly created item.

Chances are that you did not instantiate the geometry exactly at the center of the scene. While this does not make any difference we will edit the new item position numerically and put it at the center of the scene. The new item is already selected and its properties are displayed on the right side of the editor in the Properties window. From this window, edit the Transformation tab content and set all fields of the position vector to 0. You can press Tab to move from one field to the next.


The Item transformation tab.

While you are at that, go to the General tab of the Properties window and change this item name to Body.

Setting up the physic model.

Move to the Physics tab of this same Properties window and select Vehicle (Dynamic) as the item physic mode. New fields appear in the tab and a new Vehicle tab appears below this tab. The item physic mode is set but the item has no collision. So create a new Box collision shape by clicking the Add... button in the Physics tab. Adjust the box transformation and Mass so that it matches the following values: Position (m) { 0, 0.3, 0 }, Euler (°) { 0, 0, 0 }, Size { 2, 0.8, 5 } and Mass (Kg) 500.


A nice if simple collision rig.

Now is the time to test our goodness! Already ? Yes. Go ahead and press F5... We got that car falling alright. You can close the Debug window. Of course, with no ground to prevent the vehicle from free-falling we are not going to drive it anytime soon. Instantiate the 'cube_02.nmg' geometry and move its item to position (m) { 0, -14, 0 }. Set the physic mode of the newly created cube item to Static Collision (Static) and add new Box collision shape of Size (m) { 25, 25, 25 }.

Try a preview again by pressing F5. The car chassis now stops as expected, it is just missing wheels at this point. Close the Debug window.

Setting up the vehicle physic model.

Select back the Body item and go to its Vehicle property tab. Click the Add button to create a new wheel and select it from the list. Move it to Position (m) { 0.9, 0.15, 1.5 }. Now while this wheel is still selected click the Clone button. Select the newly created wheel and negate the X component of its position, effectively moving it to Position (m) { -0.9, -0.3, 1.5 }. It is very important that the wheel setup is perfectly balanced. Now select both wheels and click the Clone button again. For the two newly created wheels set the Z component of their position to -1.4.


The vehicle model, almost complete.

If you preview your work at this point you should see the car springs working. We will see about adjusting the spring values in a moment.

Communicating with the model.


Visualizing the model wheels.

In order to visualize the vehicle wheels we first need to instantiate their models in the scene. Drag'n'drop both the 'wheel_0.nmg' and the 'wheel_1.nmg' geometries two times each in order to create four wheel items. The wheel items position does not matter as the Vehicle model will provide the correct position for them automatically. So leave them that way.

Rename the first 'Wheel 0' item to 'WheelFR' (front right) and the second one to 'WheelRR' (rear right). Then rename the first 'Wheel 1' item to 'WheelFL' (front left) and the second one to 'WheelRL' (rear left).

Now that we can identify each wheel uniquely we have to query the Vehicle model for their transformation and send it to the corresponding item. To do that, we need to use a short script. In the scene explorer, select the Scene entry and in its Script property tab click the Add... button and select New.... Accept the default settings and press OK.

Note: We could add this script to the Body item itself, but doing that on the scene is in fact, much more interesting. You will know why by the end of this tutorial.

In the newly opened editor, paste the following code:


                          
  1. class Vehicle
  2. {
  3. body = 0
  4. wheels = 0
  5.  
  6. function OnUpdate(scene)
  7. {
  8. // For each wheel...
  9. for (local n = 0; n < 4; ++n)
  10. {
  11. // ...query the wheel matrix from the Vehicle model...
  12. local m = ItemPhysicVehicleGetWheelMatrix(body, n)
  13. // ...and update the wheel item matrix.
  14. ItemSetMatrix(wheels[n], m)
  15. }
  16. }
  17.  
  18. function OnSetup(scene)
  19. {
  20. // Store a reference to the Body item.
  21. body = SceneFindItem(scene, "Body")
  22.  
  23. // Store a reference to each wheel item in an array.
  24. wheels = []
  25. wheels.append(SceneFindItem(scene, "WheelFL"))
  26. wheels.append(SceneFindItem(scene, "WheelFR"))
  27. wheels.append(SceneFindItem(scene, "WheelRL"))
  28. wheels.append(SceneFindItem(scene, "WheelRR"))
  29. }
  30. }

                        

After saving the modified script, switch back to the Vehicle scene and press F5. The wheels are now under the car where they belong.

Adjusting the Vehicle model.

Select the Body item and go back to its Vehicle property tab. We will now edit each wheel values in the Vehicle model so that it fits the visual geometries used. Here is a brief description of the important properties of a wheel in the Vehicle physic model:

  • Friction: How much a wheel (its tire) resists lateral motion.
  • Radius: The tire radius in meters.
  • Rest length (m): Rest length of the suspension from the wheel position. This is the distance the spring will try to maintain at all times.
  • Max. Travel (m): The maximum offset from its rest length the suspension spring will travel.
  • Stiffness: How strong the suspension tries to go back to its rest length.
  • Damping: Limits the maximum travel speed of the suspension spring.

Note: From all these parameters the most difficult ones to understand and master are stiffness and damping. They work together, as you increase stiffness to make your suspension more nervous the car will start to jump around, increasing damping will limit this effect and preserve the stiffness of the suspension.

Select all four wheels and input the following values: Friction 1.5, Radius 0.485, Rest length 0.5, Max. Travel 2, Stiffness 22 and Damping 0.8. Preview the scene once again. The car now comes to rest in a much more natural way.

Driving time.

If you did not do it already, add a light to the scene by selecting Add/Light from the Scene menu. Select the scene entry from the Scene Explorer and in its Script property tab click the Edit vehicle.nut... button.

Paste the final version of the car controller script over the current content:


                          
  1. class Vehicle
  2. {
  3. body = 0
  4. wheel_items = 0
  5.  
  6. function OnUpdate(scene)
  7. {
  8. // Update wheel matrix from the physic model (mise a jour de la matrice des roues depuis le modele physique).
  9. ItemSetMatrix(wheel_items[0], ItemPhysicVehicleGetWheelMatrix(body, 0))
  10. ItemSetMatrix(wheel_items[1], ItemPhysicVehicleGetWheelMatrix(body, 1))
  11. ItemSetMatrix(wheel_items[2], ItemPhysicVehicleGetWheelMatrix(body, 3)) // Bullet uses a different ordering from our template.
  12. ItemSetMatrix(wheel_items[3], ItemPhysicVehicleGetWheelMatrix(body, 2))
  13.  
  14. local device = GetKeyboardDevice()
  15.  
  16. // Steering (direction).
  17. local steering = Deg(0)
  18. if (DeviceIsKeyDown(device, KeyLeftArrow))
  19. steering = Deg(-30)
  20. if (DeviceIsKeyDown(device, KeyRightArrow))
  21. steering = Deg(30)
  22.  
  23. ItemPhysicVehicleSetSteering(body, 0, steering)
  24. ItemPhysicVehicleSetSteering(body, 1, steering)
  25.  
  26. // Thrust and brake (acceleration et freins).
  27. local F = 0, B = 0;
  28.  
  29. if (DeviceIsKeyDown(device, KeyDownArrow))
  30. B = 35
  31. else
  32. if (DeviceIsKeyDown(device, KeyUpArrow))
  33. F = 1800
  34.  
  35. // Front-wheel traction (traction avant).
  36. ItemPhysicVehicleSetForce(body, 0, F)
  37. ItemPhysicVehicleSetForce(body, 1, F)
  38.  
  39. // 4 Wheels braking (freinage des 4 roues).
  40. for (local n = 0; n < 4; ++n)
  41. ItemPhysicVehicleSetBrake(body, n, B)
  42. }
  43.  
  44. function OnSetup(scene)
  45. {
  46. // Store a reference to the Body item.
  47. body = SceneFindItem(scene, "Body")
  48.  
  49. // Grab all wheel child items (recupere les item roues enfants de cet item).
  50. wheel_items = []
  51. wheel_items.append(SceneFindItem(scene, "WheelFL"))
  52. wheel_items.append(SceneFindItem(scene, "WheelFR"))
  53. wheel_items.append(SceneFindItem(scene, "WheelRL"))
  54. wheel_items.append(SceneFindItem(scene, "WheelRR"))
  55. }
  56. }

                        

Save the file, switch back to the scene and preview it. You can now drive the car using the keyboard arrows but take care, that playground is very small!

Broadening your horizons.


A terrain to drive on.

Create a new 3D scene and name it TestWorld. Create a new terrain by selecting Add/Terrain... from the Scene menu. Accept the default settings and click the Ok button. In the terrain item Physics property tab set its mode to Static Collision (Static). Add a new collision shape of type Terrain. Feel free to sculpt the terrain to your liking but try to go easy on the slopes, you will be driving this soon. Finally, add a light to the scene.

Bringing in the car(s).

Instantiate the Vehicle scene by drag'n'dropping it from the Project Explorer to the scene viewport. Adjust its position so that the car chassis lies above the terrain. Preview the scene, you can now safely exit that purple box area and drive onto the terrain.

Hint: By marking the Cube 02 and the New Light items as helper items from their General property tab in the Vehicle scene you can prevent them from being imported through a scene instance. They will however still be available when previewing the Vehicle scene directly.

Now instantiate the Vehicle scene a few more times by drag'n'dropping it over the viewport again and preview the result. Not too difficult right? While the same result can be achieved by scripting the Body item directly in the Vehicle scene, we need a way to locate the correct wheel items among those of all the Vehicle instances in the host scene item tree. When scripting the Vehicle scene and using scene functions to locate items GameStart automatically restrict its search to the instantiated scene items.

Results in motion.

Click here to download the completed tutorial from which the following video was taken.

Add a bit of polish and you will get pretty close to this.

Note: The complete project uses a different approach and scripts the Body item directly. In order to locate the correct wheel items for a given body when several vehicles are instantiated in an host scene the wheels are set as children of the Body item they belong to.

Comments

blc's picture

I have problem with second piece of code .. especially with "KeyboardUpdate()".
When running game with F5 then game stops with message "Error: the index 'KeyboardUpdate' does not exist".
I have GS build 1209 ,gsframework1.2.2 and Win7 x64 with qt4.7.4.

Emmanuel Julien's picture

I had forgotten to update the scripts in the tutorial... This is fixed now.
Thank you for the report!

blc's picture

Verry thanks for fast reply. I make something wrong, but now missing "Error: the index 'item' does not exist" smiley

Emmanuel Julien's picture

Sorry, it's fixed now, I had to readapt the final sample to the tutorial as both versions differ a bit and I made a mistake. Should be ok now.

blc's picture

Now all perfect working ... very thanks for this tutorial.
Any idea about making tank tracks?

Emmanuel Julien's picture

You are welcome. You could simulate a tank using a similar vehicle setup. Probably with more than 4 wheels, you could use 8 or 10 wheels and use the wheel objects to control the position of the tank thread (a skinned object whose bones are the wheels and animated through UV scrolling?). That would give very realistic interactions with the ground but the setup involved is complex.

It really depends on the level of realism you aim for and the control you have over the models you use. I think that you can get fairly good results with a 4 wheeled model already.

blc's picture

Yes i use more than 4 whells, but i dont have idea how i make joint on whells for mesh of track. I use UV map skin with move. Level of realism is not big ... now only im need understand technigue tank tracks. Maybye later im make something better.