How to make custom/concave polygons in Farseer.BMX

One of the major strengths of farseer is the ability to create concave polygons and have them collide with each other in a realistic manner. This How-to will walk you through on how to easily construct a concave polygon in Blitzmax code. Once complete, you’ll have a concave polygon that can be manipulated by the left and right buttons of the mouse and collides against a floor physics object.

Requirements:
Farseer.BMX physics module
– Blitzmax IDE and compiler

So let’s begin by creating a blank bmx file in your editor of choice.

1. Import the needed libraries and declare our globals

At the top of your bmx file type in the following:

[blitzmax2]
SuperStrict
Import aco.farseerphysics

Global physicsEngine:TPhysicsSimulator
Global body:TBody
Global geometry:TGeom
Global floorBody:TBody
Global floorGeom:TGeom
[/blitzmax2]
This’ll give us access to the needed farseer physics library. We’re using global variables for simplicity here. The physicsEngine variable is a reference to the farseer physics engine. “body” and “geometry” are references to our custom polygon we will be constructing. “floorbody” and “floorGeom” are references for a floor object we’ll insert in the scene also, so our polygon has something to bounce and collide against.

Note: using lots of globals is most likely not the way you want to go about coding more complex games in the future, many tutorials and examples tend to take ‘shortcuts’ in good code design to help make it easier to follow the relevant code in that particular article.

2. Initialize our graphics object

[blitzmax2]
‘init our graphics
Graphics(800, 600, 0, 60)
[/blitzmax2]
Pretty straightforward there…

3. Call our initialization function to setup the physic engine

[blitzmax2]
‘init the engine
InitPhysics()
[/blitzmax2]
We’ve yet to implement this function so trying to compile now will result in a compile error. I tend to leave my function implementation details towards the bottom of the file while having the high-level main loop code declared at the top….

4. Write our main loop for drawing and upating

[blitzmax2]
While Not(KeyDown(KEY_ESCAPE))
Update()
Cls
Draw()
Flip
Wend
[/blitzmax2]
Update() and Draw() are not implemented yet and will be defined after we define our ‘InitPhysics()’ function below…

5. Stub out our InitPhysics() function

[blitzmax2]
Function InitPhysics()

End Function
[/blitzmax2]
Now that we’ve stubbed out our InitPhysics() function we can implement the details…

6. Declare our physics engine and create custom vertices

Put the following inside InitPhysics()…
[blitzmax2]
physicsEngine = TPhysicsSimulator.Create(Vector2.Create(0, 100))
‘ now lets create some custom polygon with vertices
Local vertices:TVertices = New TVertices
vertices.Add(Vector2.Create(0, 0))
vertices.Add(Vector2.Create(0, 100))
vertices.Add(Vector2.Create(50, 100))
vertices.Add(Vector2.Create(25, 50))
vertices.Add(Vector2.Create(200, 0))
[/blitzmax2]
We initialize our physics engine with a set gravity of 100 in the downward direction. Afterwards, we create a custom vertex array with some random points that will define the shape of our polygon. This is where farseer shines because you an define just about any shape you wish with this technique and the physics will ‘just work’ once added to the physics engine.

7. Create the body and geometry of our custom polygon

Put the following inside InitPhysics()…
[blitzmax2]
‘ create the body with the vertices
body = TBodyFactory.CreatePolygonBody(physicsEngine, vertices, 1)

‘ create the geometry with vertices
geometry = TGeomFactory.CreatePolygonGeom(physicsEngine, body, vertices)

‘now lets move our body to somewhere else on the screen
body.SetPosition(Vector2.Create(300, 300))
[/blitzmax2]
As you can see, we pass the vertices object to our body and geometry, and farseer will internally construct the needed properties and data for the physics object to act correctly. At the end we set our body to a position that is near the center of the screen.

8. Create a floor

At the bottom of our InitPhysics() function we add…

[blitzmax2]
‘lets create a floor for our body to collide against
floorBody:TBody = TBodyFactory.CreateRectangleBody(physicsEngine, 800, 100, 1)
floorBody.SetStatic(True) ‘ this makes our floor unmovable
floorBody.SetPosition(Vector2.Create(400, 550)) ‘ put our floor at the bottom of the screen

floorGeom:TGeom = TGeomFactory.CreateRectangleGeom(physicsEngine, floorBody, 800, 100)
[/blitzmax2]

9. Implement our Update() function

[blitzmax2]
Function Update()
‘ update our physics engine
physicsEngine.Update(0.016) ‘ 0.016 is 16 millisecond time steps

‘to make things interesting lets spin our body when we hold the mouse left down
If MouseDown(1) Then
body.ApplyTorque(300)
End If

