I’d suggest making your class inherit from Resource, and making the base attack class fairly broad. A Resource is a kind of object with instances that can be saved to disk, and those instances can then be dragged into script variables in the inspector.
Example
Maybe your base attack class looks something like this:
class Attack: Resource {
[Export] public int Damage = 0;
[Export] public Element ElementalAffinity = Element.None; // enum of elements in the game
[Export] public StatType AttackStat = StatType.Strength; // enum of kinds of stats
public virtual void OnAttack(Character source, Character target) {
target.hp -= Damage + source.Stats[AttackStat];
if (target.IsWeakTo(ElementalAffinity)) {
target.hp -= Damage;
}
}
}
Here, most attack definitions would be instances of your base attack class, rather than subclasses. Every time you needed a new attack, you could make a new instance of your Attack resource, save it to disk, and then plop it into the UI or Character or whatever stored available attack definitions.
Here’s what a few attack resources might look like, written in pseudocode (with Resources, you would input these values in the inspector):
Bash:
Damage: 10
ElementType: None
AttackStat: Strength
Poisoned Dagger:
Damage: 5
ElementType: Poison
AttackStat: Dexterity
If you needed an attack to do special behavior, you could override OnAttack. For example, maybe some attacks should cost mana.
class Spell: Attack {
[Export] public int ManaCost = 0;
public override void OnAttack(Character source, Character target) {
if (source.mp >= ManaCost) {
base.OnAttack(source, target);
source.mp -= ManaCost;
}
}
}
And your new resources could look like this:
Magic Missile:
Damage: 5
ElementType: None
AttackStat: Intelligence
ManaCost: 5
Fireball:
Damage: 20
ElementType: Fire
AttackStat: Intelligence
ManaCost: 20
Of course, it’s up to you what you include in the base class vs in its children, and there’s a lot more behavior you could add to either (attacks that heal the source or target, attacks that hit multiple times, etc).
I’ve kind of rambled on a bit here. TLDR:
- Make a base attack Resource
- Define new attacks as instances of that Resource whenever possible.
- If you need new functionality, add it to the base class or create a new subclass of your attack Resource