TorchBear is a game about a bear with a magic torch, fighting hordes of evil monsters. You have bear cards and torch cards. Your bear cards are stronger the more bear cards you have in your hand paw, and same with torch cards for other torch cards. A simple concept used to help me prove the viability of my card-game system in Godot.
I lost my job in January 2024, when the studio I had worked at for 3 years, Little Red Dog Games, was shut down. This was particularly bad for me, as none of the 3 projects I had worked on during my time there got published, so I had no credits to my name. The first was cancelled after my first 11 months, a hotel management game in Unreal 4 that did not yield the fun we had hoped it would. We had been prototyping a fantasy mercantile strategy game in Godot, before it was shelved in favor of our Unity tactics game that was a year away from releasing. Both projects sank along with the ship that was LRDG.
With the freedom of unemployment, I went on to develop a card-game system in my new favorite game engine. The purpose of it was to be a foundation for any card game I wanted to design, and I think what I made is pretty darn close. All I needed now was to test whether the foundation I laid was sustainable.
I was initially inspired by the (now seemingly abandoned) project "godot_card_engine" by Olivier Boucard (BraindeadBZH). However, I required a
What I liked or found interesting:
type equals spell.However, there was still a lot that needed changing and fixing. Converting from Godot 3 to 4 broke much of the project, and took months to manually debug and fix (in between adding my own features). I eventually replaced the tween animation system (which did not survive my convertion) with a system using AnimationPlayer nodes.
Instead of Resources, EVERYTHING was saved via text files. My first change was replacing non-user data, like specific cards or card zone layout data, into Resources (comparable to ScriptableObjects in Unity). All of the editor tools were closely linked with these text files, saving and loading directly into them, and thus had to go. I replaced them with a custom editor tool co-designed by a LRDG colleague of mine (details on that later in this post).
As I developed TorchBear, the card data consisting of only Strings and ints began to be too limiting. I resisted for the longest time, but eventually followed the footsteps of the Slay the Spire devs: each distinct card would be its own script file, its variables and functions manually written out. They would no longer be Resources, but RefCounted. An instance of each card would be statically loaded to a list at the beginning of the game (replacing the need for the Database class which did the same thing). Because of these changes, the Query system had to be refactored as well. While I thought the way it was handled worked well, this new method I like moreso—instead of distinct syntax for different ways to sort and filter between texts, categories, and values, it would all be Expressions. Godot has this handy little class that can parse single lines of text written in GDScript syntax, even those written at runtime! While a bit more verbose than the old system, it was much easier to read and lacked the specific syntactic quirks.
After the demise of LRDG, my former tech lead, Denis Comtesse, wanted to work on an addon in Godot. He designed FRED, the Flexible Resource EDitor, whose purpose was to provide custom, user-friendly layouts that were harder to achieve with the normal inspector tab. Godot's entire user interface was made with the same UI tools it offers it developers, making it as easy to make these editor tools as it is to make a scene for gameplay. Each data type would have its own widget, and you would construct the scene with widget instances for each variable that you wanted to be editable. The scene would automatically connect those widgets to the resource's variables, saving and loading their values seamlessly.
While Denis laid the ground work, I added some much needed features. The addon was made before Godot had statically typed exportable Dictionaries (previously only non-typed Dictionaries were available, and were a hassle to use without dynamically populating them). I introduced a complex Dictionary widget that allowed for static typed Dictionaries.
I also added options for editing internal variables through Expressions. For example, if you only wanted to edit the x value of a Vector3, that would be possible. You could even edit array and dictionary elements this way. If your resource had a dictionary that always shared the same key between instances, this would streamline the time needed to add it—instead of adding the key and value for each resource, the key would already be there, waiting for you to input the value. I even included an optional, "optional" toggle, that could add or remove the key value pair from the array or dictionary.
After my refactoring of card data resources, and with Godot's new exportable typed Dictionaries, I eventually switched to just using the inspector panel to edit some of the Resources. However, FRED was not without use, and still had a certain advantage: I could easily staple on custom widgets more easily than I could in the inspector. It also provided cleaner views of variables in a pleasant-to-look at layout (which for some larger Resources, was a must). Card zone layouts needed a lot of data, and I made a custom window to visualize how cards would be placed on them.
I also utilized FRED to make a widget for my TurnOrder Resource, which detailed the order of phases (such as draw phase, mana phase, player turn, etc.). The real use of this was to show off "blocks" of phases, which were harder to visualize in the inspector. Blocks would condition the phases it contained, such as "only one player should be experiencing these phases" vs "players simultaneously experience phases." Or maybe the phases should restart from the beginning of the block after it reaches the last phase. Or all of the above. Blocks could be contained within other blocks.
I am not that great of a digital artist. I could never get comfortable with a drawing tablet, and the ones with screens are too expensive. This being a personal project, I also did not have the budget to hire other artists. For these reasons, I resorted to free online asset packs.
The enemy sprites, as well as the background tiles during the encounter, were sourced from the "Doodle Rogue Tileset." This was really the turning point for the game artistically, as it cemented the art direction into something cute and scribbly. Using it as a jumping off point, I made my attempt to emulate the art style and drew the bear with a mouse in the vector art program Affinity Designer. I mixed together a couple of bear and torch reference photos, drew a rough outline, and scribbled in the colors and shadows. Came out quite well in my opinion, and it looks cohesive with the rest of the sprites.
The cards were also created by me in Affinity Designer, through the use of its many vector shape tools. I followed many a tutorial, while also looking at other digital card games I admire as inspiration, taking bits and pieces of their designs for my own. I always wanted the bear cards to have little ears on them. I am not as satisfied with the torch card design, but I could not make complex fires to my liking with the limited tools at my disposal. I compensated that by making the selection outline a bit fiery. Big thanks to RJ, a friend who pointed me in the right direction to figure out the shader, as I am ignorant in the dark arts that they call "tech art."
The icons for the bear, torch, and honey attributes were drawn by me in, again, Affinity Designer. All other icons come from Game-icons.net. The remaining UI elements I sourced from "Kenney's free asset library.
On a quick note about the music: I think ragtime is an underrated genre of music! People often associate it with showtunes, but I think it has much more range than people give it credit for, and thought it would fit organically with this game. As I do not have the equipment necessary to record music, I found these free recordings by Ragnar Hellspong on his website. The pieces I used were "Troubadour Rag" by James Scott and "Stoptime Rag" by Scott Joplin, both in the public domain. The intro music was "Decline" by Kevin MacLeod.
TorchBear was originally a bunch of disconnected ideas. One was a passing thought of a generic fantasy card game, where you had cards for different classes, and the more of one class's card you had in your hand, the more powerful they were. You could have Warrior cards and Cleric cards, and then maybe Paladin cards that could gain bonuses from both. There wasn't much thought about how it would actually work, but I jotted it down anyway and promptly forgot about it.
At a later point, I was rather enamored by Alan Wake 2. It had a rather infamous musical number that got stuck in my head, and as the bars kept repeating in my brain, it eventually distorted into silly nonsense.
Restricting it to just two card types, Torch and Bear, added both simplicity and a surprising amount of depth. There would be an inherent friction both turn-by-turn and while building the deck. Were the game to grow beyond this prototype, I had plans to explore the eccentricities of deckbuilding in the ecosystem of two card types. Two such features include a "morality" system and a "card pack" system. The game's true ending would only unlock when balancing the two card types in your deck, rather than favoring one over the other in an attempt to optimize, in addition to two "bad" endings for relying too heavily on only Torch or only Bear cards. For card packs, you would be presented with multiple packs to choose from, each with 3 cards of a single type that synergize with each other.
I also wanted a way to make cards distinct from each other outside of status effects. Giving cards different shapes seemed like a fun way to do so. While the shapes in the prototype are rather limited (so far only the Fire Ball, which attacks in a cross-shape), the opportunities presented are limitless. Being limited to strings and ints made arranging different shapes for card data too cumbersome, and is one of the main reasons I changed the data structure for cards to be more open ended.
Were I to revisit TorchBear again, there are many things I would need to change and improve upon. If you've played it, you might notice some oddities with the way events queue up. Most obvious is when you bring an enemy to zero health. They might not die right away, but instead wait until the next turn to play their dying animation. This has also wrought some rather annoying bugs, as on rare occassion the events never fire, or fire multiple times.
Currently, an EventQueue is comprised of its name (like "draw_phase" or "foe_attack") and three queues—before, during, and after—as well as a "finished" signal/delegate. The queues themselves are comprised of QueueItems that are either delegates themselves, or names of AnimationPlayer events to fire. The most common way it works is that listeners would listen by being added to the before queue, and when that fires add a oneshot QueueItem to the during or after queue. Sometimes it would chain other event queues this way. Once a before, during, or after queue is starts firing, however, it cannot be edited in any way; if you want to be reactive, you have to add it to the
I think the ultimate killer for the queue, and why it needs to be refactored, is it wasn't made to handle animations; its ability to wait for animations is limited as it was stapled on after the fact. That, and some overcomplexities in the actual enqueueing of items, have given me the knowledge I need to remake it in the future, which I'll likely do for other projects.
Other issues mainly lie with the incomplete refactors and hardcoding of systems into what should be abstract classes. Some functions to handle after turn effects, like enemy attacks, movement, and status effects, were written directly in the CardGameplayManager class, rather than extended to a specific inheriter class for TorchBear.
There are also two different attribute systems: the old one which needs replacement, currently in use for player stats like Hearts, Honey per turn, or Bear card bonus, and the improved, streamlined attribute system, in use by the cards and enemies.
So, if I were to return to TorchBear, things I would work on (in no particular order):