Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs

Fantasy RPG Card Battle Game

A topic by Callum John created Aug 17, 2018 Views: 384 Replies: 9
Viewing posts 1 to 8

So after a bit of coaxing from users on the GBJAM discord, I decided make a little game inspired by Pokémon: Trading Card Game on the Game Boy Color and the Fire Emblem series.

This is the story of my failure.

(1 edit)

Day 0

So after recieving no replies to an earlier post asking about how much I was allowed to prepare, I decided that it was OK to go ahead before the starting gun so long as my work wasn't directly related to the final product.

The first step would be to decide what tools I would use to bring this so-called Fantasy RPG Card Battle Game to life. At first I was considering going with LÖVE, but ever since LOWREZJAM 2018, I couldn't help but find it lacking when it comes to longer-form jams like this. Unless I was willing to sit through hours of boilerplate code and class coupling, I figured that it wasn't going to cut it this time. Enter Godot, an engine that I've been trumpeting from the rooftops ever since the release of it's third major version, but never actually finished anything with. like LÖVE, it's free and open source, but it has an edge for an RPG like this in that it features its own shading language and user interface system, which is integral to a turn-based RPG like this.

Now that I'd chosen an engine and a language (I'll be using GDScript for this one since it's the one I'm most comfortable with) it was time to take a critical look at how I was going to stick within the rules. Rule 1 is a bit of a bust, since as far as I know my direct inspiration doesn't run on the original Game Boy models, but rules 2 and 3 I knew I could clear before the jam even started!

Setting up the resolution was fairly simple. Once I'd muddled my way through a few keyword searches I could staple down the default resolution to the required 166x144, and configure the game's window to be resizable by default in such a way that the viewport always maintained the correct aspect ratio and filled the center of the screen, with 2D, nearest-neighbor scaling.

Getting the game down to four colours was a little more tricky. I could just make all of my assets in four colours and call it a day, but what if I don't like the colours later on? I'd have to go over every sprite, background and nine-slice just to sharpen up the contrast! Even worse is when someone else doesn't like my colours. With so many people playing and rating games, how am I going to ensure that I keep everyone happy? What if I could just make my assets in linear greyscale and just tell the game which colours to use instead? This sounds like a job for...

...Shaders!

Shaders are computer programs specifically designed to tell your graphics card what to do when it comes to putting things on the screen. Your typical shader has two main components; the vertex shader and the fragment shader. The vertex shader runs once for each vertex in a mesh (which could be each corner of a sprite or other texture) whilst a fragment shader alters each pixel currently visible to the projection. By changing the properties of each, you can create a whole host of different effects, like heat haze, motion blur and cartoon-like cel shading.

Unlike most things you do on the CPU, shaders require a bit of forward planning. In an idea I totally didn't steal from the web series Makin' Stuff Look Good, we'd use a palette sampler texture like this one:


and use it as a horizontal lookup table. For each pixel on the screen, we figure out how red it is as a normalised value between 0 and 1, and replace it with the colour found at that location on the palette. Brighter grayscale colours would have higher quantities of red light in them, and would therefore be replaced with brighter colours, so long as the palette was sorted from left to right as above. If we ever decide that the palette is inappropriate, we just load a different texture.

After my brain adjusted to the fact that screen-space effects have to be applied to an object in the world with the projection as a parameter instead of a script telling a camera to draw a projection using a shader, I grabbed Aseprites official Game Boy palette and hit Play:


At first, this looked great! Not only had the shader converted the greyscale Tetris screenshot, but it had also converted the default Godot icon, which had it's own set of colours. But something about it felt off. Looking a little closer and opening it up in Aseprite revealed why:


All of the colours were ever so subtly different. It's most obvious at the edges of things that are supposed to be anti-aliased. It turns out that by default, Godot attempts to make your textures look smoother through a process called Billinear Filtering, in which the colours of each texture fragment are averaged out with that of the adjacent colour in the texture, blurring them together. As of writing it, I haven't found a way to reliably turn this off, but I have found a way to ensure that only a fixed number of colours are displayed. This meant that the shader was finding the correct texel, but it was a floating point value on a much larger texture, meaning that each fragment returned it's own value.

