Aether.Physics2D - Release v 1.0 - 1.5

Aether.Physics2D is a 2D physics Engine for MonoGame.

It’s based on a fork of Farseer Physics 3.5/Box2D (farseerphysics.codeplex.com)
In this Release:

  • Bug fixes
  • Validation checks
  • Performance improvements
  • Parameterless constructors for World & Body
  • Reusable Bodies, (see: BodyPoolTest.cs)
  • Thread friendly (You can initialize/run the engine from different threads)
  • Use custom World/View/Projection in DebugView

Github:

Nuget:
https://www.nuget.org/packages/Aether.Physics2D
https://www.nuget.org/packages/Aether.Physics2D.Diagnostics

8 Likes

Cool stuff! Actually thought of doing the same. Will defenitely try this out! :slight_smile:

1 Like

Aether.Physics2D v1.1

In this Release:

  • Multithreading VelocityConstraintsSolver (video).
  • fix CCD warmstarting. The bug caused bodies to lose momentum after a collision (video).
  • Default constructor for Controller.
  • Refactor PhysicsLogicFilter, ControllerFilter & Controller Types. Allows 3rd party Controllers.
  • Breakable Bodies removed from the core engine and moved to Common.PhysicsLogic.
  • Use TimeSpan for Diagnostics.
  • Reduce garbage (GC) in TestBed.
  • Reimplement warmStarting & subStepping.
  • fix Breakablebodies and Explosions sample.

Github:

Nuget:


3 Likes

Aether.Physics2D v1.2

In this Release:

  • Multithreading PositionConstraintsSolver.
  • ContactManager.ContactList as IEnumerable.
  • Rewrite Camera (view/projection) and correct Physics in Samples and HelloWorld.
  • Two new samples, 3D Camera Demo and Shadow Demo.
  • Fix FixtureProxy.ProxyId value stored in IBroadPhase.
  • Removed obsolete collision behavior (Settings.UseFPECollisionCategories).
  • Removed Fixture.IgnoreCCDWith.
  • Removed ConvertUnits.
  • Removed setters of Body.IsStatic and Body.IsKinematic.
  • Use Color in DebugView methods.
  • Other minor micro-optimizations.

https://www.youtube.com/watch?v=cWod7HteMmI

Github:

Nuget:


3 Likes

Aether.Physics2D v1.3.1

In this Release:

  • Multithreading ContactManager.Collide().
  • Optimize ContactManager.AddPair().
  • fix Settings.SkipSanityChecks. Throws NullReferenceException when SkipSanityChecks = true.
  • Validate World state in Body.BodyType.
  • Validate Body owner in World.Add(Body). Faster O(1) check.
  • Move Multithread Thresholds from static Settings to World.ContentManager.
  • Move Maths.Complex to Common.Maths.Complex.
  • Rename World.IsStepping to World.IsLocked.
  • Move static Settings.SkipSanityChecks. as parameter of Triangulate.ConvexPartition().
  • Allow users to specify PositionIterations/VelocityIterations on Step().
  • Add tests MultithreadWorldsTest and TheLeaningTowerofLireTest.

Github:

Nuget:


3 Likes

Just wanted to leave you a big thank you! for your continuous work on Aether.Physics2D.

I used the old Farseer Physics Engine a lot and I can say that you did a great job rethinking and rebuilding the library. It’s very innovative and fast to work with.

It’s also pretty impressive what’s possible in a multithreaded environment. Having 1000’s of active physics objects with more than 10000 contacts at the same time isn’t a problem anymore.

I’m also curious if you will further evolve the particle hydrodynamics like with elastic particles in upcoming iterations of Aether.Physics2D.

Anyway, keep up the good work!

Thanks! It’s good to know that others make use of it and you seem to push it to it’s limits!

V1.3 is a milestone where I converted 3 of the most heavy methods in the library to run in parallel.
I need to take a break from it at the moment to focus on other priorities. I don’t know when I’ll be able
to work on the SPH.

2 Likes

This looks really cool! Could I attempt some tutorials on this? Though it may take me a while to figure out how to go about it…!

There is a big sample directory in the repo where you can learn from:

