Here is my current approach.
- Create a class that updates ranges, and checks through available cooldowns. The order of priority is based on its position inside a list/array.
- I create an abstract class called CharacterActions. Which handles pretty much all the logic once the conditions are met. Things such as being in range/angles/cooldowns.
- Even things like Idle and Death states have their own script.
All of these classes share HandleState, OnEnter, OnExit.
The Idle.class which derives from CharacterActions is always defaulted to when there’s nothing available. A flying enemy can act differently than a ranged and a boss etc…
The problem here is the serialization and keeping track of everything can be tricky but it’s nice not to have to write the same code for Idle states for each enemy logics.
Now the references are the class itself, they represent the base and the cooldowns and other local things are stored in a struct inside of a monobehavior. The base is never modified since other objects might use it too.
I understand that inheritence isnt something you should use and to be honest I’m only using it to save time coding.
The problems:
- It works fine in situations where only one state can be active at a time. It gets really messy when you want to actions to be peformed at once or inherit velocities from another.
- Having to add variables to accommodate for modifiers add more code where it’s not really needed. Can be interrupted, can inherit velocity, some need to reference other actions. For example, one action spawns a bunch of swords and another ability pulls the swords later on. In this case, having a class for each overall logic might be a better approach…
I’ve tried making flexible AI systems but more often than not it ends up with alot of bloat so I’m looking for some tips on how to deal with this.