At first I tried converting the entire image to greyscale before applying the colour swap, but that didn't do anything. After someone suggested that I might be able to use posterisation to limit the amount of colours on-screen, I tried rounding the x value in the shader to see what would happen:


Perfect one-bit colour. This would be fine if I only wanted to use two colours in my game, but I knew that I and anyone else using this shader would need the full four. I'm terrible at maths, but that same person suggested that I could use the following formula to round in even increments of the whole:

x = round(x * a) / a

where x is the horizontal UV location of the desired colour, and a is the total number of colours. it then took a bit of tweaking for the shader to be sensitive to the width of the palette in pixels, but thanks to Godot's handy textureSize() function, I now had a robust effect I could be proud of:


It's still not perfect, mind you. Creating the texture images required by the shader is slow and reading them is even slower, but this is more than capable for my needs. I think I'm ready for this.

If you want the shader, it's free on Github: https://github.com/ItsSeaJay/godotboy

(1 edit)

If you haven't found out already, you can disable filtering in the Import tab after clicking the texture and disabling the Filter checkbox and clicking Reimport. There used to be a project-wide setting for that but I can't find it in 3.0.6... But the antialising is from the icon itself actually.

I looked and I found it. There's a seperate 'import' tab near the scene tree that allows you to configure default settings.

Thank you!

Day 1

So after waking up to a brand new github repository, I immediately started to do some rough sketches of how I wanted the game to look:


One is a simple layout that explicity resembles a tabletop game, and the other two are closer to a traditional RPG. I asked the Discord which one they liked best, and they all seemed to pick the first one, which I neatened up into this:


Once I'd decided how I wanted the game to be laid out, I then started to configure a new Godot project with the Godotboy shader I made the other day.

I figured that my main focus should be extremely basic actions, and so after a while of muddling my way through some rather confusing calculations, I ended up with this:


You have a randomised deck of cards that you can draw from up to a maximum of four. Though you'd only know that if you read the debug log:


The only thing I haven't got working is moving the cursor around to allow you to select cards. I would use mouse controls for this, but I'm not sure you can plug a mouse into a Game Boy. Allowing the cursor to figure out which card it should snap to based on the direction you pushed is going to be quite a challenge, but hopefully it should be worth it for the amount of cards you're able to see at once.

(1 edit)

Day 2

Disaster!

So as I logged onto my computer eager to breathe some life into the game I was taken aback by this message:


my password manager stopped working.

Despite the fact that I attempted my login using the exact same computer, location and credentials, their system randomly decided I was a filthy hacker. "Not to worry" you might think, just "tap the app". I don't have a mobile device and forgot to set up 2FA. "Try a different device?" my laptop gave me the same message. "Check your e-mail like the message says?" well I would, if I remembered the password that's locked inside the password manager that I'm currently locked out of.

Needless to say this is kind of a big deal, and until I can convince customer support to give me my account back, no work will be done on the game. I mean, I still have a local clone of the source and could continue to keep working on it, but I wouldn't be able to focus at all.

UPDATE: I've now regained access and am swiftly moving to fix this single point of failure. Development on the game will resume soon.

Day 3

I had personal matters to attend to and couldn't work on the game.

Day 4

I didn't sleep well that night and couldn't bring myself to work on the game, not even a little. Disappointing, yes, but at least I know what went wrong.

Day 7

I'm pulling out. Remember day 3 where I said I had personal matters to attend to? Well those haven't really gone away and I need to focus on dealing with them. I knew from the outset that this project was ambitious, but I didn't know how ambitous it was until I realised how difficult it is to deal with being able to select a dynamically sized hand of cards with a controller. I thought switching to mouse controls very early on, but I was too stubborn and was worried how it might affect my ratings if I went that route.

I have thought of ways that I could finish it by the end of the day, such as shifting the objective to not require another player at all, but I don't want to deal with the crunch. After LOWREZJAM, the damage was done; I was just too drained to immediately start working on something large I wasn't entirely sure of.

Though what little I did manage to make was an interesting challenge, and I'll definitely consider coming back next year!

Good luck everyone!