I Finished my first Rust Game - called “Some Tank Game”!
Source can be found here: https://github.com/horup/some-tank-game-rs
The aim of the project was to implement a full game (albeit a simple one) using Rust and using the Bevy game engine.
Why? More or less to prove my gut feeling that Rust is a great programming language to make computer games and that Bevy is an awesome engine with a lot of potential.
The game I implemented is nothing fancy, just a simple top down shooter. The game features four levels, pixel-art graphics, random collected sfx and music by Zander Noriega.
For fun, I tracked every hour I spent implementing the game, including play-testing, debugging, asset drawing, sfx searching, etc.
I started development the 27. of march and finished version 1.0 in the 2. of July. About 3 months of calendar development time. In this interval, I spent 65 hours in total or about 1 hour a day implementing the game.
I quickly got Bevy up and running and was able to draw some sprites. Bevy did not have tilemap support, so I implemented my own tilemap plugin which can render a tilemap consisting of many sprites batched into a mesh.
Bevys plugin system is really easy to work with. Simply define a struct and implement the Plugin trait and one can insert new resources, systems, etc. into Bevy.
The Entity Component System of Bevy is very non-verbose and easy to work with. Any struct (as far as I know) can be made into a component. Systems are implemented as plain functions and can be ‘wrapped’ as a system type for bevy to consume simply by calling
<function name>.system(). This operation will fail at compile time if the function cannot be used as a system in Bevy, e.g. if it’s signature does not match the signature of supported functions. Systems run in concurrently and locking of resources are automatically handled. Great!
For the game I needed a collision detection and handling system. Bevy does not provide this out of the box, but due to the plugin friendly nature of Bevy, I quickly found a crate,
bevy_rapier2d, that provides collision detection and response directly into the engine using rapier specific components and resources. Integration of this was a breeze! especially compared to implementing my own custom collision detection and handling systems.
For level editing, I used the excellent Tiled editor to construct my levels. Bevy does not support Tiled out of the box, but I found the
tiled crate which provides generic Tiled support in Rust. I wrapped tiled in my own asset loader and ‘bam!’ I had Tiled support in Bevy. I later learned that
bevy_tiled exists, which more or less does what I implemented - but hey, one less dependency :-)
Another awesome feature with Bevy is the build speed. By default, Bevy and the application compiles into a single ‘fat’ executable. This takes several seconds. However, Bevy also provides the ability to dynamically link to Bevy which reduces the compile times significantly.
I spent a lot of time getting Bevy UI to do want I wanted, specifically to render text in the correct positions and with the correct ordering. For a future projects I think I will opt-out of Bevy UI and instead use an immediate mode API such as egui through the use of the
For sound and music playback I initially went with what was readily available in Bevy, which is more or less a single audio channel and the ability to schedule a wave, mp3 or ogg file to be played. However, I quickly realized that I needed the ability to loop music and also stop and restart a music track whenever a level ended either through a win or a loss. I found the
bevy_kira_audio plugin which more or less replaces audio part of Bevy with the
Lastly, I created a simple installer using Inno Setup which bundles my assets and executable into a self-extracting installer.
All in all, a fun project with the following post-project reflections:
- Rust is an awesome programming language for Gamedev.
- Bevy is an awesome engine for Gamedev currently only lacking in web support and maturity.
Next steps is to see if I can port the game to HTML5, which is one of the goals of the Bevy engine (although still in progress and not yet realized as far as I can see).