Here for example is the HelloWorld sample:


You can also search in google for “Box2D Tutorials”, as they should apply in the most cases to this physics systeme. You can already find a lot of good stuff around the net.


Edit: Or did you actually asked to MAKE some tutorials? Maybe I just misunderstood you :smiley:

I was asking if I could make some tutorials! :slight_smile:

My general plan would be to make a project per tutorial, ask if the Aether.Physics2D creator thinks it makes sense. Then I make the tutorial! :smiley:

1 Like

Yeah, I guess writing some documentation is the next thing I need to do.
The page currently points to Box2D documentation but the API is different in a few places.

Sure! that would be great.

Okay, sorry. English isn’t my native language but I try hard :smiley:

Hey @nkast,

I’m trying to make a platformer (think Castlevania) where there is a fixed movement speed when moving left and right.

The problem I’m having with Aether is “ApplyLinearImpulse” is a gradual increase in velocity. Have you got something set up for a fixed velocity?

I’ve tried “ApplyForce”, but that doesn’t seem to be working for me at all.

Below is my world, and player:

// LoadContent
_world = new World(new Vector2(0f, 500));

var playerBody = _world.CreateRectangle(50, 50, 1f, new Vector2(100, 100));
playerBody.BodyType = BodyType.Dynamic;
playerBody.FixedRotation = true;

// PlayerUpdate
if (_currentKey.IsKeyDown(Keys.A))
  Body.ApplyLinearImpulse(new Vector2(-10000f, 0));
else if (_currentKey.IsKeyDown(Keys.D)) 
  Body.ApplyLinearImpulse(new Vector2(10000f, 0));

if ((_previousKey.IsKeyUp(Keys.Space) &&
    _currentKey.IsKeyDown(Keys.Space)))
{
  Body.ApplyLinearImpulse(new Vector2(0, -500f)); // Jump?
}

I’m also trying to add a jump, but nothing is happening with that.

Sorry to bother you with these sorts of questions! It could very well be that I’m looking at this in the wrong way, or the library isn’t meant to be used like this.

Let me know. Cheers! :slight_smile:

The HelloWorld Sample does exactly what you are looking for :stuck_out_tongue:

It seems that you are using pretty high values for your you kind of rectangle. Usually you would have much lower values if you don’t change the mass.

Please reduce the world gravity to a much lower value like 10.

If you want that your rectangle (player) jumps, then you also need to set a positive value for Y:
Body.ApplyLinearImpulse(new Vector2(0, (+)15f));

Using ApplyForce() is fine with left and right movement, but take care of the friction and linear damping of the rectangle.

Do you connect your Body object with the playerBody object? Because it’s not shown in your code example.

Edit: Ah I see your rectangle itself is pretty big. It’s usually a good advice to start with small objects and make your experiences / do research and then if needed scale everything up. Are you aware of simulation units?

Okay, I’m going to spend the next few hours looking at the HelloWorld sample (I’ve been using Samples and NewSamples). I’ve also noticed the comment “96px x 96px => 1.5m x 1.5m”, so I’ll try and figure that out into everything.

I’ll get back when I come up with something!

P.S here is where I connect playerBody to Player.Body

  var playerBody = _world.CreateRectangle(50, 50, 1f, new Vector2(100, 100));
  playerBody.BodyType = BodyType.Dynamic;
  playerBody.FixedRotation = true;

  _sprites.Add(new Player(square)
  {
    Colour = Color.Red,
    Body = playerBody,
  });

Yes, that’s the right approach.

By using the physics systeme you always need to take care of the simulation-units-to-display-units-ratio or at least it’s helpful to know what this is meaning.

Basically (regarding to the defaults) you can say that 64 pixels on your screen should be 1 meter in the physical world. This is espacially helpful if you want to create realistic simulations.

Use the following helper functions to make your life as a game dev simpler:

public Vector2 ConvertWorldToScreen(Vector2 position)
{
    Vector3 temp = GraphicsDevice.Viewport.Project(new Vector3(position, 0), Projection, View, Matrix.Identity);
      
    return new Vector2(temp.X, temp.Y);
}
     