‘if you hold right click down the body will rise into the air
If MouseDown(2) Then
body.ApplyForce(Vector2.Create(0, – 600))
End If
End Function
[/blitzmax2]
We do a simple call to physicsEngine.Update() to update our physics bodies and also listen for left and right mouse clicks to allow us to manipulate our physics body. So holding left click will spin our physics body while holding right click our body will rise straight up into the air. All that’s left now is to implement drawing!

10. Implement the Draw() function

[blitzmax2]
Function Draw()
‘draw our vertices for our custom polygon
Local vertices:TVertices = geometry._worldVertices
For Local index:Int = 0 To vertices._vecArray.Length – 1
Local point1:Vector2 = vertices._vecArray[index]
Local point2:Vector2 = vertices._vecArray[vertices.NextIndex(index)]
DrawLine(point1.X, point1.Y, point2.X, point2.Y)
Next

‘ draw vertices for our floor
Local floorVertices:TVertices = floorGeom._worldVertices
For Local index:Int = 0 To floorVertices._vecArray.Length – 1
Local point1:Vector2 = floorVertices._vecArray[index]
Local point2:Vector2 = floorVertices._vecArray[floorVertices.NextIndex(index)]
DrawLine(point1.X, point1.Y, point2.X, point2.Y)
Next
End Function
[/blitzmax2]
This draw function mean seem a bit odd as it goes pretty deep into the inner-workings of farseer to draw polygons. For the purposes of this tutorial I decided to go this route, as ‘rendering polygons’ is a different topic all together and this tutorial is just to show how to properly construct oddly shaped polygons.

We’re Done!

And that’s all there is to it! Ten steps later and you’re on your way to creating fun farseer physics polygons! Below is the whole file pasted for easy access.

[blitzmax2]
SuperStrict
Import aco.farseerphysics

Global physicsEngine:TPhysicsSimulator
Global body:TBody
Global geometry:TGeom
Global floorBody:TBody
Global floorGeom:TGeom

‘init our graphics
Graphics(800, 600, 0, 60)

‘init the engine
InitPhysics()

While Not(KeyDown(KEY_ESCAPE))
Update()
Cls
Draw()
Flip
Wend

Function InitPhysics()
physicsEngine = TPhysicsSimulator.Create(Vector2.Create(0, 100))
‘ now lets create some custom polygon with vertices
Local vertices:TVertices = New TVertices
vertices.Add(Vector2.Create(0, 0))
vertices.Add(Vector2.Create(0, 100))
vertices.Add(Vector2.Create(50, 100))
vertices.Add(Vector2.Create(25, 50))
vertices.Add(Vector2.Create(200, 0))

‘ create the body with the vertices
body = TBodyFactory.CreatePolygonBody(physicsEngine, vertices, 1)

‘ create the geometry with vertices
geometry = TGeomFactory.CreatePolygonGeom(physicsEngine, body, vertices)

‘now lets move our body to somewhere else on the screen
body.SetPosition(Vector2.Create(300, 300))

‘lets create a floor for our body to collide against
floorBody:TBody = TBodyFactory.CreateRectangleBody(physicsEngine, 800, 100, 1)
floorBody.SetStatic(True) ‘ this makes our floor unmovable
floorBody.SetPosition(Vector2.Create(400, 550)) ‘ put our floor at the bottom of the screen

floorGeom:TGeom = TGeomFactory.CreateRectangleGeom(physicsEngine, floorBody, 800, 100)

End Function

Function Update()
‘ update our physics engine
physicsEngine.Update(0.016) ‘ 0.016 is 16 millisecond time steps

‘to make things interesting lets spin our body when we hold the mouse left down
If MouseDown(1) Then
body.ApplyTorque(300)
End If

‘if you hold right click down the body will rise into the air
If MouseDown(2) Then
body.ApplyForce(Vector2.Create(0, – 600))
End If
End Function

Function Draw()
‘draw our vertices for our custom polygon
Local vertices:TVertices = geometry._worldVertices
For Local index:Int = 0 To vertices._vecArray.Length – 1
Local point1:Vector2 = vertices._vecArray[index]
Local point2:Vector2 = vertices._vecArray[vertices.NextIndex(index)]
DrawLine(point1.X, point1.Y, point2.X, point2.Y)
Next

‘ draw vertices for our floor
Local floorVertices:TVertices = floorGeom._worldVertices
For Local index:Int = 0 To floorVertices._vecArray.Length – 1
Local point1:Vector2 = floorVertices._vecArray[index]
Local point2:Vector2 = floorVertices._vecArray[floorVertices.NextIndex(index)]
DrawLine(point1.X, point1.Y, point2.X, point2.Y)
Next
End Function
[/blitzmax2]

2 comments

  1. Could i request a Polygon Texture tutorial? Or just a short explanation of how to make it as ive tried things like

    Global LegT:TImage = TDrawingHelper.CreatePolygonTexture(LegVerts, TColor.White)

Leave a Reply

Your email address will not be published. Required fields are marked *