Bevy Jam #2 Postmortem
This is my second time participating in a Bevy Jam.
I've done a few Ludum Dares before, so I'm not entirely new to the whole jamming thing, but I'm not as experienced with Bevy - and with the fast pace of Bevy development I felt as if I was getting constantly stuck at a beginner level (advanced beginner perhaps?). I have some of my projects going on, but I struggle at certain intermediate to advanced topics, most notably regarding the rendering APIs which aren't as obvious to me (I should probably learn-wgpu?).
With all that said, my goal for this Jam was to make myself learn a bit about rendering. The theme came to me pretty quickly, it was almost obvious - split the game into R, G and B channels (one channel per screen), and have players "combine" the information in those channels to solve tasks. I thought this would get me busy with shaders and RTT, which are certainly useful skills to have.
Development wise it went pretty great. It was amazing how far one could get by looking at the split_screen an post_processing examples.
I had my wife play-test the game a bit. To my surprise, she liked it on the first go, and had some good pointers about controls, level order and display. I also introduced a timer, foolishly thinking I could manage to squeeze in random level generation (and thus infinite gameplay), but oh well, it was nice to dream. I still like the timer as it makes the game more challenging, but I can understand how it can be frustrating at the same time - could see it in my wife's eyes in person...
The game ended up being as most of my games do - strong mechanics with no humor (props to people who manage to make such games). I'm particularly happy with how it turned out, and for the scope of the jam I wouldn't change it one bit. In fact, I think this format (informational screen-split) can be interesting for various types of games (mobile/web perhaps). The game is unfortunately one of the least played and rated games, but that's due to my lack of a WASM build, a fault entirely my own.
That all being said, as I was developing I wrote notes about things that went good and what went bad. Mostly the bad. So here's my list.
There are many problems that cause a slow iteration:
- I based my project on the https://github.com/bevyengine/bevy_github_ci_template template, and I've added the usual suggestions, including what I now believe are the "cursed" optimizations. These optimizations was a horrible idea for my project, and completely broke the Bevy promise of "Productive Compile Time" (0.8~3.0s). I was in fact getting 10s+ incremental build times in both release and the optimized debug modes, and this is with both the `--features bevy/dynamic` and lld/mold linkers (tried both, same-ish times but with mold being buggier in general). It was only after I disabled those optimization flags that I started to get semi-usable build times (~2.7s)
- My CPU at the beginning of this jam was i5-4690K, and it took ~515s for a fresh compile in debug + optimization flags and ~325s for a release build. Those are very high numbers in general, and can really hurt if you want to start a new project, or checkout some crate examples. Before the jam I setup sccache in order to reduce fresh build times, but after using it for a bit, it started generating various link-time errors, similar to what I've seen people report on Discord.
- Shader hot reloading was broken - I had to apply some workarounds (order dependent plugin setup) to get it to work. There are multiple Bevy examples "using it" - without it actually functioning correctly. Misleading examples aren't ideal - although I'm sure it'll get fixed if it isn't already.
- Setting the camera through egui inspector didn't fully work for me. I could set the Transform, but I didn't have an easy way to set the "look at" property. Camera is one of those things you definitely want to be able to tweak in an editor, and having to constantly recompile to test was quite annoying (especially with my slow compile times).
So that's in on the slow iteration issues. I did manage to improve my fresh build times significantly, got it all down to ~45s (debug), and 76s (release), a 4~8x increase in clean compile time. How did I do that? I got a new CPU. Yes, I spent a good 4+ days of the jam to research a CPU/Motherboard/RAM/Cooler combo, finally buy everything (i7-12700, 32G RAM, etc) and assembly by Saturday, and then actually do the remaining jam part on Sunday. Incremental times would still be unacceptably slow, at around 5s, so I just disabled those optimization flag, and I think those are still an unresolved problem.
Here are some other unsorted issues:
- CI template should have better Clippy defaults - Bevy is quite different from normal Rust projects, and certain things just don't apply. Here are my Clippy settings. At this point I found out that Clippy can't set global lint excludes in a configuration file like you can in most other linters, which is quite disappointing. I suppose this is more of a Rust ecosystem issue.
- Bevy timer should have a way to get the remaining time - it would just be more ergonomic, and I'm sure a lot of people use timers like that.
Near the end I started getting some "weird" crashes, of which I'll give one excerpt:
thread 'main' panicked at 'error[B0003]: Could not add a component (of type `bevy_render::view::visibility::render_layers::RenderLayers`) to entity 111v23 because it doesn't exist in this World.', /home/gajop/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.8.0/src/system/commands/mod.rs:764:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
On its own, this doesn't tell the user much. Setting the RUST_BACKTRACE didn't reveal anything, and as most experienced Bevyers(?) know, the key was in the `B0003` error. I think this is one of those cases where a better error message could help. Instead of writing the cryptic B0003 error (which most people will ignore as noise), it should point to https://bevyengine.org/learn/errors/#b0003
- Moving on, at this point I figured it would be nice to have a way to debug print the stage/frame information. Perhaps this already exists (unsure?), but it might help get an idea of what's happening.
Unfortunately, despite being set pretty well, there were a couple of annoying things with CI:
- I almost ran out of free GitHub minutes. I wonder if it's possible to have some sort of cache for the CI too, so it doesn't use so many minutes - I would've been in trouble if I completely ran out and had to do builds manually.
- My WASM build didn't work. It spewed some errors, I took a quick look and gave up. Despite CI being built pretty well, I suppose WASM just isn't at a state where an export would work out of the box. (I'm sure I could get it to work if I spent some time, but I was lazy)
- A minor issue, but the CI would create Linux binaries that had to be `chmod +x` manually in order to be runnable. Doing this myself and re-zipping still makes the executable runnable when unzipped on different machines, so it's definitely a thing that can be easily fixed.
Ok we're at the end of the bad things, and I hope it didn't feel like a huge whine - I'm used to writing every little small detail, mostly from my experience working with smaller game engines, in which I'd make it as an almost personal TODO list.
There were many things that went well, most notably:
- It was impressive how simple it was to specify custom shaders and implement RTT. I managed to do early setup in under an hour, and it was my first time looking at the code.
- Making the game was really a lot of fun.
- LDTK is an amazing piece of software. This my first time using it and everything just worked, perfectly. I never had to google anything, everything was just intuitive and easy. It's easily the most impressive experience I've had with software in a long while.
- I ended up buying a new PC which is just blazingly fast at everything!
Leave a comment
Log in with itch.io to leave a comment.