public Vector2 ConvertScreenToWorld(int x, int y)
{
    Vector3 temp = GraphicsDevice.Viewport.Unproject(new Vector3(x, y, 0), Projection, View, Matrix.Identity);
      
    return new Vector2(temp.X, temp.Y);      
}

For that you just need to set up a Projection and View matrix.

The old Farseer Physics Engine did it with a seperate class. Take a look at it here:

This is of course just to help you with your game development.

For the first just play around with the values from the HelloWorld sample and you should get a good feeling for everything.

Okay, I think I’ve got it.

The first problem I had is I wasn’t setting my environment up properly to that +y was up.

I’ll be writing a tutorial shortly that will spawn a static image in the centre of the screen, but the main focus will be setting up the world, and view.

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System.Collections.Generic;
using tainicom.Aether.Physics2D.Dynamics;

namespace AetherTutorial001
{
  /// <summary>
  /// This is the main type for your game.
  /// </summary>
  public class Game1 : Game
  {
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;

    private BasicEffect _spriteBatchEffect;

    private World _world;

    private Matrix _projection;

    private Texture2D _texture;

    private Vector2 _origin;

    private Vector2 _scale;

    private Body _body;

    public Game1()
    {
      graphics = new GraphicsDeviceManager(this);
      Content.RootDirectory = "Content";
    }

    /// <summary>
    /// Allows the game to perform any initialization it needs to before starting to run.
    /// This is where it can query for any required services and load any non-graphic
    /// related content.  Calling base.Initialize will enumerate through any components
    /// and initialize them as well.
    /// </summary>
    protected override void Initialize()
    {
      // TODO: Add your initialization logic here

      base.Initialize();
    }

    /// <summary>
    /// LoadContent will be called once per game and is the place to load
    /// all of your content.
    /// </summary>
    protected override void LoadContent()
    {
      // Create a new SpriteBatch, which can be used to draw textures.
      spriteBatch = new SpriteBatch(GraphicsDevice);

      _spriteBatchEffect = new BasicEffect(graphics.GraphicsDevice);
      _spriteBatchEffect.TextureEnabled = true;

      _world = new World();

      _texture = Content.Load<Texture2D>("Square");

      _origin = new Vector2(_texture.Width / 2, _texture.Height / 2);

      _scale = new Vector2(1f, 1f);

      _body = _world.CreateRectangle(_scale.X, _scale.Y, 0.1f, new Vector2(0f, 0f));
      _body.BodyType = BodyType.Static;
    }

    /// <summary>
    /// UnloadContent will be called once per game and is the place to unload
    /// game-specific content.
    /// </summary>
    protected override void UnloadContent()
    {
      // TODO: Unload any non ContentManager content here
    }

    /// <summary>
    /// Allows the game to run logic such as updating the world,
    /// checking for collisions, gathering input, and playing audio.
    /// </summary>
    /// <param name="gameTime">Provides a snapshot of timing values.</param>
    protected override void Update(GameTime gameTime)
    {
      // update camera View Projection
      var vp = GraphicsDevice.Viewport;
      var cameraZoomFactor = 12.5f / vp.Width; // zoom out to about ~12.5 meters wide
      _projection = Matrix.CreateOrthographic(vp.Width * cameraZoomFactor, vp.Height * cameraZoomFactor, 0f, -1f);

      _world.Step((float)gameTime.ElapsedGameTime.TotalSeconds);

      base.Update(gameTime);
    }

    /// <summary>
    /// This is called when the game should draw itself.
    /// </summary>
    /// <param name="gameTime">Provides a snapshot of timing values.</param>
    protected override void Draw(GameTime gameTime)
    {
      GraphicsDevice.Clear(Color.CornflowerBlue);

      _spriteBatchEffect.Projection = _projection;
      spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, RasterizerState.CullClockwise, _spriteBatchEffect);

      spriteBatch.Draw(_texture, _body.Position, null, Color.White, _body.Rotation, _origin, _scale / new Vector2(_texture.Width, _texture.Height), SpriteEffects.FlipVertically, 0f);

      spriteBatch.End();

      base.Draw(gameTime);
    }
  }
}

