I want to be able to switch between multiple abilities, so I use ScriptableObject assets to contain them, and they’re called from a PlayerAbilityScript attached to my Player GameObject.
All abilities have a manaCost and coolDown, but only OffensiveAbility:Ability have damage and range.
I’ve got it working fine, but now I want to create enhancements that the player picks up that can alter properties (damage, manaCost, castingTime, coolDown, etc) of all or just some specific Abilities. But I can’t figure out a way to code it so that it works with the ScriptableObjects.
This is my code, very simplified:
public abstract class Ability : ScriptableObject
{
public string abilityName;
public float manaCost = 0f;
public float cooldownTime = 10f;
public abstract void TryToUseAbility(PlayerAbilityController controller, PlayerAbilityController.AbilityData abilityData);
}
// ------------------------------
public abstract class OffensiveAbility : Ability
{
public float damage = 10f;
public float range = 10f;
public override void TryToUseAbility(PlayerAbilityController controller, PlayerAbilityController.AbilityData abilityData) { }
}
// ------------------------------
[CreateAssetMenu(fileName = "New ProjectileAbility", menuName = "Abilities/New Projectile Ability", order = 1)]
public class ProjectileAbility : OffensiveAbility
{
public float travelSpeed = 50f;
public GameObject prefab;
// Called from PlayerAbilityController when player presses a key
public override void TryToUseAbility(PlayerAbilityController controller, PlayerAbilityController.AbilityData abilityData)
{
if(abilityData.coolDownRemaining <= 0)
{
CreateProjectile(controller, abilityData);
abilityData.coolDownRemaining = cooldownTime;
}
}
void CreateProjectile(PlayerAbilityController controller, PlayerAbilityController.AbilityData abilityData)
{
// Code to instantiate and initialize prefab to travel in the correct direction, deal damage according to parameter in OffensiveAbility, etc
}
}
// ------------------------------
// The class that modifies stats. No idea how to write this class.
public class Enhancement : ScriptableObject
{
}
// ------------------------------
public class PlayerAbilityController : MonoBehaviour
{
[SerializeField] PlayerController playerController;
[SerializeField] Ability[] abilities = new Ability[2];
[SerializeField] AbilityData[] abilityDatas = new AbilityData[2];
[SerializeField] List<Enhancement> enhancements;
void Start()
{
for (int i = 0; i < abilities.Length; i++)
if (abilities[i] != null)
abilityDatas[i] = new AbilityData(abilities[i]);
}
void Update()
{
foreach (var abData in abilityDatas)
if (abData.coolDownRemaining > 0)
abData.coolDownRemaining -= Time.deltaTime;
}
// Called by event when player presses left mouse button
public void Ability1Input(InputAction.CallbackContext context)
{
OnAbilityKeyDown(abilityDatas[0]);
}
// Called by event when player presses right mouse button
public void Ability2Input(InputAction.CallbackContext context)
{
OnAbilityKeyDown(abilityDatas[1]);
}
void OnAbilityKeyDown(AbilityData abilityData)
{
abilityData.ability.TryToUseAbility(this, abilityData);
}
// ------------------------------
// Contains non-static data belonging to the ability.
[Serializable]
public class AbilityData
{
public Ability ability;
public float coolDownRemaining = 0;
public AbilityData(Ability ability)
{
this.ability = ability;
}
}
}


