Quake level loading for Bevy!
More specifically, integration and support for the following workflows:
- TrenchBroom -> .map -> Bevy
- TrenchBroom -> .map -> ericw-tools -> .bsp -> Bevy
-
Add the
bevy_trenchbroom
to your project:cargo add bevy_trenchbroom
. -
Add the
TrenchBroomPlugin
with a suppliedTrenchBroomConfig
to your app like so:
use bevy::prelude::*;
use bevy_trenchbroom::prelude::*;
fn main() {
App::new()
// ...
.add_plugins(TrenchBroomPlugins(TrenchBroomConfig::new("your_game_name")))
// ...
;
}
You can configure TrenchBroomConfig
through a builder syntax.
Quake's entity classes are treated as an analog to Bevy's components. Here is an example of a simple point class:
use bevy::prelude::*;
use bevy_trenchbroom::prelude::*;
#[point_class]
#[derive(Default)]
struct MyClass {
property_a: f32,
property_b: String,
}
Then register the type with .register_type::<MyClass>()
on app initialization.
Now just run your game once, and it should automatically be available in TrenchBroom!
For more comprehensive documentation on this topic, see the manual.
Now that you have your environment setup, and have assumedly created your map, loading it is pretty easy.
use bevy::prelude::*;
use bevy_trenchbroom::prelude::*;
// app.add_systems(Startup, spawn_test_map)
fn spawn_test_map(
mut commands: Commands,
asset_server: Res<AssetServer>,
) {
commands.spawn(SceneRoot(asset_server.load("maps/test.map#Scene")));
// Or, if you're using BSPs.
commands.spawn(SceneRoot(asset_server.load("maps/test.bsp#Scene")));
}
Because Bevy's material system so heavily relies on generics, storing and inserting arbitrary materials at runtime is challenging.
To this end, i've created the bevy_materialize crate, which bevy_trenchbroom
uses.
TrenchBroomPlugin
Automatically adds MaterializePlugin
with the default toml
deserializer. If you wish to use a different deserializer, add your own MaterializePlugin
before adding TrenchBroomPlugin
.
Texture loaders for loose and embedded textures can be changed in TrenchBroomConfig
.
The default loader for loose textures first looks for <texture>.<GenericMaterial extension>
.
<GenericMaterial extension>
is also defined in your config, and is "material" by default.
If the file can't be found, it then tries to load <texture>.<Image extension>
into a StandardMaterial
as a fallback.
<Image extension>
can similarly changed in your config.
The fallback is because if you have a bunch of simple textures where the material file would look something like
[material]
base_color_texture = "example.png"
it can get a bit repetitive.
You can also configure the rest of the properties of the default material in MaterializePlugin
.
bevy_trenchbroom
supports BSP loading via the qbsp crate when the bsp
feature is activated.
For more information, please see the manual.
bevy_trenchbroom
supports bevy_rapier3d and avian3d to easily add colliders when spawning geometry.
First, enable the rapier
or avian
feature on the crate, then either call convex_collider
or trimesh_collider
on your class's SpawnHooks
to create the respective type of collider(s) with said geometry.
For dedicated servers bevy_trenchbroom
supports headless mode by turning off its client
feature. e.g.
bevy_trenchbroom = { version = "...", default-features = false }
See the Migration Guide when updating between versions!
Bevy | bevy_trenchbroom | TrenchBroom | ericw-tools |
---|---|---|---|
0.16 | 0.8-0.9 | 2025.3 | 2.0.0-alpha9 |
0.15 | 0.6-0.7 | 2025.1-2025.2 | N/A |
0.14 | 0.4-0.5 | 2024.1 | N/A |
0.13 | 0.1-0.3 | 2024.1 | N/A |
There is a good chance other versions of TrenchBroom and ericw-tools will work, especially close ones, these are just the versions we officially support.
Versions before 0.8 didn't target a clear version of ericw-tools, or didn't support BSPs at all, which is why they are N/A.