So in my game at the moment, the player can control many characters, each with their own default weapon. The weapon these characters use will never change, but the special ability that it associated with the weapon can be changed for another. Since the player can control any of the 3 characters at any time, I use an inherited method from a parent class to create each weapon, then call said method.
But in the case of creating the special abilities, depending on the weapon, I may have to pass in additional parameters. Since different abilities for the same weapon will always have the same parameters to call the “use” method, my first though is to create a base class for abilities for the weapon, lets say “GunSpecial”, then let the abilities for that weapon inherit that method. Since I need the game to recognize that each SO instance is a special ability, I can maybe make an interface with a simple enum that defines for what weapon the special is compatible for, as well as marking the ability as a “special”.
I’m just not too sure if there is a better way of implementing this as I am sure that there are better ways to approach this. Any help is welcome!
You can do this a bunch of ways. A Decorator pattern might work well but it really depends what you are trying to do going forwards but the simplest solution would just be to create an interface called IWeaponthat all the weapons implement and give it a property called SpecialAbility of type ISpecialAbilityon that interface you can add any properties or methods you need to determine the effect of the special abilities.
For example
You could have on the ISpecialAbility interface a simple float
that acts as an attack damage multiplier.
Then any implementation of ISpecialAbility would have to also implement that damage multiplier and it can be used when using an IWeapon implementation.
What this also means is that at runtime all you need to do is swap out the implementation of ISpecialAbility with another and everything should still be able to work as expected just with the different implementation code to determine how that ability functions.
Example
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IAbility
{
double AttackMultiplier { get; }
}
public class MegaAttack : IAbility
{
public double AttackMultiplier { get; } = 1000;
}
public class UltraAttack : IAbility
{
public double AttackMultiplier { get; } = 10000;
}
public interface IWeapon
{
IAbility Ability { get; set; }
}
public class Weapon : MonoBehaviour, IWeapon
{
public IAbility Ability { get; set; }
public double AttackStrength = 5;
void Attack()
{
Debug.Log($"Attacked with a strength of: {AttackStrength * (Ability?.AttackMultiplier ?? 1)}");
}
void Update()
{
// Example of setting the ability at runtime to a different implementation
if(Input.GetKeyDown(KeyCode.Alpha1))
Ability = null;
else if(Input.GetKeyDown(KeyCode.Alpha2))
Ability = new MegaAttack();
else if(Input.GetKeyDown(KeyCode.Alpha3))
Ability = new UltraAttack();
// Using attack which multiplies your attack strength (if set) with the current ability
if(Input.GetKeyDown(KeyCode.Space))
Attack();
}
}