Using the Box2D Physics Engine

The Box2D physics engine is available for several languages including Smart Pascal, for which we have written a tutorial section to help you to get started. The official documentation is for Erin Catto's C++ original and this C++ tutorial is most useful. (See our tutorial C/C++ after Pascal for help with the syntax).

A Lazarus version of Box2D, which requires no installation, is available in (15.4 MB) from this GitHub page. Unzip the box2D Lazarus Package 2.3.0 folder to a convenient location and open Demos\TestBed\TestBed.lpi in a recent version of Lazarus. Type CTRL+F9 to compile and execute TestBed.exe directly if the application will not run in the debugger. (We used this method for all of our Box2D programs).

We could run most the tests (in a list box at the top right corner of the screen) using where necessary instructions at the left of the screen. Be prepared for a delay after you have clicked on the name of a test. If you receive an error message about an access violation, restart the test bed and click on the failed test name before any other. (We could not run the test Collision Filtering even after a restart). Try Dominos.

The source code of the tests is very helpful, and you should understand some of the 20000 lines of Pascal code in the game engine. See below a simple test based on our Smart Pascal demonstration of a rectangle in a box. You can use the mouse to throw the rectangle and to impart spin.

Note the following points when writing your own tests for the test bed.

  • Y increases up the screen in Box2D in Lazarus.
  • Add your test to the uses clause of TestBed.dpr. You may find it helpful to remove existing tests as shown below.
  • Use SHIFT+F11 to add the current file (your test) to the project if necessary and accept the invitation to add its folder to search path.
  • You can check that your test is compiling by checking the date and time of the .ppu and .o files for your test (in the TestBed\lib\i386-win32 folder. You can remove the files if necessary to ensure recompilation. (This should not be a problem if you have added the file to the project).

See the following pages for examples that do not use the test bed.

Code of simple test

unit UTrial;

{$I ..\..\Physics2D\}

   UMain, UPhysics2DTypes, UPhysics2D, SysUtils;

   TTrial = class(TTester)
     constructor Create; override;


constructor TTrial.Create;
  WIDTH = 200;
  HEIGHT = 200;
  SCALE = 10;
  BW = 0.5; //Border width
  MOB_WIDTH = 3;
  FRICTION = 0.5;
  FBody, FFloor: Tb2Body;
  FixtureDef: Tb2FixtureDef;
  BodyDef : Tb2BodyDef;
  // Create fixture definition (used to describe fixture objects)
  FixtureDef := Tb2FixtureDef.Create;
  FixtureDef.Density := 1.0;
  FixtureDef.Friction := FRICTION;
  FixtureDef.Restitution := RESTITUTION;
  // Create body definition class (used to describe body objects)
  BodyDef := Tb2BodyDef.Create;
  BodyDef.BodyType := b2_StaticBody;
  // Create the surrounding bars.
  FixtureDef.Shape := Tb2PolygonShape.Create;
  Tb2PolygonShape(FixtureDef.Shape).SetAsBox(0.5 * WIDTH / SCALE, BW / 2);
  BodyDef.Position := MakeVector(0.5 * WIDTH / SCALE, BW / 2);
  FFloor := m_world.CreateBody(BodyDef, False);
  FFloor.CreateFixture(FixtureDef, False, False, False); // Bottom horizontal bar
  BodyDef.Position := MakeVector(0.5 * WIDTH / SCALE, HEIGHT / SCALE - BW / 2);
  m_world.CreateBody(BodyDef, False).CreateFixture(FixtureDef, False, False, False); // Top horizontal bar
  Tb2PolygonShape(FixtureDef.Shape).SetAsBox(BW / 2, 0.5  * HEIGHT / SCALE);
  BodyDef.Position := MakeVector(BW / 2, 0.5 * HEIGHT / SCALE);
  m_world.CreateBody(BodyDef, False).CreateFixture(FixtureDef, False, False, False);  // Left vertical bar
  BodyDef.Position := MakeVector(WIDTH / SCALE - BW / 2, 0.5 * HEIGHT / SCALE);
  m_world.CreateBody(BodyDef, False).CreateFixture(FixtureDef, False, False, False);  // Right vertical bar
  // Create a rectangular dynamic object.
  BodyDef := Tb2BodyDef.Create;
  BodyDef.BodyType := b2_DynamicBody;
  Tb2PolygonShape(FixtureDef.Shape).SetAsBox(MOB_WIDTH / 2, MOB_HEIGHT / 2);
  BodyDef.Position := MakeVector(10, HEIGHT / SCALE - MOB_HEIGHT / 2 - BW);
  FBody := m_world.CreateBody(BodyDef, False);

   RegisterTestEntry('Trial', TTrial);

Code of Testbed.dpr for a single test

program TestBed;

  Forms, Interfaces,
  UMain in 'UMain.pas' {frmMain},
  UOpenGLCanvas in '..\..\OpenGL Canvas\UOpenGLCanvas.pas',
  MSTimer in '..\..\Physics2D\MSTimer.pas',
  UPhysics2D in '..\..\Physics2D\UPhysics2D.pas',
  UPhysics2DControllers in '..\..\Physics2D\UPhysics2DControllers.pas',
  UPhysics2DHelper in '..\..\Physics2D\UPhysics2DHelper.pas',
  UPhysics2DPolygonTool in '..\..\Physics2D\UPhysics2DPolygonTool.pas',
  UPhysics2DTypes in '..\..\Physics2D\UPhysics2DTypes.pas',
  UDump in 'UDump.pas' {frmDump},
  UTrial in 'Tests\UTrial.pas';

{$R *.res}

  Application.CreateForm(TfrmMain, frmMain);

Programming - a skill for life!

Using SDL, Box2D or the GLScene or Castle Game Engine to write games in Pascal