I am trying to implement an ability system in Unity for a game similar to XCOM (turn based, team consists multiple of units, grid based). Every unit have X action points per turn.
I would like to do it in the way that everything that unit can do per turn is an "ability"
- Moving is an "ability"
- Attack is an "ability"
- Spell is an "ability", etc...
I searched and found out that that it would be suitable to use Scriptable objects. The idea is there would be a base abilty class from which other abilities inherit.
public class AbilityBase : ScriptableObject
{
public string desc;
public int actionCost;
public virtual void Execute(){};
}
And other abilities would look like this
public class HealAbility: AbilityBase
{
public virtual override void Execute()
{
//GetComponent<Unit>()
//Check if Unit has enough action points
//If so then apply heal
};
}
Which would propably work fine. Every unit would have some sort of AbilityManager which would hold references to the ScriptableObjects abilities.
The problem with this solution is:
- Some abilities (Taking cover, healing) can be applied on caster itself. It can get a reference from inside Execute method.
- Some others needs to have targed in form of a unit (Attack on another unit)
- Some needs a target in form of a grid Node (throwing a granade, AOE spell)
The Execute method takes zero argument and inherited classes cannot modify that.
Questions:
- How could I solve this problem with missing target references? (How to pass target into a ability?) The target of abilities could also be of a different type.
- Abilities that takes target needs to pick it first. So it should indicate that to the player (for example other units light up). Same with an ability that takes a grid node (Allowed nodes would light up). Should this be implemented from inside the ability itself or should it handle the parent script that uses abilities?
My possible solution to questions:
- Since the game is grid based, the all the targets will propably be on an grid node. So theoretically passing an grid node or an array of nodes to the Execute method could work.
void Execute(GridNode[] nodesToCastOn)
Then the Execute method would look up which unit is standing on the nodes and apply its effect on them. - I think it should not handle the ability script, because it the ability should not wait for player input.
If anyone managed to read this far I thank you. Do you thing my solutions would be Correct? If no, could you elaborate why not and/or breafly explain your solution?
I will be thankfull for any insight from you guys.