Jumping, double jumping, slash attack, jumping attack, jumping pounce attack, and more... so many abilities and actions that the player can perform in Purrtato Tail. How can we possibly manage all of these individual abilities without a monstrous character controller and spaghetti code? Read on - as today we are talking about how we handle all of this - the Task Master!
In the early days of converting our original Purrtato Tail puzzle game into a platforming JRPG / Metroidvania, we only had two moves - Jump and Attack. It was simple. It worked. But... it was kind of boring. Pixel wanted to do so much more, yet we limited her to these two most basic of actions. And who are we to tell a cat what they can't do? (Go try that with your cat, see how well it works.)
"I sleep here now." - Yuki
After some careful planning and designing, we determined a list of other things we would like Pixel to be able to do - like Pounce, Double Jump, Ground Pound, and much more. Cracking open the code, we initially started to integrate these into the character controller for Pixel... and... it was a mess. We quickly determined that the character controller is the wrong place to manage these kinds of abilities, even though most games do indeed put them there. In fact, the famous game Celeste even shared their Character Controller code, and that is precisely how they did it as well! (You can check that out here).
Taking such a different direction wasn't a rash decision on our part. We had a list of gotchas and hurdles we needed to resolve, including...
If one ability gets modified, it requires touching multiple parts of the character controller.
Adding a new ability can cause race conditions and overlap issues with other abilities and actions.
Trying to control any entry and exit effects - like a pre-attack animation - adds another layer of complexity to the character controller.
The character controller is meant to move the character - abilities should be a different system that communicates with the character controller.
Overall, trying to implement multiple moves into a character controller makes it far too easy for moves to interfere with each other (which you may notice does indeed happen with some games).
This all prompted us to open the Great Purrtato Design Notebook (actually an old Fallout themed notebook) and think about a better way of handling how the player moves and uses abilities. We drove up into the mountains (literally) and used the calm drive to plan through how to accomplish this, and the basis of the Task Master system was designed.
Stuck on design or code? Give nature a try...
The base concept behind the Task Master system is simple - When input occurs, the Task Master system is informed. The system then checks for what Tasks the player has available at that point in time (based on what they have unlocked via the Ancestral Yarn Grid, what State Flags are active, etc.), and compares the Entry input needed for these available tasks. If any matching tasks are found we do some additional checks - such as if another task must be active to move into a task, or if the current task can be interrupted by the desired task - and if we pass all checks, move into the new task.
Here's a very high-level diagram of what this logic flow looks like.
The result of this is every single thing the player can make the character do in the game is a Task, and every Task has entry requirements, and supports both an Entry and an Exit sequence. The power this gave us to integrate new moves is quite intense. For one, we don't need to worry about two abilities interacting with each other, because the system makes this impossible. Secondly, the system automatically detects Task scripts, so no setup of tasks is required. Third, we can have alternate versions of tasks based on conditions - for example, maybe Pixel has a happy idle pose, but if she is somewhere scary, she has a scared idle pose. Each of those would be a different Task, with entry conditions that confirms things as needed.
Another very important feature of this, and moving between tasks, is knowing what the active task is. This means if we want the player to have a Jump Attack, then the task would require a Jump task to already be active before the Jump Attack task could be entered. This allows us to have all kinds of moves that can build on top of other moves!
Task Master is probably one of the single coolest and most powerful things we developed for Purrtato Tail. It introduces a development methodology of creating clean support for player abilities that has worked extremely well for us and we intend to build upon and refine for future games.