Download

Looking for some ideas/solutions - dynamic skill system

I’ve been working for quite a while on “skills” for my game. Rather than hardcode every skill, I created a system where skills can be created on the fly by entering values for a struct. My current setup is as follows

BaseItem - Simply a shell “item” (actor) that will serve as the base for all other items/skills (what are skills but items that are equipped in a specific way and don’t get consumed?)
Each BaseItem contains an array called ItemEffects of type EffectStruct.
Each EffectStruct contains several other structs dealing with the target of the effect, cost to use it and the impact.

When a BaseItem is used, each EffectStruct is looped through. Before anything else happens, the blueprint obtains an array of targets - who will this skill be affecting? For each target, a BaseEffect is created. The BaseEffect is an actor that is passed in the corresponding EffectStruct. The BaseEffect then applies its effect to the target. The idea is to have one effect per target. The BaseEffect is destroyed once the effect ends.

With this system I can do the following
Add an EffectStruct to a BaseItem. Specify the cost to be 10 mana, specify the target as “Self”, specify the impact to modify the current health by +5.
Add another EffectStruct. Specify the target as “Cursor” (script will get the actor under the current cursor location when the item is used), specify the impact to modify the current health by -5.

That item will now cost 10 mana, heal you for 5 and hurt your target for 5.

I hope this makes sense so far, I know I’m not great at explaining things.

There’s one more important aspect of this system which is the center of the problem. In the EffectStruct, there is also a selection for the effect’s type. I define the type as one of the following

  • Instant - The effect is applied once immediately
  • Delayed - The effect is applied once after a specified delay
  • Duration - The effect is applied immediately. Then, after a specified delay, the effect is negated and applied again. (Ex: Gain 5 health for 10 seconds. First it gives you 5 health, then waits, then takes 5 health away. The delay can also be unspecified and the effect will persist until otherwise cancelled. One other note on duration effects that might be important… if you have 8/10 health and use an item to gain 5 health, the effect keeps track of how much you actually gained. When it comes time to negate the effect, it will only take away 2 instead of 5)
  • Pulse - The effect is applied N times with a specified delay between each application where N is the specified number of pulses.

You could have two effects on a single item with different types. Where I started having issues was what if I wanted to have an Instant effect that was only applied after the Duration ended? I could go and create a bunch more effect types, one for each possible combination of types. But that’s messy and I’m trying to make this as dynamic as possible. Besides, what if I then wanted an effect that applied for a duration, then applied an instant effect then a pulse then another duration? It’s probably not a skill that would ever be created but the framework needs to be in place to allow this if it’s needed.

So … the problem is that BaseEffects created from the same BaseItem need some way to communicate with each other. I need to be able to create an effect once the current one has finished. So far my thoughts on how I could do this are as follows:

  1. Add another struct to EffectStruct called “SubEffect”. This would also have the type of EffectStruct and would allow me to specifiy effects that would only be created after the parent had completed. This was my ideal solution. It’s simple and intuitive. I found out quickly this will crash UE4 since it tries to recursively add SubEffects. A structure cannot contain a reference to itself.
  2. Compile the effects in BaseItem. Before I spawn any BaseEffects, loop through each of the EffectStructs looking for a new flag that says “This is a subeffect of effect N”. Then, when creating effect N, also pass in any specified subeffects. The effect will then create the subeffect when it is done. It’s messy to implement and requires non-intuitive setting of EffectStruct values (I would like others to be able to use this system easily). That being said, I do really like the idea of having the parent effect create the subeffect.

This isn’t just for creating effects after a duration. What if I wanted to make something that said “Deal 5 damage to an enemy then heal for that much”. The healing effect would need to be passed information from the first damage effect (if somehow some of the damage was mitigated and you only did 2 damage to the enemy, I would need to ensure you were only healed for that much).

So BaseEffects need to be linked somehow. But I have no idea how to properly approach this. It’s severely slowed down progress on this project.

I know posting this here is probably a futile attempt - this is a big block of text explaining a system I created without much for documentation. The chances that someone will read this and understand it well enough to be able to contribute to it is probably pretty slim. But I had to try.

Thanks for reading

I am not claiming this is the best method, but if I were you I would use a single BP as an effect controller that would handle all effects in your game. When a skill goes off, it would pass important info to the effect controller BP(transform, duration, type, etc), and that BP could use that info to decide what effect to play and even mix it together with other effects.

I generally do this with most of my systems eventually, even if they start off separate and chaotic as they are prototyped in. It makes cleaning up, reading, and upgrading your code easier. It makes debugging easier since you know all trains run through the one station. It may also be more performant, but I haven’t bothered testing that theory(it would depend on your exact situation anyway).

Ok, it’s worth a shot. This is my first time doing something like this and I’ve already re-worked it a few times, so what’s one more? :slight_smile:

What class would you use for that kind of BP? I’ve been using actors for all my stuff but I can’t help but feel like there’s a more appropriate one. Also, how would you reference this BP from the individual characters?

I use just a plain old data actor, though there might even be a simpler one that they have added recently called a data actor. Or it might already know it is a data actor if it doesn’t have a mesh in the world. Those patch notes are too big to remember sometimes… :stuck_out_tongue:

I spawn all my controllers in game mode, since it can initialize everything at the start of the game and every BP can call it directly.

Good call, thanks for the responses.

Be careful of the struct bugs :stuck_out_tongue:
*Was a good read

Nice system you have going here.

Thanks, so far it only works OK. I’m trying to make something that others would be able to use without going into blueprint. To be able to create or modify the effects spells, abilities or items by modifying parameters and values rather than muddling through blueprints. Plus I thoroughly enjoy modular and dynamic systems.