I think the above is about as basic as I can get it. I’m going to debug it over the weekend to see if I can understand it more.

With everything being rotated, and using the smaller values for positions and such, my brain is a little mumbled right now!

Hey, thats realy cool. But one question, why not merge that into the new release of the Farseer Physics Engine? https://github.com/VelcroPhysics/VelcroPhysics

One way to move is to set Body.LinearVelosity. This will override the current velocity of the body.
Another idea is to set Body.LinearDamping at 1 and apply a force on every step().

Of course the preferred.way is to use forces if you want your sprite to interact with other objects and set LinearDamping to a value that feels like air resistance. In that case you have to read the current LinearVelosity. and apply only the required force needed to have a max velocity.
The difference between ApplyLinearImpulse() and ApplyForce() is that force dependence on the mass of the object. Double the mass requires double the force to get equal acceleration. ApplyLinearImpulse() will multiply the impulse with invMass , so you get more or less the same result and you don’t have to care about the mass.

In the worst case, you can have a kinematic body where you are responsible for moving your sprite however you want, and you can still make use of the collision system (Body.ContactList).

The simulation works in KMS (kilo-Meters-seconds) and the coordinates system is Right: [+1;0], Up: [0,+1], Rotation: (CounterClockWise). It’s best to use realistic values and then everything will just work. Rendering the world is another issue. The samples use SpriteBatch for simplicity but it’s not the best choice because SpriteBatch works in ScreenSpace. In a real game you will probably replace SpriteBatch with your own batching, translation and effects or 3D models.

So, in order to work with spriteBatch I use a customEffect to override the default projection with my own View/Projection.
Additionally I had to Flip the sprites Vertically and CullClockwise.

Hey, this looks like a pretty great evolution of Farseer! I have a quick question:

While Farseer is not technically deterministic, it is very close and is possible to make determinstic (assuming run on the same runtime/CPU-architecture) with only a handful of simple changes. And so my question is, does the addition of multithreading break the near-determinism of the physics simulation? (Which, if not easy to fix, would make Aether unusable for my purposes since my game relies on determinism for its multiplayer.)


And unrelated to the above question, here’s an idea for a possible optimization that I just want to throw out there. It’s one that I’ve implemented in my own fork of Farseer to great effect in my particular game, with the caveat that my use case stresses Farseer in a pretty unusual and extreme way.

Basically, in my game it is common to have hundreds (or in extreme cases, thousands) of fixtures attached to a single body. Here’s an example of what I mean, with a debug layer turned on that shows all of the fixtures (there’s 380 of them):

The problem is that Farseer is not optimized for an extremely high ratio of fixtures to bodies. There are a couple problems with Farseer’s implementation:

  1. The broad phase needlessly queries for and finds overlaps between fixture AABBs in the same body, only to throw them out before creating the contacts. When you have so many fixtures constantly in close proximity constantly getting flagged for overlaps, this is a ton of wasted work.

  2. When a body moves, all of its fixtures also move, which requires updating the AABB of every single one of them in the broad phase’s DynamicTree. When you have so many fixtures, this is just really expensive.

My solution to these problems was to modify the broad phase so that it stores bodies instead of fixtures and to give each body its own DynamicTree of fixtures stored in body-relative coordinates. Only when the AABBs of two bodies overlap do the fixtures in the two bodies get queried for overlaps with each other, and fixtures within the same body never even get queried against each other. Additionally, since fixtures are stored in body-relative coordinates, the DynamicTree containing them doesn’t need to get updated continuously as the body moves.

The upside of this is that the performance improvement when there is a high ratio of fixtures to bodies is dramatic, in my case a couple orders of magnitude improvement. The downside is that in the case where there are only a few fixtures per body, the engine is likely slowed by the additional overhead of having to do body overlap queries and then fixture queries, plus the overhead of having to translate AABBs between coordinate systems on-the-fly during the fixture overlap queries (since fixtures are stored in body-relative coordinates). But I suspect most of the downside can be ameliorated by having some threshold under which bodies with only a few fixtures simply have their individual fixtures inserted into the broad phase and bodies over the threshold get optimized as above.

Anyway, just an idea. :slight_smile: