Magus Parvus Devlog

I made a cozy little 2D top down mage game. You walk around the map, activating statues and killing enemies by casting spells. In this blog post, I describe my development process and the challanges I faced using the Bevy game engine.

The Game

The game Magus Parvus, which you can play on itch, is a small 2D top down game where you cast spells by typing them out. It's fairly short, but that's kind of the point. I wanted to make a very small and compact game that would teach me the basics of how to create a 2D top down game.

In this post I will focus on the technical implementation and some challanges that I see that need to be addressed to make the development process of this kind of game more feasible. The whole game is open source, so feel free to look around, fork the project or open a PR.

Implementation in Bevy

The game is made in bevy 0.12.1 and uses the following third party crates.

The main challange here was to get dynamic chunkloading to work with the bevy_ecs_ldtk package. Implementing physics and collisions with bevy_rapier2d was also a little tedious, but this is mostly because their documentation is somewhat broken (quite a lot of outdated href links). Apart from that, most of the development was concerned with implementing the actual features of the game.

Development Process

As this is only the second game I made in Bevy, there were still a lot of things I didn't know how to do and I had to figure them out along the way. That being said, I feel like I was able to make progress rather quickly, which I contribute to the fact that the workflow of the Bevy simply works better for me then that of engines like Unity and Godot.

Map Creation with LDtk

I chose to create the map using the LDtk tool, which is a feature rich 2D level creator. Using the bevy_ecs_ldtk crate, I was able to load the .json files generated by LDtk into Bevy.

I wanted to implement chunkloading into the game, however there weren't any examples or blogs about it (at least none that I could find), but luckily the maintainer of the crate is really friendly. I opened an issue and he was quick to guide me on how to implement it. Turns out, there actually IS an example on how to implement this, I of course somehow managed to miss that.

So following the example on how to load and delete level sections, I got a basic chunkloading system in place. This is actually a bit overkill for this project, but it's going to be very useful for future games.

Physics and Collisions

While I don't need any fancy physics in my game, I do need collisions and basic linear velocity. bevy_rapier2d is perfect for this. It's pretty straightforward, however the documentation is a little broken at places, so I had to look through the source code for certain informations (which is pretty common with most of Bevy I find).

The only issue I still haven't fixed here is how to handle camera movement. In Magus Parvus, the camera is always dead center on the player, at least it should. Because the player has a Rigidbody, it is controlled by Rapier, meaning I can't just set the camera position equal to the players position. I did manage to somewhat circumvent this problem by adding the current player velocity to the camera position, but that creates new isssues of it's own (when the player is walking into a wall the camera will be a little bit in front of the player).

Sprite Animations

Both of the above problems deal with the backend, which you write once and pretty much leave alone for the rest of the project. Animations on the other hand are much more problematic. The more content you add to your game, the more your workflow of adding the content matters. Physics and chunkloading are independent of the content size, they work the same if you have 1 or 100 different enemies. However, if your workflow of adding animations is by hardcoding sprite indices into your source doe, then you will have a terrible time managing this mess for even 10 types of enemies, let alone 100.

This is one of my major problems with Unity and Godot, their animation tools are really tedious to use (mainly because you must use the mouse, which tends to store relevant information in meta files. This works horrible with verison control). Bevy's built in solution is: ... Well it doesn't have one of course. I found the bevy_trickfilm crate to be quite intuitive, the API feels similar to that of Godot, but you define the animations inside of a .ron file, which means I don't have to use the mouse to create animations. The crate still needs quite a bit of work though, but that's to be expected. With some more work on the crate it should be much simpler to use sprite animations in the future.

UI

The game also has UI, which is kept to a minimum as I already know that UI is one of the worst parts of game development. Despite it looks, the UI for the spell book took my a dozen hours or so to implement. The code for it is fairly clean now actually, after many refactors.

Future Plans

My long term plan is to work on some more small projects like this one, all in the 2D top down style. The goal with each is to learn something new so that I can eventually work on bigger and bigger projects. I already have some ideas for future projects, so stay tuned for those. I also plan to make all of my future games open source and put them on my github, I will also write blogs about each of them here. Till then, keep it slow and steady.