Minerva Labyrinth - a dark magical girl dungeon crawler

It’s been an incredibly difficult year for me, so my game development has had to fall by the wayside for a while. I’m trying to find ways to remotivate myself, so I thought I would try posting about it here.

Minerva Labyrinth is a traditional dungeon crawler (chief inspirations being Wizardry and The Bard’s Tale) with magical girl and horror themes. It takes place in an unnamed medium-sized city in the southeastern USA, sometime in the mid-21st century. You control a party of magical soldiers and explore extradimensional labyrinths to eradicate a twisted horde called the Hate. The website is here and has some gameplay footage, screenshots, and devlogs. This is my second dungeon crawler, the first being a jam game that I released in 2020.

I have been working on this off and on (mostly on) for a few years, and it was getting pretty close to completion until Unity blew itself up last year. I have started converting it to Godot, but the process is extremely painful and demoralizing, and has quite a ways to go.

The blurb:

In the 1990s, humanity finally comes together on an unprecedented scale to confront the global climate and energy crises that threaten its future. Decades later, humanity thrives in a new era of cooperation and humanism, and the recent rediscovery of ancient magic promises miraculous new advancements. Yet as human strife recedes, something dark and forgotten returns from deep in the earth…

excited to see a post for this!

most my experience with drpgs is etrian odyssey - this seems to have something similar with front/back rows (though i imagine that’s hardly new for drpgs) and i feel like i rarely see indies in this genre at all.

id be down to hear more about what the process of porting is like, with godot. I’ve definitely seen devs that switch over, for one reason or another, but don’t necessarily go out and rebuild a project that was already in progress. Or when they do it ends up being an opportunity to change a lot of things and the end result is pretty different. Has your process been mostly to stick to the original plan? What are some of the bigger hiccups, outside of just getting into the groove of a new engine?

I appreciate the support, it means a lot.

It does have front and back rows for both players and enemies, although the mechanic is more strict than in EO (which I actually never played until… right now, with the Steam release). I do take a little bit of general inspiration from JRPGs here and there, and I borrowed a lot from Experience’s games in designing an interface that is playable with a gamepad.

It’s true that there aren’t many indies (or anyone) making games in this style, although there are a few. Part of it is just that the gaming press completely ignores this genre. The EO Steam trilogy might have gotten a mention, but other than that, the last one I can remember most of the press even speaking about was The Bard’s Tale IV (incidentally, one of the worst RPGs I have ever played).

I have tried to convert straight over as much as possible, but there are some things that I took the opportunity to improve, such as using Godot’s signals to simplify some of my convoluted input and event code.

The most difficult part has been that Godot SUCKS at handling data-driven design. The inspector will only display classes that inherit from Node or Resource, no custom classes at all. There are also other irritating limitations to the inspector, like (as of 4.1 at least) the lack of typing on dictionaries and the fact that generics break the entire editor.

An example of how this disrupted my conversion is items. In Unity, inventory and equipment were handled entirely in code and didn’t physically exist as GameObjects. This didn’t work in Godot because, if I recall correctly, I couldn’t actually assign items to chests or enemies in the inspector, because InventoryItem was a custom class. Instead, I had to rework everything to handle items as Nodes, even though there is no reason or benefit to doing so.

There’s also a really irritating behavior around duplicating objects, either in the node editor or in the project view, in which Godot only makes shallow copies of everything. This means that, for example, if you have a node that contains a List of integers, and you duplicate that node, the duplicated node will be pointing to the same List. If you change the List on one node, you change them both. WTF would I want that behavior? You can break these links and do a deep copy, but you have to do it for each object individually. There is a “deep copy everything” button, but it doesn’t work. Note that there is no clear indication that an object reference is shared by other nodes or resources.

One thing that bothers me in the back of my mind is that Godot’s “everything is a node” mentality is directly at odds with the fact that the manual explicitly warns you not to use too many nodes at a time. How many is too many? The manual doesn’t know. I also gather that nesting nodes too deeply is a performance problem, just like in Unity. But when everything is a node and every node is composed of other nodes, given that pure data is generally unusable, how am I supposed to avoid that?

