I've been busy updating the architecture of Glace to solve an issue I started to run in to. Basically, behaviors in the game had to know way too much about other behaviors in order to work. Whenever I added new features - or changed one, I'd have to go back and update way too much stuff. Classic.
Take the air dash component for example. It explains how the air dash behavior works, but it also defines when the behavior can be performed. Before it would execute, it would have to ask a bunch of other components if it was ok to do so. Am I climbing a ladder? Am I in the middle of an attack? Am I bouncing off a wall?
This means air dash needs to know about climbing ladders and attacking and yadda. And it gets real gross, real fast.
I took a step back and decided on a new way to move forward. That's mostly why I haven't had much new stuff to show lately. I've been "in the weeds" as they say. The Unity weeds.
So real quick - here's info on the solution I'm going with. The problem is I had the behavior and the conditions for that behavior all roled up into one booger. These should be two different boogers. Air dash should do air dash things and someone else should decide on whether to air dash at all.
One solution is the good old finite state machine. The nodes are your behaviors (air dash), and the transitions are your deciders on whether to do something.
No bueno for me as I needed multiple nodes active at once + I wanted to treat nodes as state in addition to behaviors.
I ended up with something I'm calling a model graph in my app. It's a graph of nodes, similar to a finite state machine, but allows multiple states active at once. Instead of transitions between two explicit nodes, nodes have independent conditions to decide whether to run. If a node doesn't have any conditions it just always runs.
There are two types of nodes. Activity Node and Value Node.
ActivityNodes are for any kind of behavior you need. You attach behaviors to them in the form of Activities. Activities have methods like OnStart, OnUpdate, OnStop. E.g. When a node's conditions pass, it starts, and all of its activities get a call to OnStart. When the conditions cease to pass, it calls stop, etc.
ValueNodes associate an arbitrary value (like whether the jump button is down) and allow other nodes to have conditions on it.
Dependencies between nodes are used to do a topology sort so they execute in the proper order. The graph ends up being directed and acyclic (a DAG).
So this let's me create a node called AirDashNode, give it an activity called AirDash (which replaces the need for an AirDashMonoBehavior), and then add conditions to the AirDashNode to decide when to run. The AirDash activity doesn't know anything about the conditions.
After you build the graph you just have to call update on it once per frame.
I plan to open source this later. I'll be talking about it more.