Click here to Skip to main content
15,880,427 members
Articles / Mobile Apps / iOS

Box 2d vehicles - part 1

Rate me:
Please Sign up or sign in to vote.
4.89/5 (12 votes)
23 Aug 2012BSD4 min read 29.3K   1.4K   22  
How to create nice car using box2d?

Introduction

This article shows how to create a car game; the concept of this game is very popular and used in many games. To create a game with a realistic physical behavior we used box2d physical engine. The final code in this article can be implemented in your own complete game. This code was written in object oriented JavaScript used for cross-platform development called Moscrif, but box2d is ported to many other programming languages and its usage is very similar. Video with this project is available also on youtube.

Box2d engine 

The box2d physical engine offers realistic physical simulation. It shows performance in many devices like Nintendo Wii, DS and several mobile phones (including Android and iPhone) as well as most major operating systems.

Box2d joints

All physical elements are created as box2d bodies, which interact in the box2d world and are connected together with joints. Many types of joints are supported: distance, friction, gear, mouse, prismatic, revolute, weld etc... 

Every joint connects two bodies together and allows some type of movement. In this sample we use prismatic, revolute and mouse joints.

  • The prismatic joint allows for relative translation of two bodies along a specified axis. Prismatic joint prevents relative rotation between the bodies.
  • The revolute joint allows relative rotation of two bodies around an anchor point.
  • Mouse joint is used only to connect the wheels and chassis to deny the contacts between these bodies.

Image: prismatic and revolute joint 

Image 1

Sometimes, it is unwanted to allow joint’s movement on the whole range. To restrict the joint movement we can use joint’s limit. Also, motor can be applied onto joints to drive the motion of the connected bodies according to the joint's degrees of freedom.

Car

Car consists of five bodies, the chassis, wheels, and dampers (suspensions). All bodies are partially dynamic which means that they interact with other static or dynamic bodies and are fully simulated – moves under forces and velocity. Dampers are only small bodies, which are not visible. They only provide connection between prismatic and revolute joint. The dampers move top-down by prismatic joint and wheels are connected onto dampers by revolute joint, which allows them to rotate around they center. The wheels are the part of the car which is in contact with the ground. Their friction (together with friction of the ground) affects the car adhesion

In our sample all cars’ features are provided by Car class. The create function creates the new car.

Example: create all car’s bodies

