Get access to over 100 FireMonkey cross platform samples for Android, IOS, OSX, Windows, and Linux!

AndroidAppmethodCode SnippetDelphiDemoFiremonkeyIOSOSXWindows

Box2d Firemonkey Theo Jansen Walker Demo For Delphi XE6 Firemonkey On Android And IOS

| Delphi 11 10 XE8 XE7 XE Seattle Berlin Tokyo Rio Firemonkey Delphi Android Delphi IOS

Delphi XE6 Firemonkey Box2d Theo Jansen Walker | Delphi 11 10 XE8 XE7 XE Seattle Berlin Tokyo Rio Firemonkey Delphi Android Delphi IOSOne of the demos in the TestBad application that comes with the Box2d Firemonkey physics engine project is a demo called Theo Jansen Walker. This demo should work in Delphi XE5, Delphi XE6, and AppMethod. It should also work cross platform on Android, IOS, Windows, and OSX. The walker is a pretty complex physics object built up of a chassis and legs. It basically looks like a spider and is actually a representation of a Strandbeest. From what I can gather about it on the Wikipedia entry a Strandbeest is self propelled based on it’s interactions with it’s environment. That being said it could easily be modified for use in a game. The walker has six legs that move it around. When you load up the physics simulation the walker will automatically start walking towards the right side of the screen. However, you can also use the keyboard to make the walker walk left and right. Here is the sample code of the code needed to create the chassis:
   // Chassis
begin
shape := Tb2PolygonShape.Create;
shape.SetAsBox(2.5, 1.0);

sd := Tb2FixtureDef.Create;
sd.density := 1.0;
sd.shape := shape;
sd.filter.groupIndex := -1;
bd := Tb2BodyDef.Create;
bd.bodyType := b2_dynamicBody;
{$IFDEF OP_OVERLOAD}
bd.position := pivot + m_offset;
{$ELSE}
bd.position := Add(pivot, m_offset);
{$ENDIF}
m_chassis := m_world.CreateBody(bd);
m_chassis.CreateFixture(sd);
end;

begin
cshape := Tb2CircleShape.Create;
cshape.m_radius := 1.6;

sd := Tb2FixtureDef.Create;
sd.density := 1.0;
sd.shape := cshape;
sd.filter.groupIndex := -1;
bd := Tb2BodyDef.Create;
bd.bodyType := b2_dynamicBody;
{$IFDEF OP_OVERLOAD}
bd.position := pivot + m_offset;
{$ELSE}
bd.position := Add(pivot, m_offset);
{$ENDIF}
m_wheel := m_world.CreateBody(bd);
m_wheel.CreateFixture(sd);
end;

begin
jd := Tb2RevoluteJointDef.Create;
{$IFDEF OP_OVERLOAD}
jd.Initialize(m_wheel, m_chassis, pivot + m_offset);
{$ELSE}
jd.Initialize(m_wheel, m_chassis, Add(pivot, m_offset));
{$ENDIF}
jd.collideConnected := False;
jd.motorSpeed := m_motorSpeed;
jd.maxMotorTorque := 400.0;
jd.enableMotor := m_motorOn;
m_motorJoint := Tb2RevoluteJoint(m_world.CreateJoint(jd));
end;

{$IFDEF OP_OVERLOAD}
wheelAnchor := pivot + MakeVector(0.0, -0.8);
{$ELSE}
wheelAnchor := Add(pivot, MakeVector(0.0, -0.8));
{$ENDIF}

CreateLeg(-1.0, wheelAnchor);
CreateLeg(1.0, wheelAnchor);

m_wheel.SetTransform(m_wheel.GetPosition, 120.0 * Pi / 180.0);
CreateLeg(-1.0, wheelAnchor);
CreateLeg(1.0, wheelAnchor);

m_wheel.SetTransform(m_wheel.GetPosition, -120.0 * Pi / 180.0);
CreateLeg(-1.0, wheelAnchor);
CreateLeg(1.0, wheelAnchor);

As you can see at the bottom it uses a function called CreateLeg to create each of the six legs. Here is the source code for the CreateLeg procedure:
procedure TJansenWalker.CreateLeg(s: PhysicsFloat; const wheelAnchor: TVector2);
var
p1, p2, p3, p4, p5, p6: TVector2;
vertices: array[0..2] of TVector2;
poly1, poly2: Tb2PolygonShape;
fd1, fd2: Tb2FixtureDef;
bd1, bd2: Tb2BodyDef;
body1, body2: Tb2Body;
djd: Tb2DistanceJointDef;
rjd: Tb2RevoluteJointDef;
begin
p1 := MakeVector(5.4 * s, -6.1);
p2 := MakeVector(7.2 * s, -1.2);
p3 := MakeVector(4.3 * s, -1.9);
p4 := MakeVector(3.1 * s, 0.8);
p5 := MakeVector(6.0 * s, 1.5);
p6 := MakeVector(2.5 * s, 3.7);

