Rat With a Gun – Devlog #1

I’ve started work on a new game. You play as a rat with a gun tied to its back, sent out to kill aliens at the behest of a gun-toting Rat God. Simple stuff. It’s shaping up as a platformer of sorts where you use the kickback of your gun to gain height and stomp on your enemy’s heads. I’ve got some ideas for how I’m planning to lay out the levels, but I’m focusing on the basics first.

I started off by making a robust player state machine. It’s by no means exhaustive yet, but encapsulates basic movements and keeps the players behaviors nice and contained. I decided to express the states as nodes that are managed by the handler, but instead of having player behavior be defined by the individual states, I had them make calls to the main player class for things like jumping, movement, and so on. While it makes my player class rather large and unwieldy, it prevents me from re-implementing simple functions in each state. For example, the left-right movement function is referred to by most of the classes, so if I need to implement any changes to movement physics, I don’t have to update each class. I considered passing similar functionalities down through an inherited state, but decided against it so that I could easily override behaviors in the future, like with a power-up that changes how the jump works. I wanted to add such effects modularly, so that’s informed a lot of my decisions in deciding how I wanted my state machine to function. Summarized, gamestep calculations and inputs are sent from the player to the state manager. The manager then runs these through the state. The state runs through its functions, which are implemented back in the player class. The state then returns either a new state based on what it knows, or a null, which tells the manager to keep it in its current state. Hooray!

Wish I had relationships as rich and complex as my state machines.
Look at all these perfect little nodes.

The player implementation is an inheritor of the actor and state classes that I made, and they’ll be used by entities as well. While I’d like to have more modular control over entity design here (e.g. add a “jump” node to an actor and now it has the ability to jump), I do appreciate the control and relative safety the state machine brings. Still, I reserve the right to complain about how long it takes to set up.

I’ve also set up basic movement options for the player, kitted out with various standard bells and whistles; variable jump height, coyote time, input buffering, and so on. Speaking of buffering, I’ve been kicking around an implementation of a Command pattern system that would plug into my actor classes, and would allow me to both keep track of inputs as well as easily implement all manner of input buffering. It would also make custom controls a breeze, though that’s already pretty simple in Godot.

Anyway, once I got the basic run-and-jump-type stuff to where I liked it, I set up a skeleton for the shooting system. While there’s no bullets flying just yet, I thought I might as well map out how I’m going to have the kickback movement work. I first set up a skeleton for the Gun class, and made a blank prototype gun that passes back its kickback power. For now, the player will be launched along a vector opposite from where the cursor is when they shoot, though I’m already becoming aware of some poor game feel as a result of doing this. For now, due to the verticality of the play field, I’ve restricted a lot of the right-to-left impulse, though I’m considering just changing the system to only recognize if the bullet is aimed up or down, and discarding the horizontal influence of the kickback altogether. Testing, testing, and more testing will be needed.

wheee
He doesn't have a gun yet, but he has spunk.

Tabling that for now, I also set up some simple prototype enemies and some stomp fields that the player can jump off of. The implementation is simple (though it required setting up a new state and a bunch of new state relationships) and it allows each stomped-on entity to handle the results themselves. As it stands the player briefly holds a reference to the hitbox of the stomped actor, which is a dirty little hack that is begging to throw errors about null references. I did this because the step where I get the interaction comes before the state that utilizes the information I get from it, and I need to store the values through the state change. I wanted to make sure the player bounce and the resultant enemy reaction happen in tandem. I’m gonna smooth out in the future, I promise, probably by pulling the information I need first and “bouncing” the enemy before I “bounce” the player. Don’t code like this at home kids.

Also, I set up PAIN detection and health for the player, but it doesn’t factor in to anything much right now. I’m not ready to start sweating about UI yet, and I still need to set up a Hurt state, but we’ll get there when we get there.

It has no mouth, but it must scream.
Peep the horror of placeholder assets.

On the visual side of things, I’ve been making do with placeholders. I originally was going to go for a pixel style, and I set up a viewport so that I can render the scene in low resolution; however, I’ve become rather fond of digital painting lately, and rather tired of trying to get pixels to look right. I think I’m going to pivot to a loose, messy painting style in the hopes that it will might cut down on the ridiculous amount of time I spend agonizing over art dev. Work with an artist? What? Who? Leave me alone! I have a process!

My next priority is fleshing out my gun class, getting bullets onto the screen, and finally figuring out how I want kickback physics to work. After that, I’ll probably start working on some base enemy systems and basic AI, just so there’s a proper backboard to throw ideas against. I’m gonna try to work on consistent devlogs with this game, unlike I did with Dispelling Bee, in an effort to keep my work more consistent as well. So far my year has been a disorganized mess of disappearing weeks. Here’s hoping for better!

Leave a Comment

Your email address will not be published. Required fields are marked *