Hi,
I have been trying to figure out the best way to do collisions using MonoGame Extended’s ECS. I started off by dissecting the Platformer example, but it did not work when I tried to run it, and it had some features in it that I really didn’t need (e.g. velocity), so I decided to simplify it and write my own.
Here’s my current approach:
-
Each actor (e.g. player, NPC) and static object (such as a tile) receives a
Collidercomponent. This stores the current object collider’s bounds and state (enum that is eitherCollidingorNotColliding). -
Since actors and other objects can move, I wrote a
WorldSystemthat requires aTransform2and aColliderand updates theColliderbounds x and y position based on its currentTransform2position.Collideralso stores the last valid position before a collision, which is set in theMovementSystem. -
There is the
CollisionSystemthat (for now) just iterates over each object with aColliderand does a simpleRectangleF.Intersectto see if we are colliding or not with any other collider (and updates the enum accordingly of the colliding objects). Time complexity is probably awful but I was going to concern myself with that later and make it a bit smarter (will replace with Trinith’s QuadTree mentioned in another collision post). -
There is the
MovementSystemthat deals with receiving keyboard input and updating the actor’sTransform2component. It records the last valid position, and after movement, if a collision occurs, it reset the player back to the last valid position.
Now I am sure there are better ways to do this design, but for now I just wanted some simple collision to work.
I am currently running into an issue with this design in which the colliding entity simply gets stuck and can’t get moved out of, and it appears as if the RectangleF.Interesect isn’t accurate enough (i.e. it collides too late, hence it gets stuck). I added some debug sprites to the GIF below (all colliders for now are just 16x16), red and blue colliders:
CollisionSystem:
public override void Process(GameTime gameTime, int entityId)
{
Collider collider = _colliderMapper.Get(entityId);
Bag<Collider> allColliders = _colliderMapper.Components;
collider.State = ColliderState.NotColliding;
foreach (Collider otherCollider in allColliders)
{
if (collider.Bounds.Intersects(otherCollider.Bounds))
{
collider.State = ColliderState.Colliding;
return;
}
}
}
WorldSystem:
public override void Process(GameTime gameTime, int entityId)
{
Transform2 transform = _transformMapper.Get(entityId);
Collider collider = _colliderMapper.Get(entityId);
// The - 8.0f is temporarily there for making sure the collider is centered
collider.Bounds = new RectangleF(transform.Position.X - 8.0f, transform.Position.Y, collider.Bounds.Width, collider.Bounds.Height);
}
MovementSystem:
public override void Process(GameTime gameTime, int entityId)
{
Actor actor = _actorMapper.Get(entityId);
Transform2 transform = _transformMapper.Get(entityId);
Collider collider = _colliderMapper.Get(entityId);
if (!actor.PlayerControllable) return;
KeyboardStateExtended keyboardState = KeyboardExtended.GetState();
float speed = actor.MovementSpeed;
actor.State = State.Idle;
collider.LastValidPosition = transform.Position;
if (keyboardState.IsKeyDown(Keys.W))
{
actor.State = State.Walking;
actor.Facing = Facing.Up;
transform.Position = new Vector2(transform.Position.X, transform.Position.Y - speed);
}
// ...deal with A, S, D here...
// ACTUAL COLLISION HERE:
if (collider.Policy == CollisionPolicy.Block && collider.State == ColliderState.Colliding)
transform.Position = collider.LastValidPosition;
if (actor.State == State.Walking)
// Play animation etc...
}
Any help, feedback, or ideas would be much appreciated!

