top of page
Resistance and Debuff System
Overview
Going into this project I knew that I wanted to focus on something that involved data storage and manipulation, as this was not something I had gotten to explore in previous projects. With this in mind, I came up with a resistance system that dynamically effects status debuffs applied to the player.
This system was designed to naturally alter the difficulty of levels as the player progresses through a game. Resistances can be increased both as a reward for completing levels, or minimally through being exposed to debuffs. In other words, if a player is struggling with a level, then they will also slowly be building up their resistances to make it easier with each failure. This could be used in a naturally restrictive open world where every zone is accessible from the beginning and has a recommended resistance level. These zones will be extra difficult if the recommendations are not met.
Debuffs:
In order of difficulty

-
Slow: Reduces the player's max move-speed.
-
Cripple: Reduces the height and distance of jumps and dashes (movement abilities).
-
Bleed: Applies a damage over time effect.
-
Dark: Reduces a player's view distance by creating a fog of war effect.
-
Paralyze: Completely stops character movement and prevents player inputs.
-
Poison: Applies a lethal damage over time effect, curable with antidote.
How do resistances influence these debuffs?
Staging debuff effects
Each debuff goes through a similar staging phase when applied to the player. First, it retrieves static data from a data table that stores information like the maximum duration of a debuff or the maximum power of a debuff. Then, it increases the player's resistance by 1 and retrieves the updated resistance value.
Once it has this information it can do the necessary calculations to determine details like the life-span and effectiveness of the debuff. Each debuff affects the player differently, so the effectiveness can be different for each debuff. For example, the slow debuff will both last less time and slow the player less, based on the level of resistance you have. Conversely, the lethal poison debuff will last longer and deal less damage over time, giving the player more time to find an antidote.

Initial Staging of the Slow Debuff: Link to Code
Managing Player Stats
Introducing the Game Instance
When interacting with player stats, such as resistances and health, I chose to work within the Game Instance blueprint. It is commonly used for data management because it is globally accessible and persists between levels.
So, what does my game instance do exactly?
It serves 3 main functions:
-
It updates the player's resistances.
-
It communicates the player's resistances to other blueprints.
-
It tracks health, applies damage, and initiates death when appropriate.
Tracking Resistances



Resistances are stored within a structure that is manipulated by the Game Instance blueprint. When another blueprint needs access to a resistance value or needs to update a value, then it can easily communicate that to the game instance through a blueprint interface (BPI). Both these functions are fairly simple too. The event/function takes in the name of the resistance it needs to access and funnels that information through a switch statement to carry out its job.

Example of 'Get Resist'
Link for Code
Similar to 'Increase Resist'
Link for Code
Tracking Health
Tracking health was primarily needed to showcase the bleed and poison debuff, and because of this I kept the logic very simple. Health is stored as a variable in the game instance, and is only altered by a 'damage' event. This event takes in a float variable 'amount' of damage to be applied. It then adds whatever that amount is to the current health and checks if the player is below a certain threshold. If the player is below 0.5 health, then it triggers a simple death sequence before resetting its value and clearing the character of any active debuffs.

Deal Damage Blueprint: Link to slightly outdated Code
Managing Debuffs
Introducing the Debuff Manager
When I set out to complete this project, I expected data management would be the biggest challenge. To my surprise, it was very straightforward. It took some time to learn the difference between Curve Tables, Data Tables, Structures and what each of them excelled at; but eventually they became very useful and intuitive tools -except for curve tables, those things are a pain. The real challenge began when I needed to manage all of the different debuffs and their variety of connections.
Debuffs needed to communicate with the data table, structure, player controller, widgets, and sometimes even the post processing material! Shortly after making the slow effect, I realized I needed to separate the debuff blueprints and trigger them from somewhere else. So, I created the debuff manager.

These widgets are controlled by the lifespan of debuff blueprints
Debuff Manager
The debuff manager is an actor blueprint that is placed in a level and responds to different triggers. It takes in the name of the debuff that is being triggered and then spawns the appropriate debuff blueprint attached to the player (helpful if you want to add particle effects). It then sets a reference to the blueprint actor and if it is triggered again, it checks to see if that actor exists in the world. If it does, then it tells the debuff blueprint to reset its lifespan, rather than spawning a duplicate blueprint.


Debuff Manager Trigger and Event: Link to Code
How to Trigger
A major benefit to having a debuff manager, is that triggering from other blueprints is very easy. This makes implementing new mechanics that need to trigger debuffs as simple as communicating what debuff to activate to the debuff manager.

All the code required to trigger a debuff
Link to Code
To make things even easier I exposed the Resist Name variable, so it could be set independently of duplicate blueprints. With that variable, I used a switch statement to set the physical traits of a 'trigger object' to indicate what kind of debuff it would trigger on runtime. Simply dropping in a trigger object and typing in a debuff name will give me any 1 of the 6 debuff triggers I want.

Example of Trigger Objects on Runtime
Wrapping Up
Takeaways
I'm very happy with the experience I'm walking away with. Data management in Unreal Engine 5 turned out to be a lot simpler than I had expected, and I learned a great deal more than that. This was my first time using Unreal's modeling tools and it is quite an improvement to the alternative Geometry Brush Actors. I also got a lot more experience using Blueprint Interfaces. It's wild to think I only needed to cast two times for this whole project! If it's not obvious at this point, most of my previous experience was in Unreal Engine 4. So, there were a lot of new features for me to explore.
If you're interested in the Blueprints for each debuff, I've listed them below along with the video presentation of the project for FIEA:
-
Slow: Link to Code
-
Cripple: Link to Code
-
Bleed: Link to Code
-
Dark: Link to Code
-
Paralyze: Link to Code
-
Poison: Link to Code
bottom of page