Behaviour and the Resolving Assets
Modular Footstep is heavy on the asset-based workflow. These assets connects together via asset reference (GUID), there is absolutely no string
or enum
labels, no magic numbers or index, etc.
Each type of asset here is a subclass of ScriptableObject
, a class which can instantiate an asset file to exist in the project, serializing values.
FootstepBehaviour
This type of asset is the final destination, representing how the sound would behave.
If an eleplant repeatedly steps on wet grass, the "audio would behave" in one FootstepBehaviour
way. If using the same floor but change the stepper to human wearing sandals, we get one different FootstepBehavior
. If we lock it to a human still, but change sandals to boots, again, a different FootstepBehaviour
.
Each FootstepBehaviour
has a "program" inside to account for variations or sequence of sound that it can produce. You can ask any FootstepBehaviour
to sound in interval, or one-shot (once or repeatedly).
You may think of an API to look like this :
footstepSource.Play(footstepBehaviour);
Similar to the familliar audioSource.Play(audioClip)
. But this approach has one big problem : Footstep often have shared "traits" or "hierarchy" between them.
By using only FootstepBehaviour
, we are forced to linearize all those connections. And the workload of choosing the right FootstepBehaviour
from a mountain of assets falls into the programmer.
Imagine this collection of FootstepBehaviour
all represent different occassions, even though only parts of them are different :
Walk-Grass-Greaves.asset
Run-Grass-Greaves.asset
TipToe-Grass-Greaves.asset
Walk-Grass-Boots.asset
Run-Grass-Boots.asset
...(100+ more?)...
This character wearing other footwear, this character on an another kind of surface such as soil or stone floor, or a new kind of action, all add combinations to the whole thing.
I play Overwatch often, and it is amazing that you can identify which character is approaching you by listening to the footsteps, which are intentionally unique and volume boosted more than your ally. Each character has an equally identifiable walk, jump, and landing sound on many kind of surfaces in the game. This game has 32 characters. Imagine how many FootstepBehaviour
would these exploded into. There are even more AudioClip
that are needed, because one FootstepBehaviour
would need to randomly pick from several clips for variety. Props to the sound engineer that managed to design gorilla step sound onto all required surfaces and actions...
Footstep package need to step in and provide hierarchical feature to combat this management nightmare!
The 4 resolving assets
Modular Footstep uses 4 asset types to represent different combinations that would resolve into a single FootstepBehaviour
. They are named :
-
Surface
: Intended to represent different surfaces. -
SurfaceModifer
: Intended to represent different conditions of the surface. -
Stepper
: Intended to represent footwears, or actor that is stepping (such as what kind of animal). -
StepperModifier
: Intended to represent different actions performed on the surface, wears and tears level of the footwear, or even different kind of switchable footwears if you usedStepper
as something else such as character's name.
I say intended all over, because you can think of these in completely abstract way, as A, B, C, and D without any meaning. (Though, it would help if your interpretation is not too far from these names.)
Providing 4 assets at the same time (null
on one of these is also considered a unique combination) gets you back 1 FootstepBehaviour
.
You can setup a "menu" to program which combination resolves into which FootstepBehaviour
, explained in a bit.
The plugin performs the FootstepBehaviour
resolving step for you, then immediately play the returned FootstepBehaviour
. Therefore an actual API looks more like this (not exactly) :
footstepSource.Play(surface, surfaceModifier, stepper, stepperModifer);
You are not allowed to input FootstepBehaviour
directly into any of the API. Input are always Surface
+ SurfaceModifier
+ Stepper
+ StepperModifier
. It resolves inside the package into FootstepBehaviour
automatically, according to your "menu". In practice, this allows you to switch only some part of the API call dynamically so it resolves into a different FootstepBehaviour
.
Where is this "menu"?
Surface
is the menu!
4 resolving assets are almost equal, only the Surface
has a bit more going on inside.
When you inspect on Surface
asset, the Inspector allows programming the resolver how it takes in 3 remaining asset types : SurfaceModifier
, Stepper
, and StepperModifier
, that would resolves into which FootstepBehaviour
you would like. (More about this in Getting Started/Setup Resolvers in the Surface.)
Look at this prototype API call again :
footstepSource.Play(surface, surfaceModifier, stepper, stepperModifer);
From your perspective, it looks like 4 assets are combined into one FootstepBehaviour
. But actually, the plugin takes 3 latter assets : SurfaceModifier
, Stepper
, StepperModifier
, to resolve with the logic that is stored in the first argument Surface
, producing FootstepBehaviour
.
And this also means Surface
cannot be null
among the 4 assets. Inversely, just Surface
and without SurfaceModifier
, without Stepper
, without StepperModifier
is enough to resolve a FootstepBehaviour
.
Imagine a simple game that step sound does not change no matter which character you use, has only walk sound, and change according to surface. You only need a collection of Surface
and equal amount of FootstepBehaviour
for this game. The resolver is then a simple 1-to-1 mapping from Surface
to FootstepBehaviour
.
Tip
Notice that only Surface
's icon has no little red tag, unlike the others (, , ).
This is a reminder that other assets are mere "tags" and have less data, unlike Surface
which has big settings inside it.
Implied hierarchy ordering
The resolver being inside Surface
implies that it is "the first" among 4 assets that combine into FootstepBehavior
. You can of course look at all 4 assets equally, fusing together into FootstepBehaviour
. But Footstep Behaviour is opinionated that the resolving hierarchy is according to the following :
Surface > SurfaceModifier > Stepper > StepperModifer ---> FootstepBehaviour
This opinion is reflected in the "menu" you can program into the Surface
. Footstep Behaviour give you a tree-like UI that let you program the resolver in this order SurfaceModifier
> Stepper
> StepperModifer
, saving you repetitive work. (And also a more generic, linear SurfaceModifier
+ Stepper
+ StepperModifier
UI without the tree structure.)
You are ready to create these assets!
Go to Getting Started/Installing to get Modular Footstep inside your game, then start creating the resolver inside Surface
in Getting Started/Setup Resolvers in the Surface.