Collision
This page is up to date for MonoGame.Extended 6.0.0. If you find outdated information, please open an issue.
The MonoGame.Extended collision system in 6.0 is split into two layers:
- a low level geometry layer built around explicit bounding volumes and
Collision2D - an actor/world layer built around
ICollisionActor,CollisionShape2D, andCollisionWorld2D
This separation lets you choose the level of abstraction that fits your game. If you want to manage actors, layers, and broadphase queries, start with CollisionWorld2D. If you only need shape tests, containment checks, or allocation free geometry routines, use the bounding volume types and Collision2D directly.
Where to Start
For most gameplay collision systems, start with the actor/world layer:
ICollisionActordefines the objects that participate in world queriesCollisionShape2Dwraps the actor's collision shape without usingIShapeFCollisionWorld2Dstores actors in named layers, owns layer membership, and provides candidate, collision, and pair queriesCollisionResult2Dreturns overlap state, collision normal, penetration depth, and minimum translation vector
If you are moving from MonoGame.Extended 5.5.1, read the Migration Guide after this page. If you want the step-by-step setup path for a new project, go to Collision Quick Start. If you want the architecture, query flow, and performance rationale behind the system design, go to the Collision Technical Reference.
Collision Architecture
Low Level Geometry Layer
The low level layer lives in the MonoGame.Extended namespace and is centered on explicit geometric types such as:
BoundingBox2DBoundingCircle2DBoundingCapsule2DOrientedBoundingBox2DBoundingPolygon2DLine2DLineSegment2DRay2D
These types provide:
Intersects(...)boolean overlap testsContains(...)containment queries- transformation and translation helpers
- direct access to lower level
Collision2Droutines when needed
For the full geometry reference, see 2D Geometry.
Actor/World Collision Layer
The actor/world layer builds on top of those geometric primitives for gameplay collision management.
In this layer:
- actors implement
ICollisionActor - actor shapes are exposed as
CollisionShape2D - broadphase uses
CollisionShape2D.BoundingBox - narrowphase uses
CollisionShape2D.Intersects(...)orCollisionShape2D.TryGetCollision(...) - collision filtering uses explicit named layer rules
This is the recommended layer for character controllers, triggers, hazards, projectiles, and other gameplay objects that need world queries or collision resolution data.
Recommended API: CollisionWorld2D
CollisionWorld2D is the primary query oriented collision API in 6.0. It stores actors in named layers, uses broadphase queries to reduce candidate checks, and exposes collision results relative to the actor being queried.
Typical flow:
- Implement
ICollisionActor. - Expose a
CollisionShape2Dfor the actor. - Create one or more
Layerinstances. - Register those layers with
CollisionWorld2D. - Enable the layer pairs that should collide.
- Insert actors into the default or named layers.
- Query collisions, inspect membership, or move actors between layers during gameplay as needed.
The result of a narrowphase collision query is a CollisionResult2D. Its MinimumTranslationVector moves the receiving shape out of the other shape, which makes it suitable for simple overlap resolution.
foreach (CollisionEvent2D collision in world.QueryCollisions(playerActor, "walls"))
{
playerPosition += collision.Result.MinimumTranslationVector;
}
For a full walkthrough, see Collision Quick Start.
Why There Is No Update()
CollisionWorld2D deliberately does not have an Update() method.
That design keeps responsibilities separate:
- your game code owns actor movement, state changes, and frame timing
CollisionWorld2Downs broadphase storage, layer rules, and collision queries
This avoids hidden rebuild work and avoids guessing when actor movement for the current step is "done." Instead, the world exposes RebuildDynamicLayers() as an explicit synchronization point after you finish updating actor shapes and before you run the next set of queries.
Shapes and Result Queries
CollisionShape2D is a wrapper for the actor/world layer. It can represent the currently supported collision shapes including:
BoundingBox2DBoundingCircle2DOrientedBoundingBox2DBoundingCapsule2DBoundingPolygon2D
There are two main query styles:
Intersects(...)when you only need to know whether two shapes overlapTryGetCollision(...)when you also need collision result data
CollisionShape2D.Intersects(...) supports more shape pairs than CollisionShape2D.TryGetCollision(...). If you need a CollisionResult2D, make sure the specific shape pair you are using supports result returning queries in the current preview.
Layers and Filtering
The 6.0 collision system uses explicit named layer rules instead of the older implicit behavior.
That means:
- layers must be registered in the collision world
- collisions only occur for layer pairs that are enabled
- self collision is controlled explicitly per layer pair
- broadphase candidates can be filtered out before narrowphase work runs
This makes collision behavior easier to inspect and easier to disable for unrelated groups of actors.
World Owned Membership
In 6.0 preview, layer membership belongs to CollisionWorld2D, not to ICollisionActor.
That means:
Insert(actor)places the actor into the default layerInsert(actor, "layerName")places the actor into a specific registered layer- inserting the same actor into the same world twice is an error
MoveToLayer(actor, "layerName")is the explicit way to change membershipContains(...),TryGetLayerName(...), andGetLayerName(...)let you inspect world specific membership
This keeps layer placement tied to the world that owns it and allows the same actor to participate in more than one collision world when needed.
Broadphase Sizing
Each Layer owns its own broadphase structure. When you use SpatialHash, that means different layers can use different cell sizes.
This is allowed, but it has tradeoffs:
- it does not usually change collision correctness
- it can change candidate counts and query cost significantly
- it makes tuning harder because each layer may behave differently under load
As a default recommendation, start with the same SpatialHash size for all layers in one CollisionWorld2D, or at least keep them similar. This gives you a more predictable baseline and makes it easier to reason about performance across layer pairs.
Use different sizes only when you have a clear reason, such as:
- one layer has much smaller or denser actors than another
- one layer is measured to perform better with a different cell size
- you are deliberately tuning separate workloads after profiling
If layers collide with each other frequently, similar broadphase settings are usually easier for consumers to understand and maintain.
Dynamic vs Static Layers
Layers also control whether their broadphase is rebuilt during synchronization.
Layer.IsDynamic = truemeans the layer participates in rebuilds duringLayer.Reset()orCollisionWorld2D.RebuildDynamicLayers()Layer.IsDynamic = falsemeans the layer skips that rebuild work
Use dynamic layers for moving actors and static layers for fixed world geometry or other layers whose contents do not move after insertion.
Migration From 5.5.1
If you are coming from MonoGame.Extended 5.5.1, the most important changes are:
IShapeFis no longer the collision system abstractionICollisionActornow exposesCollisionShape2D ShapeICollisionActorno longer uses callback based collision methodsCollisionWorld2Dis the new primary actor/world API- low level collision code now uses explicit bounding volume types
- collision filtering now uses explicit layer pair rules
For detailed before/after mappings and upgrade examples, see Migrating from 5.5.1.
What to Read Next
- Collision Quick Start for the main 6.0 setup path
- Migrating from 5.5.1 if you are upgrading existing code
- Collision Technical Reference for architecture, lifecycle, and performance details
- 2D Geometry for the low level shape and
Collision2Dreference