Looking for advice on implementing an Ability System a la Overwatch

Hello everyone!

I’m coming here today kind of desperate :p. I am attempting to create an Overwatch demake in the style of a 2D platformer. I’ve implemented many of the gameplay systems (like weapons, health, etc.), but I’ve been stuck on abilities for quite some time.

For the last month or so, I’ve been researching the various ways in which people implement ability systems into their Unity games. For example, I came across these 2 great forum posts ( here , and here ), this video from the official Unity YouTube channel, and several more resources; however, while trying to implement many of these methods, I’m finding, or at least feeling like, they don’t fit my needs.

I sat down and tried to make a list of the characters I want to add, their abilities, and then tried to categorize each ability in a way so I could see what logic some of them may share, etc. It seems to me that MOST of the abilities in the game are just different enough from each other that I can’t categorize them together. So, in my mind, that eliminated ScriptableObjects from being used.

What I need help with/what I’m asking:
I’ve read way too much into this, and I’m absolutely feeling stuck on this problem. I’m not sure how I should even begin to think about adding abilities in this style to the game. Overall, I’m asking how you would implement an ability system in this style:

  • All characters have 2 abilities, some have 3, some have a passive ability.
  • Some of the abilities are Toggleable (Soldier: 76’s sprint ability, Bastion’s transform ability), some are Timed (Tracer’s blink, Reaper’s invincibility form), some fire once (Winston’s leap), and so on. Is a big inheritance tree inevitable with this?
  • Some abilities have multiple charges (for example, Tracer’s blink has 3 charges, each with a 3 second cooldown, 9 seconds total)

ANY tips on how to implement such an ability system would be beyond appreciated and I would be happy to clarify anything if needed (my brain is very fried).

The game I’m working on has a similar system with space ships, where each ship has a unique set of powers similar to Overwatch. I just use straight up components on the object, one branch deep deriving from an Ability class. Ability defines the bare minimum: UI icons, state (available, cooling down, whatever else you need). Like you said, each power is so unique that you basically have to hand script every single one and most of them interfere with the state of the object too much to keep agnostic – like Bastion, as you noted – it’s working fine so far. Keep it simple.

2 Likes

I‘m just a noob but I‘d structure it like that:

  1. Build a template ScriptableObject class for all abilities. It would have several virtual functions like „ManualyActivate“, „TrigerActivated“ „TimerTick“, „Checkifavailable“ or „Deactivated“. It would basically contain all possible functions abilities could have. It will also have icons, descriptions and such things. Basically everything but any player data.
  2. Add lists of actions like public List. One for Avery state of the ability like begin, run, end.
  3. Write a base class with virtual functions for these actions (again: ScriptableObject).
  4. Implement the different actions.
  5. write the final implementations for the abilities that will access the lists of actions.

finally:
6. Write an AbilityController monobehavior that will be attached to a player. It would contain a list of available abilities and manage them like calling functions and also keeping all variables. That way you can use the abilities on different characters without conflict.

This is the approach I was leaning towards, so I’ll probably stick with it. Thank you!

I would just program each ability and strip out any reuseable parts into their own class afterwards.

Abilities would be stored in a list (of type Ability, or IAbility), and would have an Update function that is called so they can recharge, etc.

Your “CurrentAbility” is just an integer that represents the element in the list. When pressing the correct key, you would just do AbilitiesList[CurrentAbility].Execute();.

1 Like

I don’t have time to write up a lot of detail but here’s a hint. Make your abilities work through a single interface with flexible plugin-like features.

For example, in my games (all of them) I have a single MonoBehaviour attached to each entity called ‘Tool’. It simply takes a ‘ToolEffectAsset’ as a drop-in as it’s only editor UI element… That’s it. What is a tool effect? Well, it’s a serializable asset that implements the IToolEffect interface. This interface provides just a couple basic commands that allow me to control the Use, EndUse, and ContinueUse events of the tool. This allows for anything from a single one-off ability, weapon firing, or event or even allows me to have charge-up abilities and weapons. The tool itself doesn’t do anything. it just provides this simple universal interface for use. The effect assets are where the real work is done.

I have lots of tool effects. Many are for common audio and visual effects. One such effect, ToolSoundEffect, plays a sound (with several configurable aspects like audio clip, volume, looping, etc). Another effect, PlayAnimationEffect, tells the owner entity of the Tool behaviour to play an animation. Another spawns and plays a particle effect.

There are also gameplay effects. The, SpawnProjectile, spawns an object derived from ‘Projectile’ with a variety of starting parameters like speed, direction, lifetime. Another allows me to activate or deactivate gravity on the owner of the tool. Another allows me to make the owner invincible for a time. Another moves the owner forward to perform a dodge or dashing motion. And so on.

I also have utility-like effects. For example, the ToolEffectList is simply a list of other tool effect assets that can be dropped in and when triggered it activates each in a sequence. This way I can attach several of the above effects to a single master effect. Another effect takes a single effect as a parameter once again, but activates it after a configurable delay. And so on.

Using this system I can accomplish several things: 1) Build complicated series of effects that are all tied to a single ability/weapon/event/whatever. 2) Reuse the same effect assets for multiple entities so that they are all sharing memory and not bloating it with loads on un-needed copies of the exact same data (this is important since I might have hundreds or even thousands of entities all using the same effects at the same time). 3) Swap out entire effect chains with a single asset, effectively allowing me to ‘change weapons’ or ‘change character classes’, or ‘upgrade abilities’ with a single line of code at runtime or a single drag n drop operation in the editor.

I’ve used this system for build highly configurable weapons used by both the player and the NPCs in a bullet-hell game. I’ve also used it for a retro-style beat em up that allowed for various button combos to perform different attacks or chained attacks. I plan to use it next for a dungeon crawler with classes and equipment and such.

The only really tricky part was the cases where you actually do need instanced information per tool owner rather than shared data. In this case each tool has a blackboard object (I use the one from nodeCanvas). ToolEffects can use an interface to create runtime variables to store temporary data. You just have to make sure that your system properly ensures no two effects overwrite each others data and that you clean it up when effects are removed.

It can be a little bit of boilerplate to get this stuff working at first but you’ll find once you get the skeleton of the system ir starts to become easy to add new effects as needed until you eventually have a nice library of them at which point you’ll spend much less time writing code and more time configuring effects and trying out new ideas. The best part is that you can even use this system to hot-swap things at runtime so you can play around with different things until you like what you see!