This walkthrough shows how to add Velcro to a simple FlatRedBall project. We will create a diagonal stack of blocks which will fall and collide against a static surface. This tutorial uses the FlatRedBall desktop engine, which means it uses proper XNA (as opposed to MonoGame). MonoGame projects must use the MonoGame version of the Farseer .dll.
We will begin with an empty FlatRedBall project:
Add a new Block entity:
Right-click on Entities
Select Add Entity
Enter the name Block
Click OK
Next, we'll add a Sprite to the Block so we can see it in-game:
Expand the Block entity
Right-click on Objects
Select Add Object
Select Sprite
Click OK
The Sprite needs to be modified so it will show up in game:
Change the Sprite's Color Operation to Color. This allows us to use solid colors to draw the sprite instead of a texture.
Set the Red value to 1
Delete the Texture Scale value
Enter a Width of 32
Enter a Height of 32
Next we'll create a screen to hold our Block instances and the Farseer logic:
Right-click on Screens
Select Add Screen
Enter the name Game Screen
Click OK
GameScreen needs a Block list so that we can construct the blocks in code and have them be automatically managed. To do this:
Push and hold the right mouse button on the Block entity
Drag the entity onto GameScreen
Release the mouse button
Select Add Entity List
Now that our Glue project has been created, we'll add Farseer to the Visual Studio project:
Download the Farseer precompiled .dll: https://github.com/vchelaru/FlatRedBall/blob/master/Engines/FlatRedBallXNA/3rd%20Party%20Libraries/Farseer/FarseerPhysics%20XNA.dll?raw=true
Open the game project in Visual Studio
Right-click on References in Visual Studio under your game project
Select Add Reference...
Click the Browse category
Click the Browse... button
Navigate to where you saved the Farseer dll file
Select the file and click Add
We'll add the code to create a Farseer Body instance in the Block.cs file. Open the Block file and modify the class so it appears as shown in the following code:
public partial class Block
{
Body physicsBody;
/// <summary>
/// Initialization logic which is execute only one time for this Entity (unless the Entity is pooled).
/// This method is called when the Entity is added to managers. Entities which are instantiated but not
/// added to managers will not have this method called.
/// </summary>
private void CustomInitialize()
{
}
public void CreateFarseerPhysics(World world, Vector2 position, float conversionFactor)
{
position.X /= conversionFactor;
position.Y /= conversionFactor;
var width = SpriteInstance.Width / conversionFactor;
var height = SpriteInstance.Height / conversionFactor;
physicsBody = BodyFactory.CreateRectangle(
world, width, height, 1, position);
physicsBody.Restitution = .6f;
physicsBody.SleepingAllowed = true;
physicsBody.Friction = .5f;
physicsBody.BodyType = BodyType.Dynamic;
}
private void CustomActivity()
{
}
private void CustomDestroy()
{
}
private static void CustomLoadStaticContent(string contentManagerName)
{
}
internal void UpdateToFarseer(float conversionFactor)
{
this.X = physicsBody.Position.X * conversionFactor;
this.Y = physicsBody.Position.Y * conversionFactor;
this.RotationZ = physicsBody.Rotation;
}
}Finally we'll add code to our GameScreen . Modify your GameScreen.cs file so it looks like the following code:
public partial class GameScreen
{
World world;
Body ground;
private const float ConversionDivisor = 10;
private float ConversionFactor => SpriteManager.Camera.OrthogonalHeight / ConversionDivisor; //Conversion Factor: the screen's height corresponds to 10 meters
private float ToFarseer(float pixels) => pixels / ConversionFactor;
private float FromFarseer(float meters) => meters * ConversionFactor;
void CustomInitialize()
{
CreateFarseerWorld();
CreateBlocks();
CreateGround();
}
private void CreateFarseerWorld()
{
float gravity = -9.82f;
world = new World(new Vector2(0, gravity));
}
private void CreateBlocks()
{
int blockCount = 6;
for (int i = 0; i < blockCount; i++)
{
var block = new Entities.Block();
var position = new Vector2(-80 + i * 15f, i * 40); //this position will be converted to Farseer Units inside block's CreateFarseerPhysics()
block.CreateFarseerPhysics(world, position, ConversionFactor);
BlockList.Add(block);
}
}
private void CreateGround()
{
var frbRectangle = new AxisAlignedRectangle();
frbRectangle.Width = 700;
frbRectangle.Height = 13;
frbRectangle.Y = -200;
frbRectangle.Visible = true;
ground = FarseerPhysics.Factories.BodyFactory.CreateRectangle(
world,
ToFarseer(frbRectangle.Width),
ToFarseer(frbRectangle.Height),
1,
new Vector2(ToFarseer(0), ToFarseer(frbRectangle.Y)));
ground.Restitution = .7f;
ground.SleepingAllowed = true;
ground.IsStatic = true;
ground.Friction = .5f;
}
void CustomActivity(bool firstTimeCalled)
{
world.Step(TimeManager.SecondDifference);
foreach (var block in BlockList)
{
block.UpdateToFarseer(ConversionFactor);
}
}
void CustomDestroy()
{
}
static void CustomLoadStaticContent(string contentManagerName)
{
}
}If we run the game we'll see our blocks falling and colliding:
The is a .NET library which can be used to add more advanced physics beyond what is offered by FlatRedBall's shapes (such as Circle or Rectangle). Note that the Github page for Velcro states that sponsorship is required to use Velcro Physics in a commercial project, so consider this if you plan on selling your game.
In general, the following must be done to use Velcro Physics:
Instantiate a World object
Call the World instance's Step function every frame
Create one or more Body instances - A Body is created through Velcro's Factory classes. The Body must be added to the World.
Set properties on the Body instances - You can set properties such as size, orientation, velocity, and how the bodies respond to collisions (inertia, elasticity, friction).
This demo will create two Body instances which will perform the physics simulation. It also creates a FlatRedBall Circle and Polygon to display the visuals of the Velcro bodies.
To add Velcro to your project:
Expand your game project's Dependencies
Right-click on Packages and select Manage NuGet Packages...
Check the Include prerelease option
Search for GenBox.VelcroPhysics.MonoGame
Add the Genbox.VelcroPhysics.MonoGame package to your project.
Once you have added Velcro to your project, you can begin using the classes to perform physics simulations. The following is example code which could be added to a GameScreen to create a simple Velcro simulation:








