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:
- 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.
- 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