fd1 := Tb2FixtureDef.Create;
fd2 := Tb2FixtureDef.Create;
fd1.filter.groupIndex := -1;
fd2.filter.groupIndex := -1;
fd1.density := 1.0;
fd2.density := 1.0;
poly1 := Tb2PolygonShape.Create;
poly2 := Tb2PolygonShape.Create;

if s > 0.0 then
begin
vertices[0] := p1;
vertices[1] := p2;
vertices[2] := p3;
poly1.SetVertices(@vertices[0], 3);

vertices[0] := b2Vec2_zero;
{$IFDEF OP_OVERLOAD}
vertices[1] := p5 - p4;
vertices[2] := p6 - p4;
{$ELSE}
vertices[1] := Subtract(p5, p4);
vertices[2] := Subtract(p6, p4);
{$ENDIF}
poly2.SetVertices(@vertices[0], 3);
end
else
begin
vertices[0] := p1;
vertices[1] := p3;
vertices[2] := p2;
poly1.SetVertices(@vertices[0], 3);

vertices[0] := b2Vec2_zero;
{$IFDEF OP_OVERLOAD}
vertices[1] := p6 - p4;
vertices[2] := p5 - p4;
{$ELSE}
vertices[1] := Subtract(p6, p4);
vertices[2] := Subtract(p5, p4);
{$ENDIF}
poly2.SetVertices(@vertices[0], 3);
end;

fd1.shape := poly1;
fd2.shape := poly2;

bd1 := Tb2BodyDef.Create;
bd1.bodyType := b2_dynamicBody;
bd1.position := m_offset;
bd2 := Tb2BodyDef.Create;
bd2.bodyType := b2_dynamicBody;
{$IFDEF OP_OVERLOAD}
bd2.position := p4 + m_offset;
{$ELSE}
bd2.position := Add(p4, m_offset);
{$ENDIF}

bd1.angularDamping := 10.0;
bd2.angularDamping := 10.0;

body1 := m_world.CreateBody(bd1);
body2 := m_world.CreateBody(bd2);

body1.CreateFixture(fd1);
body2.CreateFixture(fd2);

djd := Tb2DistanceJointDef.Create;
// Using a soft distance constraint can reduce some jitter.
// It also makes the structure seem a bit more fluid by
// acting like a suspension system.
djd.dampingRatio := 0.5;
djd.frequencyHz := 10.0;

{$IFDEF OP_OVERLOAD}
djd.Initialize(body1, body2, p2 + m_offset, p5 + m_offset);
{$ELSE}
djd.Initialize(body1, body2, Add(p2, m_offset), Add(p5, m_offset));
{$ENDIF}
m_world.CreateJoint(djd, False);

{$IFDEF OP_OVERLOAD}
djd.Initialize(body1, body2, p3 + m_offset, p4 + m_offset);
{$ELSE}
djd.Initialize(body1, body2, Add(p3, m_offset), Add(p4, m_offset));
{$ENDIF}
m_world.CreateJoint(djd, False);

{$IFDEF OP_OVERLOAD}
djd.Initialize(body1, m_wheel, p3 + m_offset, wheelAnchor + m_offset);
{$ELSE}
djd.Initialize(body1, m_wheel, Add(p3, m_offset), Add(wheelAnchor, m_offset));
{$ENDIF}
m_world.CreateJoint(djd, False);

{$IFDEF OP_OVERLOAD}
djd.Initialize(body2, m_wheel, p6 + m_offset, wheelAnchor + m_offset);
{$ELSE}
djd.Initialize(body2, m_wheel, Add(p6, m_offset), Add(wheelAnchor, m_offset));
{$ENDIF}
m_world.CreateJoint(djd);

rjd := Tb2RevoluteJointDef.Create;
{$IFDEF OP_OVERLOAD}
rjd.Initialize(body2, m_chassis, p4 + m_offset);
{$ELSE}
rjd.Initialize(body2, m_chassis, Add(p4, m_offset));
{$ENDIF}
m_world.CreateJoint(rjd);
end;

Download the Box2d Firemonkey physics engine and demos to check out the Theo Jansen Walker.

Or check out the full source code for the Theo Jansen Walker test web demo on Github.

Have Delphi Firemonkey questions? Ask and get answers on StackOverflow.

Related posts
DelphiDemoFiremonkeyLinuxOSXShowcaseWindows

AutoBlogAI: FireMonkey Client To Leverage LLMs And Generative AI For Blogging

DelphiFiremonkeyShowcaseUtilityWindows

Unleashing Creativity With Song Writer AI: A Deep Dive

DelphiFiremonkeyShowcaseWindows

How To Build Stable Diffusion Text To Image Prompts

AndroidC++BuilderDelphiFiremonkeyIOSOSXWindows

FireMonkey 10.4.2 Features Updated iOS 14, Android 11, And macOS 11 Support Plus Hundreds Of Fixes

Sign up for our Newsletter and
stay informed

Leave a Reply