This week I’ve been picking at getting my current workspace set up for development again, a little bit at a time. This weekend I finally stepped back into the project and got a few small features migrated over. It has been a long time since I have been up for continuing, so it was nice to make some progress again.

I decided to take a break from raw code migration and try migrating the first level of the game, the subway station. This is an extremely simple level that serves as the introduction and tutorial. All of the geometry is in place, so now I need to migrate all the scripted events. These are things like dialogue and flavor text, switches, treasure boxes, and enemy encounters.

Actually building a real map as opposed to a test room has helped me better contextualize the migration work I have been doing, plus get used to what my workflow will look like in Godot and fill in some gaps there.

Today I got the save / load game functionality mostly migrated, except for the GUI and some of the validation and error handling. Line for line most of the code worked as-is, since it was mostly just serializing C# data to and from JSON. Most of the changes I had to make were because some of the data has been rearranged over the course of converting to Godot. I think it is better organized now than before, though.

I don’t do anything fancy with my saves. I just serialize only the data that is necessary to reconstruct the game state and write it to several JSON files. The files being human-readable is very helpful for testing. I don’t really care about maximizing compression or trying to prevent players from modifying them.

Godot has its own classes for file and directory access, but they’re awkward, so I opted to stick with the built-in C# classes. I am not sure if there is a reason I’m supposed to use them, or if they were just obligatorily copied over from GDScript for parity.

Looking great so far!

I wanna ask a question I hope doesn’t sound off. What was your motivation here for building this in Godot/Unity on your own as opposed to using something like RPG Maker?

Looking great so far!
I wanna ask a question I hope doesn’t sound off. What was your motivation here for building this in Godot/Unity on your own as opposed to using something like RPG Maker?

Thanks! Control, basically. I wanted total control over all of the rules, mechanics, and presentation, including the first-person perspective. I’m not that familiar with RPG Maker (the only version I ever tried was '95), so it might be more flexible than I think, but I really wanted to build my own systems from scratch. My stats, my die rolls, my GUI, my cadence of gameplay. Working out the rules is part of the fun, anyway.

From what I know, there’s an RPG Maker module out there that hacks in first-person, but I’ve played one or two games made with it, and it doesn’t seem to work very well. Which is not to criticize, I’m sure it works as well as it can.

When I developed the precursor project in 2020 that became the groundwork for this one, I had already been working with Unity for a little while, so it seemed like the natural choice to continue with. I had actually attempted a similar project years before with a Java-based engine called jMonkey, but I really don’t recommend that one. At the time, I only chose it because I was also trying to relearn Java professionally after not having touched it for many years.

After Unity blew up last year, I tried out a few other engines. I settled on Godot because despite being a paradigm shift from Unity, it still seemed like the most capable and the most able to support the code base and workflow that I had developed under Unity.

I finished migrating the “lifecycle” of the game, meaning that you can start or load a game from the main menu, save or load in-game, quit back to the main menu, transition between levels, and have your party wiped out (for which I can configure one of several results). A lot of this was GUI work, and I don’t like GUI work, but fortunately Godot has pretty good GUI tools.

One thing I particularly like in Godot is its implementation of signals. Obviously Godot did not invent this (it’s just listeners / observers), but Godot explicitly promotes it as a preferred design pattern and builds in GUI and code support to trivially define and connect signals*. As a result, I have made much more use of them than I did in my Unity code, which has helped decouple a lot of my components and simplify communication. In particular, I have a singleton that I call SignalDispatch that allows me to have any component anywhere listen to any signal it needs to hear. This has been a boon in reducing how much intercomponent wiring I need.

Not much to screenshot here, sorry.

* Granted, this is an engine dependency that would need some work to redo if I had to migrate again. Good thing you don’t need an online account to access Godot.