Add Physics Colliders
Tiled allows you to add objects to your map—either directly on an object layer or attached to a tile.
bevy_ecs_tiled
can use these objects to automatically spawn physics colliders when loading the map.
Two physics engines are supported out of the box:
Both are well-integrated and offer similar features in the context of bevy_ecs_tiled
. You can use them as-is, customize their behavior, or implement your own backend.
Creating Collider Objects in Tiled
To spawn colliders, you need to define objects in your map:
- Objects on an object layer:
These are the standard objects you place in Tiled on an object layer. - Objects attached to a tile:
Edit your tileset and use Tiled's built-in collision editor to define collision shapes for tiles.
Both types of objects are supported and will result in physics colliders being spawned in your game, based on their shapes.
Automatically Spawning Colliders
To automatically spawn colliders from Tiled objects, you need to:
- Enable the appropriate feature in your
Cargo.toml
:
Eitheravian
orrapier
, depending on your backend choice.
You can also enable only thephysics
feature and provide your own backend (see below).
Example: Using the Avian backend
[dependencies]
bevy = "0.16"
bevy_ecs_tiled = { version = "0.8", features = ["avian"] }
Note:
You may need to adjustbevy
andbevy_ecs_tiled
versions.
- Add the
TiledPhysicsPlugin<T>
with theTiledPhysicsBackend
of your choice.
Example: Using the Avian backend
use bevy::prelude::*; use avian2d::prelude::*; use bevy_ecs_tiled::prelude::*; // You must enable the 'avian' feature for bevy_ecs_tiled fn main() { App::new() // Load bevy_ecs_tiled main plugin .add_plugins(TiledPlugin::default()) // Load bevy_ecs_tiled physics plugin (select Avian backend) .add_plugins(TiledPhysicsPlugin::<TiledPhysicsAvianBackend>::default()) // Load Avian main plugin .add_plugins(PhysicsPlugins::default().with_length_unit(100.0)) // Add your systems and run the app! .add_systems(Startup, startup) .run(); } fn startup(mut commands: Commands, asset_server: Res<AssetServer>) { commands.spawn(Camera2d); commands.spawn(TiledMap(asset_server.load("map.tmx"))); }
Colliders will be spawned for every object or tiles colliders in your map automatically.
We provide two TiledPhysicsBackend
that can be used out of the box:
TiledPhysicsAvianBackend
: for the Avian 2D physics engineTiledPhysicsRapierBackend
: for the Rapier 2D physics engine
Note:
You can actually use several physics backends at the same time if you register theTiledPhysicsPlugin<T>
plugin multiple times, but with differentTiledPhysicsBackend
.
Filtering Which Objects Get Colliders
By default, colliders are spawned for all objects (regular objects and tile colliders).
If you want more control, use the TiledPhysicsSettings
component.
This component lets you filter which objects/layers should have colliders, based on their names.
Example: Only spawn colliders for certain objects/layers
#![allow(unused)] fn main() { use bevy::prelude::*; use avian2d::prelude::*; use bevy_ecs_tiled::prelude::*; fn startup(mut commands: Commands, asset_server: Res<AssetServer>) { commands.spawn(Camera2d); commands.spawn(( TiledMap(asset_server.load("finite.tmx")), // Restrict colliders to: // - objects named 'hitbox' or 'collision' // - tile colliders in a layer named 'collision' TiledPhysicsSettings::<TiledPhysicsAvianBackend> { objects_filter: ObjectNames::Names(vec!["hitbox".into(), "collision".into()]), tiles_layer_filter: ObjectNames::Names(vec!["collision".into()]), ..default() }, )); } }
Colliders Aggregation
Tiled uses simple shapes (rectangles, ellipses, polygons) to define colliders.
To reduce the number of physics colliders and improve performance, bevy_ecs_tiled
tries to merge these simple shape colliders into a single complex one whenever possible.
- Tiles: Merging is actually performed at the tilemap level.
Eventhough you can use several shapes to define a tile's collider, these shape will be merged into a single collider and all tile colliders for a given tilemap will also be merged together.
The collider entity is spawned at the tilemap level. - Regular objects: If an object references a tile, it will inherit that tile's collider and if the tile has several shapes, they will be merged.
The collider entity is spawned at the object level and each object always gets its own collider.
Note:
BothTiledPhysicsAvianBackend
andTiledPhysicsRapierBackend
provide several strategies to aggregate colliders. You can see their respective documentation for more information.
Custom Physics Backends
For advanced use cases, you can implement your own physics backend.
Just create a struct that implements the TiledPhysicsBackend
trait (i.e., provide a spawn_colliders
function), and use it when registering the TiledPhysicsPlugin<T>
plugin.
See this example for more information.
Physics Events
When a collider entity is spawned, a TiledEvent<ColliderCreated>
event is sent.
It contains information about the origin of the collider.
This can be useful to add custom components to your colliders.
For instance, with Avian:
#![allow(unused)] fn main() { use bevy::prelude::*; use avian2d::prelude::*; use bevy_ecs_tiled::prelude::*; fn startup(mut commands: Commands, asset_server: Res<AssetServer>) { commands.spawn(Camera2d); commands.spawn( TiledMap(asset_server.load("map.tmx")) .observe( |trigger: Trigger<TiledEvent<ColliderCreated>>, mut commands: Commands| { // Automatically add a RigidBody::Static component to colliders created from Tiled objects if trigger.event().event != TiledCollider::TilesLayer { return; } // Add a RigidBody::Static component to the collider entity commands .entity(trigger.event().target) .insert(RigidBody::Static); }, ), ); } }