Rogue-like skill system

I’m new to UE5 and would like to make a system of skills like in Vampire Survivors: after getting a new level on the screen there are 3 skills, each time they are randomized from a large pool of skills.

Some skills require intervention in the main character’s blueprint, for example: “you get an extra bullet” (released from “scene” as “actor”). after selecting this item somehow an extra scene should appear in a slightly different place.

I would be glad to get help or a link to youtube videos

You can write each skill as an individual Uobject.

You will probably pass in the owner (the player character) as a reference so that the skill can easily communicate with it.

Active skills can be held in an array - perhaps you just fire off events any time a key game thing happens (like you reload, or fire, or jump) and each skill can listen for whatever events that it is interested in and act accordingly.

For instance, you have an active skill called “extra ammo” and with that you get 25% more ammo from pickups. It might bind to an event called “On Ammo picked up”, and then it just calculates the 25% bonus and then calls the “Add ammo to inventory” event.

That would make for pretty good code reuse and extendability. Since the extra ammo skill is separated to its own class, you can easily add things on like an sfx jingle each time that it is activated, for example.

Epic has a robust system for this sort of thing, but i think it will be hard for a beginner to implement and probably major overkill. It’s called GAS (gameplay ability system) anyway, if you want to take a look.

this is not a tutorial for a skill system but it demonstrates how to work with uobjects if you need help with that:

Hey BigTimeMaster, I’m reviving this thread because I’m also a beginner with some wide questions about programming abilities that “listen” for game events like the one you’re describing. Following the “pick up ammo” hypothetical - I’d have some sort of setup “normally” that triggers “add ammo to inventory” when “on ammo picked up” occurs. I understand that you could set up a binding on the skill to listen for the “pick up ammo” event, but I don’t understand how that binding could intervene in the “add ammo to inventory” event by the time it happens unless you code that event to look specifically for the skill.

I guess overall I’m struggling to understand how can be done without “brute forcing” it by checking for all applicable skills from the perspective of the event, rather than the skill “listening” and changing the event itself.

Not sure I understand exactly what you mean by “intervene”. I will elaborate little more about how things work in a couple of my projects:

To be honest, maybe this is a brute force way, I don’t really know what that means exactly. But when it comes to elegant code, I don’t care about that. What I care about is standardization. Standardized code is easy to maintain code. So this is the basic pattern I use concerning events:

For any important thing that happens in the game, I have a Pre event, an actual event, and a post event.

So for example, we interact with some item.

Interaction Pre
Interaction Actual
Interaction Post

Often times I do not use all of these events, but I just set them up by default because sometimes the event sequence order does matter.

So an inventory system might listen for Interaction post, and at that time you know that the interaction system will have processed whatever was picked up appropriately. Whereas if there is only a single “interaction” event, you might be doing the processing at the same time the inventory system is asking what the item is.

I’ve found that this staged sequence of events makes pretty consistent and maintainable code for most situations.

example pseudo code:

  • Interaction item becomes valid (this is polled for by a collider on the character)
  • player presses interaction input
  • Preinteraction event dispatched
  • interaction system checks if interaction item is valid
  • isValid → interaction event dispatched
  • valid interaction item is queried to determine what it is
  • interaction items identifier is passed along with Post Interaction Event dispatch
  • Inventory system binds to the Post Interaction Event and sees that ammo type item was picked up, and handles what to do with it

Some of those events might be redundant in some situations. Like you might not care about pre or actual event with some systems, they could bind to either event. That is just nature of standardization, there is some inefficiency. But overall you gain maintainability.

I would not want for abilities/skills to have to know about other ones. Events can live in the game state, game mode, a subsystem, game instance, or a component which attaches to one of those. This way there is a globally accessible class for calling the events and binding to them. Like a central relay tower. Actors in the level all know about it, but not each other (or skill objects associated with any actor). It facilitates communication between them but breaks any hard links between them.

As for data, I would not want to keep that within skills/abilities themselves. Rather in some other global access storage. Can be game mode or similar, or component which attaches.

So then all important data that any skill wants to query is in a single place. Definitely don’t want for X skill to have to query Y skill.

This might be too high level to be useful, but big ideas behind this architecture have more written about them here:

you dont have to intervene exactly,
say you pickup 10 ammo, you call an event saying ‘ammoadded’ with an int of 10. the skill could listen to that event and it knows it adds 20% ammo so it can do the math and add 2 extra ammo. this would be a separate event, lets call it ‘bonusammo’ so it doesnt loop itself.

Or you can have a variable, ammoaddedonpickup and the skill adds 2 to that value

Appreciate all of the writeup here, this is really good perspective.

So in this scenario - the skill would bind to the the interaction event dispatch such that it would modify the post interaction event dispatch by the time that got back to the inventory system? such that the “10 ammo” value from the item itself could be modified by the skill?

I’m not sure that I fully grasp this but I think I can kind of see how breaking up the sequence into more discrete parts allows the external “listeners” to modify things before they get to the part in the sequence where values need to be read or discernible effects take place

no problem.

it does seem like there is some misunderstanding still, but i’m not quite sure where.

I don’t know exactly what you mean about modifying the skill. What sort of skill is this? I was only using a basic interaction like pickup ammo as an example to illustrate the basic communication flow where it goes from actor in the level to an abstract, global event handler to enable a one-to-any communications style.

Do you mean that you want a skill to do something like this:
If you have BandolierX5 skill, you pick up 10x more ammo? (an example)

so then you are saying that you want the skill to sort of be able to intercept the interaction process to do its magic?

If that is the case, then what I would do is not house that sort of logic in a skill class itself, but do it more data oriented.

Then in your inventory system when a pickup is processed, and then it is determined to be ammo, you can check for skills flagged with “ammo multiplier” or similar.

This might be looping through an array of skill objects and querying for some identifier. Or the skills might even just be an array gameplay tags or enums or even bools. Basically just some sort of list that tells you what skills are present, and then you can find data about those skills either from reading a data table, or querying actual instanced objects representing those skills, or data assets… probably a few more ways you could do it as well. I’m a big fan of data tables but each way has some pros and cons.

If you set things up that way, there may not be a compelling reason to have the skills be wrapped up as objects anymore… kinda depends if they tend to just be multipliers and simple data like that, or if they do a lot of logic on their own.
If it is mostly simple data then what I’ve suggested should work fine.

If a skill means that a ton of unique logic needs to happen then not sure it can stay so simple. I mean you can handle all of the skills logic in a manager class as well - I do that - but it only makes sense for single player, solo developed projects because it creates a lot of tight coupling.

If you handle reading of skills like this it means that whenever you add a new skill you may have to go update whatever systems it potentially modifiers, so it’s probably not technically as modular as something like GAS, however i think for typical indie game projects the total time cost and energy cost is likely to be a lot lower to have more simple code that you understood because you built it, even if its requires some manual tweaking here and there.

In any case, if you work out the execution flow, then where you put the code isn’t so difficult.