Building an Upgrade System in Godot
Cosmetics! Effects! All using the power of Godot Nodes and Resources!?
Last week, I released Bola Brawl, a chaotic “survivors”-style roguelike where you swing a bola around you to attack! This is an entry to La Gameja 2025, made in a team of 3 during the course of 1 week.
You can play the finished game here: albertalberto.itch.io/bola-brawl
Fair warning, the game is currently VERY difficult, so you’re in for a challenge :)

This blog goes into the implementation of a certain feature: the upgrades!
This game features 28 different upgrades that go from silly puns to a variety of references to previous “Gameja” games. At the end of every round, you get to choose between one of three upgrades (or skip the upgrade to heal back to full health).
This was my first time handling the implementation of an upgrade system like this, and I’m very happy with the end result being as clean and scalable as it is. And it wouldn’t have ended up this way if it wasn’t for Godot’s Node-oriented design.
So, let’s go step by step into how upgrades are built from the ground up, going from the simple to the complex!
What is an Upgrade?
We knew we wanted to feature upgrades from very early on. However, just saying “we want upgrades” is pretty aimless. It’s important to ask what exactly constitutes an upgrade.
Mechanically, upgrades were defined as being able to change these three things:
Apply changes to player statistics (like increasing the base move speed).
Apply more advanced effects that react to game events (like doing something whenever you kill an enemy).
Apply cosmetics to the player and bola (like adding a funny hat on the player).
Additionally, we wanted to be able to represent upgrades in the user interface in a way the player would understand, which means each upgrade should also have data about its name, description, icon, and flavor text (just for fun).
The Core Data
In Godot, the easy way to handle custom data like this is by using Custom Resources. You can define a script with whatever data you’d like to store.
That way, we can have an “UpgradeData” type of object that will contain everything necessary to make an upgrade!
So let’s start with the simplest part, the UI data.

Just after adding a couple variables, we can already create distinct upgrades with their own properties as separate objects!
But, despite the description, the upgrade doesn’t do much of anything yet if you select it. We also need to find a way to represent the effects in data.
Player Stat Changes
Changing player statistics with upgrades is ridiculously straightforward although it really makes me think “God I wish there was an easier way to do this.”
So, we want to edit the player stats, right? Well, the first part is having those player statistics somewhere. Because this was a game jam, we just handled it with a globally accessible singleton, so the statistics can be referenced from anywhere. Convenient.
The important part is making sure these statistics actually affect the way the player behaves in-game. So, if you’re increasing the “speed” stat, make sure that actually affects the player speed how you want it to in code.
(I’m speaking from experience here. I may have forgot to make custom stats affect the player more than a couple of times during this game jam…)
Then, each upgrade defines a variable for every type of statistic modification we want to do. Want extra max health? Sure. Want to add move speed? Alright, another variable. Want to multiply max health instead of adding? That’s a completely different thing, another variable!
Finally, we have the function in charge of applying every single one of these modifiers correctly onto the player stats. This is where we define that the stat modifier with the name “move speed add” does, in fact, refer to adding its own number to the current player move speed.
So if we wanted to introduce an upgrade to touch on a new stat, we’d need:
The stat itself, that affects the way the player behaves when modified.
A “stat modifier” variable in the upgrade data, that defines how and how much that stat changes.
A line in the function to apply the desired change to the stat based on the modifier.
And once you have this set up, you can apply changes to that stat from any upgrade!
Cosmetics on the Player… And Advanced Upgrades!
Surprisingly, thanks to Godot, we can do a two-in-one for this next step.
If you’re a little familiar with Godot, you’ll know that “Nodes” are the fundamental building block of the game. They represent a specific functionality, no matter if it is collision detection, showing an image, a user interface element, or an animator.
This got me thinking. What’s stopping me from turning upgrades into nodes in the scene, instantiated on the player, so they can execute their functionality on their own, while also showing whatever cosmetic they want on top of the player?
The answer is: Nothing is stopping me!
The first upgrade to be prototyped with this system was the “Party Hat”. Whenever the player throws their bola, it creates an explosion on top of them, damaging surrounding enemies. Obviously, it also comes with a cute little hat on top!
So first, we define a scene with all the nodes we want. We have the script that summons an explosion whenever a ball is released, the “hat” sprite to overlay on the player, and some confetti particles that show up whenever an explosion happens.
We can reference this scene inside of the UpgradeData of the “Party hat” upgrade by adding the proper variable field.
Then, whenever we select an upgrade, if it has a scene defined this way, we’ll slap it on the player alongside whatever functionality and visuals it has. Handy!
The beauty of using nodes for this is that upgrades can be as complex as needed, and have as many extra functionalities as you want. Want the visuals to be animated, or have some extra particles? No worries. Want to have “Happy Birthday” play every time an explosion happens? Go off I guess!
Want to make the instanced explosion scale in size and damage with the size of your current bola? Hell yeah, let’s do that, it will be fine… Won’t it?

We tried to keep most upgrades relatively simplistic for this jam. Partly because of scope, and partly because we didn’t want overcomplicated descriptions for what each upgrade did.
And that’s About the End of it
Thanks for reading this far! I didn’t cover absolutely everything concerning this, just the basics and what I deemed most important about this (Substack is already screaming at me about this post reaching email length limit).
It was an amazing experience to develop this game over the course of a week. Not only I’m pretty happy with the final result, I’m also starting to feel like I can wrap my head around Godot’s intended game architecture way better!
Reminder that the game is up and available at: albertalberto.itch.io/bola-brawl
And reminder that the game is currently extremely tough. If you actually manage to beat it in its current version, let me know :^
Thank you so much for reading this far. Feel free to share any questions or suggestions you may have.
Also, if you enjoyed reading this, and aren’t subscribed yet, I’d appreciate if you subscribe. It’s free, and only requires your email!









