Posted On: 2021-03-15
In a previous post, I wrote about how I reuse sprite animations to simplify creating/updating characters who share the same animation verbs. Unfortunately, reusing animations alone hasn't accelerated the process of making new characters quite as much as I'd hoped. In today's post, I'll unpack some of my remaining obstacles - starting with the one I most want to solve.
My biggest frustration in my new character process is that I don't have a baseline/empty character available as a template. Instead, I generally take one of my existing characters, duplicate it, and then go through and reassign all the attributes that are unique to that character*. The workflow for doing this is unpleasant and error-prone, and it often makes me nervous that, by copying from one existing character rather than another, I may have accidentally committed to some subtle implementation difference that I am not yet aware of. Yet, despite wanting to resolve this more than any other character-workflow related problem, I still haven't done so - and, until today, I hadn't properly understood why.
Although characters share core verbs, such as moving and jumping, I don't have any particular way of sharing the underlying ability to do so. Movement, for example, involves adding a (third-party) component and then manually configuring and tweaking the settings - being extra-careful of any that are intended to remain consistent between characters. This is a pretty far cry from what I would like: ideally, adding the movement ability should be a matter of simply flagging that said character can move. It should be configured correctly right out of the gate, and any character-specific variation should be derived from the data underlying the character itself*.
Achieving this, however, is a significant endeavor, and I've had difficulty being able to justify doing so. Yes, adding new abilities is inconvenient and error-prone, but several of them are built on top of third-party components - meaning that foundational changes to how they are called would require a hefty rewriting. Yet, as I analyze why my new character workflow is broken, I can see how large a role this plays. The burdensome process of adding new abilities pushes me into an easier path: copying an existing character*. Unfortunately, even if I were willing to tackle the issue with abilities head-on, some abilities affect the character's AI, which comes with its own set of challenges.
Although the tools I use to author AI simplify creating personalized, pre-scripted performances for individual characters, they really aren't designed to support creating shared, dynamic behavior. Thus, it's (relatively) easy to make an elaborate boss-fight sequence, but I don't have a way to create a shared "move to point" logic (which is a fundamental building block to many more complex behaviors.) Further still, every behavior must be hand-crafted, from scratch, which often puts me in the awkward position where I have to decide whether or not to spend time implementing AI that's required for an ability/effect that I am not currently sure will apply to the character*.
Looking at things from the perspective of reusing abilities, however, it's clear that this is something I cannot ignore. At present, I've been "sharing" AI simply by copying it between characters - in a grievous violation of the DRY principle. Generally, however, abilities rely on more nuanced, complex interpretations of said "shared" AI, meaning that every character has its own unique set of AI scripts. Thus, in order to make it easy to share abilities, I must find some way to standardize my AI - including both resolving the lack of proper sharing and establishing conventions/methodologies that allow abilities to pick the correct personalized version of the relevant AI (ideally falling back to a reasonable default.)
Laying out these issues has made the dependencies between them much clearer. Where I'd previously assumed that creating a shared template was just a matter of putting in the work, now I can see that it's tightly interwoven with how I approach sharing abilities and AI. Solving one necessitates having a plan to solve the others. Most important of all, however, I can now more appropriately estimate what it costs to improve my workflow: which, hopefully, will enable me to make better decisions about whether or not it's worth it.
I hope this post has been interesting, and helped you appreciate how spending time unpacking dependencies can reveal when one problem actually dangles at the end of a chain of other, bigger issues. As always, if you have any thoughts or feedback about any of this, please let me know.