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

  

One 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.

Comments are closed.