Using Box2D in Delphi Applications

From RAD Studio
Jump to: navigation, search

Go Up to Box2D

This topic explains how to use Box2D in Delphi applications.

Configuring Your Application to Use Box2D

RAD Studio does not provide prebuilt .dcu files for the Box2D Delphi units. To be able to build a Delphi project that contains Box2D units in its uses clause, you must configure the search path of your project so that RAD Studio can find the Box2D units.

To configure the search path of your Delphi project so that RAD Studio can find the Box2D units:

  1. Select Project > Options > Delphi Compiler.
  2. Add $(BDS)\source\FlatBox2D to the Search Path field.

You can now add references to these units in your code so that you can use Box2D.

Using Box2D

The Delphi bindings for Box2D are based on the C++ API; however there are some notable differences.

Note: To use the Delphi bindings for Box2D, you should be familiar with pointers and extended identifiers.

Delphi Mapping of Box2D Classes

The Delphi bindings for Box2D expose Box2D classes in either of the following ways:

  • As a record with the original name of the Box2D class. See Using Box2D Records.
  • As a record with the original name of the Box2D class suffixed with Wrapper. For example, the wrapper of b2World would be b2WorldWrapper. See Using Box2D Wrapper Records.

In both cases, unlike with regular Delphi records, it is not enough to declare these Box2D records to create them. You must call their Create procedure to ensure that their members have the right default values. If you declare a record and do not call Create, the default values of is members may not match those that Box2D defines.

groundBodyDef := b2BodyDef.Create;

Using Box2D Records

The Delphi bindings for Box2D provide most Box2D classes as records. The only exceptions are classes exposed as wrapper records and listener classes.

Using Box2D Wrapper Records

The Delphi bindings for Box2D provide the following wrapper records:

  • b2BlockAllocatorWrapper
  • b2BodyWrapper
  • b2BroadPhaseWrapper
  • b2ChainAndCircleContactWrapper
  • b2ChainAndPolygonContactWrapper
  • b2ChainShapeWrapper
  • b2CircleContactWrapper
  • b2CircleShapeWrapper
  • b2ContactWrapper
  • b2ContactManagerWrapper
  • b2ContactSolverWrapper
  • b2DistanceJointWrapper
  • b2DrawWrapper
  • b2DynamicTreeWrapper
  • b2EdgeAndCircleContactWrapper
  • b2EdgeAndPolygonContactWrapper
  • b2EdgeShapeWrapper
  • b2FrictionJointWrapper
  • b2GearJointWrapper
  • b2IslandWrapper
  • b2JointWrapper
  • b2MotorJointWrapper
  • b2MouseJointWrapper
  • b2PolygonAndCircleContactWrapper
  • b2PolygonContactWrapper
  • b2PolygonShapeWrapper
  • b2PrismaticJointWrapper
  • b2PulleyJointWrapper
  • b2RevoluteJointWrapper
  • b2RopeWrapper
  • b2RopeJointWrapper
  • b2ShapeWrapper
  • b2StackAllocatorWrapper
  • b2WeldJointWrapper
  • b2WheelJointWrapper
  • b2WorldWrapper

Freeing Box2D Records and Record Wrappers

The only Box2D records or record wrappers that you must free are instances of b2WorldWrapper. The destructor of b2WorldWrapper frees any memory allocated by bodies, fixtures, or joints in the b2WorldWrapper object.

The exceptions to this rule are:

  • the ShapeWrappers.
  • other Wrappers that you explicitly construct and that are destroyed in C++.

Box2D listeners are also an exception to this rule.

Defining Box2D Listeners

Box2D defines some listener classes. When you are using C++, you can create a subclass of a listener, create an instance of your subclass and register your listener object in some Box2D object, such as a world (b2World).

To create a Box2D listener object of a certain type in Delphi, you must define a custom class that implements the interface of the target Box2D listener class. The interface of a Box2D listener class is named as the Box2D listener class but prefixed with a capital I. For example, Ib2ContactListener is the interface of the b2ContactListener Box2D listener class.

TMyContactListener = class (TInterfacedObject, Ib2ContactListener)
  procedure BeginContact(contact: NativeUInt); cdecl;
  procedure EndContact(contact: NativeUInt); cdecl;
  procedure PostSolve(contact: NativeUInt; impulse: Pb2ContactImpulse); cdecl;
  procedure PreSolve(contact: NativeUInt; oldManifold: Pb2Manifold); cdecl;

Once you have a class that implements the target listener interface, you must create an instance of that class.

myContactListener := TMyContactListener.Create;

Listener setters cannot handle your listener object directly. Instead you must obtain a delegate (of type NativeUInt) for your listener object and pass that delegate to the listener setter. Use Create_<listener class>_delegate to create a delegate of your listener object.

myContactListenerHandle := Create_b2ContactListener_delegate(myContactListener);

After you destroy the Box2D world, you can destroy your listener object by passing its handle to Destroy_<listener class>_delegate.


Deploying Your Application

On desktop platforms, you must distribute the RAD Studio Box2D dynamic library along with your application.

The RAD Studio Box2D dynamic library file is available at:

  • 32-bit Windows: C:\Program Files (x86)\Embarcadero\Studio\22.0\bin\FlatBox2DDyn.dll
  • 64-bit Windows: C:\Program Files (x86)\Embarcadero\Studio\22.0\bin64\FlatBox2DDyn.dll
  • 64-bit macOS: C:\Program Files (x86)\Embarcadero\Studio\22.0\binosx64\libFlatBox2DDyn.dylib

Add this library file to the Deployment Manager for each of the target platforms that your application supports, so that when you deploy your application for any desktop platform, the RAD Studio Box2D dynamic library file is included among the deployed files of your application.

See Also