In games you almost always need to define static design data that defines how various things like abilities, stats, etc. work in your game.
Unreal has the Gameplay Ability System (GAS) framework that handles this, but Unity does not so it is up to the developer to create their own solution to this problem (henceforth referred to as a GAS solution, but the system is not limited to abilities per se). This is significantly harder than it seems at first, and to this day I haven’t seen an example solution in Unity that solves the complexity of this problem.
Some examples of previous discussion:
https://www.reddit.com/r/gamedev/comments/8ltodz/composition_based_design_for_a_spell_system/
https://www.reddit.com/r/roguelikedev/comments/ctw6vt/unity_composition/
I believe there are some simple tenets one can make in regards to GAS solution:
- Favor composition over inheritance. A purely inheritance-based solution will quickly break down with increasing gameplay complexity
- Avoid code duplication and boilerplate
- Not superfluous unused fields. For example a base Ability god class that has range, cast time, and every possible ability field even though some abilities may not have a range or cast time.
- Make defining new gameplay data as easy as possible
I think it’s helpful to also define test example cases to check whether a GAS solution can handle them:
RPG Stats and Abilities
MP = 2intelligence + 3wisdom
staff: 20% increased intelligence, “primary spell range” +4
Defining Monster Types
You have various monsters, and you want to define a list of abilities and stats for each (and also ensure there are no duplicate stats). For example
Berserker
{
Stats: HP, Rage
Abilities: Whirlwind, Frenzy
}
Mage
{
Stats: HP, MP
Abilities: Fireball
}
Bloodmage
{
Same as Mage, but additionally:
Stats: Blood
Abilities: Blood Spike
}
Mind Control Chains
Targeting:
-
- target unit
-
targeting conditions: range (primary spell range) 10 from caster, enemy unit, target MP < caster MP,
-
- target circle area
-
targeting conditions: center range (this is not a primary spell range) 5 from target unit 1), radius 5
Effects:
- Set all tiles in target area 2) on fire
- caster player now controls target 1)
- all enemy units in area 2) are now chained to target 1) with chains of length 15. If all chains are broken by distance, then the spell ends
- consumes mana per second based on the targets level and how many enemy units were in the target area. when mana runs out, spell ends
- a % of the damage applied to the controlled unit is transferred to the caster as well, and that % grows over time
- once the mind control link breaks, both units are stunned for a duration that depends on how long the mind control was active
All data used to create this ability should be reusable and generic. For example, the area targeting in 2) should be the same component as targeting a ranged AoE fireball, except with the origin of the targeting range being target unit 1) instead of the caster.
Networked Overrides
Usually an ability is cast by a local player or AI, but in a networked game you need to cast the same abilities based off of player input information that you receive from the server instead.
Clicker Game
A series of purchasable buildings (building_1 through building_10) that cost gold to purchase and produce gold. The formulas for the cost and production of building_n are some complicated formula like
cost: log(n) * 10^n * max(n, 100)
production: 5^n * n^0.5
Every quantity in the game can be modified, including modifier values themselves. For example, and upgrade with purchasable levels where
n = upgrade level
g = current gold amount
Golden Power = ( logn(g / 10 + 1) * 5 + 1) + 1.4 ^ (n ^ 0.7)
Then Golden Power is a multiplier on gold gain per second, so
gold / s *= Golden Power
and other modifiers may modify Golden Power itself, so there may be another upgrade that does
s = current stone amount
Golden Power = 5log10(s + 1)
So you’d need a GAS solution to define all the currencies, building series, upgrades, etc.
Again, the solutions should be generic. So just like the gold currency has gold per second stat that can be modified, it should be possible for buildings or upgrades to have a gain per second stat that can be modified, e.g. City buildings producing Factory buildings that produce gold. This gain per second quantity component should be implemented the same way in each.
These examples are purposely complicated, but they’re not far off from game design data you will come across in actual games.
Purpose
The purpose of this thread is to attempt to find a GAS approach with example code that fulfills all the test cases. You of course wouldn’t use the exact same code base in the RPG and the Clicker game, but the approach should be applicable to both.
Has anyone been able to find a concrete GAS solution approach that fulfills the above requirements?