Three years of Bevy 🎉
Bevy released 3 years ago at version 0.1 and reinvigorated Rust game engine development.
I started experimenting with Bevy that week and have been tinkering ever since.
Here are some of my scattered thoughts on Bevy as of version 0.11 for the 3 year birthday reflection!
- What have I done
- Rust for games
Conveyed best by https://arewegameyet.rs/. We have the blocks, bring your own glue.
The difference between being having the required features like asset loading, rendering, running game logic, and having a cohesive, productive game engine is massive. It gives me a new appreciation for game engines.
I liken it to comparing programming languages on their features vs their library ecosystem, community, tooling, etc.
What have I done in Bevy?
Top down mechanics
Layered pixel drawing
Toon shading library https://github.com/tbillington/bevy_toon_shader
Had some fun with lighting
Implemented raycast based car physics
Noise terrain playground link
Vampire survivors clone
Created an opinionated best practices guide https://github.com/tbillington/bevy_best_practices.
And a bunch of others …
It is easy to build significant functionality as Bevy plugins, see Bevy assets.
Physics, UI, networking, prefabs, camera systems, tilemaps, particle systems, water, AI, the list goes on of major components that are easy to include in your game.
It is a testament to the foresight of the engine design & structuring that a young engine can support such extensibility from 3rd party modules at this stage in its life.
However, having major components of your game come from many different developers is a risk.
- How soon after a Bevy release will they be updated?
- Will they be updated at all?
- How often do they make their own breaking changes?
- Can you find assistance if you need it?
- How do they play with the rest of the plugins you’ve assembled?
My experience with upgrading Bevy versions over time has chilled me slightly on using 3rd party plugins that don’t have clear community buy-in and traction.
Overall the extensibility of Bevy is a major feature and a core strength of an open source game engine.
Pretty simple, Bevy doesn’t have an editor yet. This is a well-known, yet painful part of using Bevy.
For some types of games this isn’t a big deal, but for others, it’s a sore spot and can be a 10x slowdown on experimentation & iteration.
Related, but Bevy does not yet have a viable scene representation. There are a number of community options, but they suffer from the common issue of depending on a 3rd party library for foundational parts of your game. The current solution is to manually create everything “by hand” in setup code, tag every entity you spawn with a marker component, and despawn them when you want to “change scene”.
One interesting alternative is a Blender based workflow.
There are stopgaps like bevy_editor_pls that help with basic runtime debugging.
From what I can tell the Editor is the priority after the UI/Scene re-work, so I’m hopefully.
Being able to use and manage assets efficiently and reliably is one of the most core parts of a game engine. The way assets work and integrate into the rest of the engine is pervasive and foundational. The asset system in Bevy feels like building blocks, and not a cohesive part of the engine. Assets V2 just merged, which I am excitedly looking forward to. It is however more “groundwork” based, features you’d expect are being tracked in this post-v2 issue.
Working with assets currently is painful.
- Only gltf is supported out of the box, most assets bought and sourced online are not in gltf format and instead in fbx or obj
- Can’t easily use “parts” of a gltf like a mesh. For example to load a mesh and add a collider you will have to write your own loader logic to wait for the mesh to be available, then build the collider, then make it available to use in game via some spawning mechanism
- In Unity I would import a model file, and be able to refer to meshes/materials inside easily from other areas, and build prefabs from them
- A significant portion of setting up new projects is writing custom loaders for different types of objects in the game. Even seemingly simple tasks like specifying the material a loaded asset within a gltf should use is involved or requires using a 3rd party library
The scene format is soft-deprecated and a new one is in the proposal stage. Hopefully it will be available by the 0.13 release in ~4-5 months. Building any non-trivial environments without a good scene representation is not really viable.
I’ve yet to see how the assets v2 affects development. I hope the full asset pipeline will still be available at runtime so games can support user generated content with the full feature set of the engine.
I’m keen to get away from path based asset references. Moving files around in the assets folder frequently breaks code, and my experience with Godot is that a system build on string paths as opposed to IDs is fragile without some layer of indirection in-between.
Bevy shaders are written in wgsl with a custom import system/pipeline.
While I think for a new engine this is probably the “correct” decision, it also means there is very few resources online, and you’re subject to breaking changes at the engine and spec level.
My shaders have broken twice with bevy updates and I expect them to break again in future. Both updates have been necessary and good improvements, and with only relatively small changes required.
Adapting to wgsl is relatively simple if you have experience in any other shader language. The difficult part is figuring how to get data through Bevy and into the shader. There is effectively no documentation on how to do it, so you’ll be reading source code from Bevy and other libraries.
Bevy also inherits wgpu’s strengths and weaknesses. Certain features in Bevy seem blocked on implementation in wgpu, and while contributors overlap between the two projects it’s a limitation to be aware of.
I don’t fault Bevy for not also writing their graphics stack from scratch. I am curious about how long wgpu will serve Bevy as the needs of a modern game engine come up against the goals and restrictions of WebGPU.
Bevy’s UI system is nascent and rough to use, and while there exists many 3rd party libraries you can use it’s risky to build something as foundational as your game UI on 3rd party libraries that may or may not update with future bevy versions.
The roughness of the UI system is compounded by not having a viable scene representation, so the built-in way to create UI is through code. I’m comfortable creating UI’s through code with my web background, however the API currently is a little verbose for my tastes :).
For now I’m putting off any serious UI investment until the upcoming Bevy UI rewrite, and using egui(an immediate mode GUI) as a stopgap.
Bevy UI is receiving focused attention at the moment, so I’m optimistic for something by 0.13 in ~4-5 months.
Bevy’s ECS has been one of the fundamental selling points of the engine, and day to day use is a delight.
Resources, Events, and Queries feel simple yet powerful to use. The learning curve is relatively small to get the basics, yet it feels like mastery is still a ways off.
Programmers who haven’t used an ECS before will feel lost initially, you have to adopt a whole new paradigm of how to write and structure your game.
However, the complexity of system scheduling, states, run conditions, 3rd party libraries and bevy sub-systems naturally creates exponential complexity. There are ways to mitigate it via system sets, plugin encapsulation, and states, however discovering the right amount to use is it’s own journey and is difficult for those new to the ECS model.
Because the ECS defaults to running systems in parallel where possible, and deferring operations like spawning, parenting, destroying, etc, there is more opportunities for inconsistent behaviour and errors arising from these race conditions if not accounted for.
In my opinionated best practices doc I state the programmer should order systems by default (within their “subsystem” eg Player or LevelLoader etc), and opt-out only if they have good reason.
Due to not having an editor, understanding system ordering and debugging it requires involved debugging. There are 3rd party plugins that can output schedule graphs as .dot and .svg files, however they don’t expose run conditions, states, and just generally quickly become unusable even on small sized projects.
Ideally I would like a visual graph editor for system ordering and run conditions that would work bi-directionally with my definitions in code. At a certain level it’s just plain easier to visualise control flow, and being able to make tweaks interactively would be incredibly powerful.
I still think Bevy ECS is best in class for ergonomics. I eagarly look forward to relationships which will open the proverbial floodgates on more ways to leverage the ECS.
I must give special mention to Sanders Martens for their writings on ECS systems and sharing their expertise and knowledge with the Bevy project.
Archetypes aren’t regularly seen or interacted with by users of Bevy, I don’t know enough to know if this is a pro or a con. I’ve seen other ECS libraries have archetypes as a first-class user level tool, even going so far as to not allow dynamic component addition/removal at runtime.
Sometimes it feels a bit loosey-goosey not having any real definition of “game objects” at a higher level than the component, so I’m curious if there are ergonomics we’re missing out on? This can manifest when storing a Entity reference for when you need to take some action later. There is no way apart from comments or variable naming to indicate what components that Entity might be expected to have.
The official Bevy book effectively hasn’t changed since Bevy 0.1. I understand why, rewriting documentation for regular breaking changes is a productivity tax on the project, but not having any real user documentation outside of sparse API docs is definitely felt by users and the community.
The majority of questions asked in discord are beginner questions that should be 80% answered by an official introduction.
My first port of call is always the examples folder in the bevy repo, then the cheatbook, docs.rs, then discord.
When reading docs for bevy on docs.rs I frequently have to open the actual submodule docs separately, eg docs.rs/bevy_render to be able to click through certain parts or view source. This is a minor yet consistent papercut.
Often when answering questions on the discord I wonder how the user could have found the answer themselves, and more often than not I can’t think of a good way. I’ve written some notes in my bevy_best_practises repo on github to try and help here.
There are efforts underway in Bevy to rectify the situation, I am excited for the future here with passionate people in the Bevy project working on the problem.
Rust as a games langauge
I can easily inspect through my codebase with tools like rust-analyzer, and seamlessly open definitions into 3rd party libraries and the engine source and it’s dependencies. From coding in rust most of the time I’ve taken this for granted, but in other engines it’s incredibly jarring to not be able to do this, or have libraries you depend on be an opaque dll.
I’ve had surprisingly few issues integrating large 3rd party libraries and having them work smoothly with the rest of the game and other libraries.
Rust is a surprisingly nice language to write game logic in. Moving the responsibility of ownership into the ECS takes away the biggest typical “complaint” about rust, what you’re left with is simply awesome.
The feature set feels almost perfectly suited for use in an ECS. Enums (aka Algebraic Types), pattern matching, iterators, favouring composition, low-overhead, optimisablility, library ecosystem & cargo, macros.
Custom allocator support is one area I think Rust is still solving though, and game engines have well known allocation patterns and object lifetimes which can be taken advantage of.
Rust as a language for game dev is easily a whole separate article, in my opinion it is the dark horse of game dev.
Technical projects are not just the code. People are as important or more than the bytes in the repo. Bevy’s community is one of it’s biggest strengths.
The unique combination of Bevys features attracts a certain type of person at this point in time, and it’s a pleasure being part of it. I think Cart and the team have done a good job in fostering it.
There are also a few content creators on Youtube who regularly cover Bevy updates and do tutorials.
If you need help the Discord is always responsive, this the main way I currently contribute to the project.
I look forward to more community created content around tutorials, guides, and libraries as the community grows and Bevy’s foundations settle.
I hope my thoughts don’t come across as negative. These are my honest thoughts after 3 years of on and off use of Bevy. I eagarly await the future of Bevy and hope to get more involved as it grows.
I’ve only covered areas which I have strong thoughts or recent experience with. To cover every aspect of the engine I’ve used would be much longer, and I’m already at time to submit this!
By building projets in Bevy, asking questions and answering questions in the community, and writing libraries and sharing my thoughts, I hope I can contribute back in my own way to the project even if I don’t feel qualified to contribute code directly.
If you are interested in getting your toes wet in the ECS world and learning, I’d say Bevy is in a great spot.
If you’re planning a project with commercial aspirations and you need to ask the question, Bevy is not ready for you yet, check back in 6 months.
Thank you for reading.