using FlatRedBall;
using FlatRedBall.Math.Geometry;
using Microsoft.Xna.Framework;
using Genbox.VelcroPhysics.Dynamics;
using Genbox.VelcroPhysics.Factories;
namespace VelcroPhysicsTest.Screens;
public partial class GameScreen
{
//Farseer Objects
World mWorld;
Body mBallBody;
Body mPlatformBody;
//FlatRedBall Objects
Circle ball;
Polygon mPlatformPolygon;
void CustomInitialize()
{
// Farseer
float gravity = -80;
mWorld = new World(new Vector2(0, gravity));
//Create a ball body with a radius of 32 and density of 1
mBallBody = BodyFactory.CreateCircle(mWorld, 32, 1);
mBallBody.Restitution = 1f;
mBallBody.BodyType = BodyType.Dynamic;
//Create a rectangle platform with a width of 400, height of 30,
//density of 1, and position at 0, -12
//Then set the position and rotation
var rectangleWidth = 600;
mPlatformBody = BodyFactory.CreateRectangle(mWorld, rectangleWidth, 30, 1, new Vector2(0, -120));
mPlatformBody.Rotation = .1f;
mPlatformBody.Restitution = 1f;
mPlatformBody.BodyType = BodyType.Static;
//FRB
mPlatformPolygon = Polygon.CreateRectangle(rectangleWidth/2, 15f);
mPlatformPolygon.X = mPlatformBody.Position.X;
mPlatformPolygon.Y = mPlatformBody.Position.Y;
mPlatformPolygon.RotationZ = mPlatformBody.Rotation;
ShapeManager.AddPolygon(mPlatformPolygon);
ball = new Circle();
ball.Visible = true;
ball.Radius = 32;
ball.X = mBallBody.Position.X;
ball.Y = mBallBody.Position.Y;
}
void CustomActivity(bool firstTimeCalled)
{
//Farseer: Only need to step (update) the world you added the objects to
mWorld.Step(TimeManager.SecondDifference);
//FRB: Don't forget to update the visual representations as well!!
ball.X = mBallBody.Position.X;
ball.Y = mBallBody.Position.Y;
//mPlatformPolygon is static (doesn't move), so there is no need to update its position
}
void CustomDestroy()
{
}
static void CustomLoadStaticContent(string contentManagerName)
{
}
}