C++
function create(scene, x, y)
{
    var damperHeight = 8*this._images.wheel.width * this._scale/10;
    var wheelDistance = 7 * this._images.body.width*this._scale / 10;
 
    // create bodies:
    this._body = scene.addPolygonBody(this._images.body, #dynamic, 0.1, 0.0, 0.0, this._images.body.width*this._scale, this._images.body.height*this._scale);
    this._body.z = 2;
    this._body.scale = this._scale;
    this._body.setPosition(x, y);
    // FRONT
    this._frontDamper = scene.addPolygonBody(null, #dynamic, 10.0, 0.0, 0.0, 2, this._images.wheel.width / 2 * this._scale);
    this._frontDamper.setPosition(x + wheelDistance / 2, y + damperHeight - this._images.wheel.width / 4 * this._scale);
 
    this._frontWheel = scene.addCircleBody(this._images.wheel, #dynamic, 0.1, 0.4, 0.0, this._images.wheel.width / 2 * this._scale);
    this._frontWheel.scale = this._scale;
    this._frontWheel.setPosition(x + wheelDistance / 2, y + damperHeight);
 
    // BACK
    this._backDamper = scene.addPolygonBody(null, #dynamic, 10.0, 0.0, 0.0, 2, this._images.wheel.width / 2 * this._scale);
    this._backDamper.setPosition(x - wheelDistance / 2, y + damperHeight - this._images.wheel.width / 4 * this._scale);
 
    this._backWheel = scene.addCircleBody(this._images.wheel, #dynamic, 0.1, 0.4, 0.0, this._images.wheel.width / 2 * this._scale);
    this._backWheel.scale = this._scale;;
    this._backWheel.setPosition(x - wheelDistance / 2, y + damperHeight);
    ...  JOINTS ....

All bodies are connected together with joints. The dampers are connected with chassis by prismatic joint. Limit and motor are applied onto prismatic joint. The limits restrict the upper and lower joint transition. The upper transition is the lowest position of wheel with fully extended suspensions and lower transition represents opposite position.

Prismatic joint also uses motor to drive the vertical motion of suspensions. The motor’s maximum force is lower than force, which affects the wheel when they hit a barrier, but larger then gravity force onto one wheel, which causes that the wheel nicely passes all barriers.

The revolute joint is used to turn the wheels around the centre. There is motor applied onto revolute joint with sufficient force to move the car. The motor speed is later changed according to the user events.

Image: joints

Image 2

Example: create joints

C++
    // JOINTS
    // prismatic joins
    var jointDef = {
        lowerTranslation    : -3 * (damperHeight / scene.scale) / 10, //(damperHeight / 5) / scene.scale,  /*meters*/
        upperTranslation    : 0.0,  /*meters*/
        enableLimit         : true,
        enableMotor         : true,
        motorSpeed          : 2.5,
        maxMotorForce       : this._body.getMass() * 8.5,
    }
    this._joints.push(scene.createPrismaticJoint(this._frontDamper, this._body, x + wheelDistance / 2, y, 0.0, 1.0, 0.0, jointDef, false));
    this._joints.push(scene.createPrismaticJoint(this._backDamper, this._body, x - wheelDistance / 2, y, 0.0, 1.0, 0.0, jointDef, false));
 
    // revolute joints
    jointDef = {
        enableMotor     : true,         // enable motor
        maxMotorTorque  : 1500000,         // maximum torque
        motorSpeed      : 0.0,         // it is changed latery*/
    }
   this._motorJoint = scene.createRevoluteJoint(this._frontDamper, this._frontWheel, x + wheelDistance / 2, y + damperHeight, jointDef, false);
   this._motorJointB = scene.createRevoluteJoint(this._backDamper, this._backWheel, x - wheelDistance / 2, y + damperHeight, jointDef, false);
 
   this._joints.push(this._motorJoint);
   this._joints.push(this._motorJointB);
   this._joints.push(scene.createMouseJoint(this._body, this._frontWheel, null, false));
   this._joints.push(scene.createMouseJoint(this._body, this._backWheel, null, false));
}

The car can speed up or down by changing the speed of motor on revolute joint.

Example: speed up

C++
function speedUp()
{
    // check if motors does not have maximum speed
    if (this._motorJoint.motorSpeed > -12*Math.PI) {
        // speed motors up
        this._motorJoint.motorSpeed -= this._speedStep;
        this._motorJointB.motorSpeed -= this._speedStep;
    }
}

Scene

The car scene contains many small hurdles to show how suspensions work. The hurdles are small rectangles, which are randomly distributed on the whole scene. There are also three jumps in the scene. The scene, wherein car moves, is usually larger then device’s screen. It means that we need to scroll the scene horizontally or vertically. To scroll the scene we can scroll canvas onto which it is drawn. The canvas is scrolled in draw method.

Example: draw scene onto scrolled canvas

C++
function draw(canvas)
{
    // draw background
    canvas.drawRect(0, 0, System.width, System.height, this._bg);
    // save default canvas state (without translation)
    canvas.save();
    // translate canvas
    canvas.translate(this._translateX, this._translateY);
    this._x += this._translateX;
    this._translateX = 0;
    // draw all scene elements
    super.draw(canvas);
     // restore default canvas state (without translation)
    canvas.restore();
}
The variable ._translateX and ._translateY are updated in process function which is called every about 25ms. This function checks current position of the car and updates the translate variables.

Example: update translate variabes

C++
// reaction to onproces event (repeates about every 25 miliseconds)
function process()
{
   var (x, y) = this._car.getPosition();
 
    if (true) {
        this._translateX = -1*((x) - (4*System.width / 10));
        this.menu.translateX = this._translateX;
    }
    if (y < 2*System.height / 10) {
        this._translateY = -1*(y - 2*System.height / 10);
        this.menu.translateY = this._translateY;
    }
    if (y > 8*System.height / 10) {
        this._translateY = 1*(y - 8*System.height / 10);
        this.menu.translateY = this._translateY;
    }
    // create step in physics world
    this.step(1.0/40.0);
}

Improvements

This article is the first part, which shows how to make basic box2d car. The appearance can be better by using vector graphics instead of bitmaps. The vector graphics ensures smooth graphics onto all resolutions, because it preserves details also after resizing.

Summary

This article shows how to create a car truck game based on physical engine box2d. The result is a free game draft, which you can download for free and use in your projects. The box2d is ported to many programming languages like: C++, Java, Adobe Flash, C#, JavaScript etc. With these languages you can create this game but probably the best way how to create this game for three platforms with only one code is using Moscrif.

License

This article, along with any associated source code and files, is licensed under The BSD License


Written By
Slovakia Slovakia
Author develops in various programming languages included: C++, Javascript, and PHP. Last year he creates mobile cross platform applications in Moscrif SDK.

Comments and Discussions

 
-- There are no messages in this forum --