FootstepSource
In summary, this component connects to any AudioSource
(which could be attached right on the same Game Object) as an output. Then it receives an order to play into that output from its scripting API, which accepts Surface
+ SurfaceModifier
+ Stepper
+ StepperModifier
, among other arguments, to resolve into FootstepBehaviour
behind the scene and then play it.
How to set it up
Attach
FootstepSource
on any Game Object. This does not determine where the sound is coming from yet, but this component can receive API calls from C# script.Attach regular
AudioSource
on any Game Object, which would be the output ofFootstepSource
in the first step. For easier reasoning, you can attach bothFootstepSource
andAudioSource
right on the same Game Object next to each other. (Like the image above.)On the
FootstepSource
component, connect a reference toAudioSource
you would like to be an output. Drag the Game Object that you attachedAudioSource
in step 2. into the "Audio Source" slot. (Like the image above.)Setup the
AudioSource
as you like, whether you want the footstep to be globally heard or positional, or whichAudioMixerGroup
output you would like to use for footsteps. Consult Unity's documentation if you need some refreshers.Call
public
APIs onFootstepSource
. Which first, you need to get a reference of it into your script. Declare a serializable reference to this component on anyMonoBehaviour
component you need to start playing footsteps :[SerializeField] private FootstepSource myFootstepSource;
Then you can start using its public API! (We will discuss what are available to call in a moment.) However, you will also need some references to the resolving assets that all these API want in order to resolve into
FootstepBehaviour
. You can get them into the script however you want to organize your game. Including something simple like this :[SerializeField] private FootstepSource myFootstepSource; [Space] [SerializeField] private Surface stage1Surface; [SerializeField] private SurfaceModifier someSurfaceModifier; [SerializeField] private Stepper mainCharacterStepper; [SerializeField] private StepperModifier someStepperModifier;
The 2 modes of public APIs
You may have seen throughout the documentation already that Modular Footstep offers 2 play modes. The details and when to use which mode are collected in their own page.
- Interval Play : The footstep plays repeatedly on its own just by calling "start". You are able to call "update" to change how it sounds while playing as well, and finally you can call "stop" to shut it up. This mode has many advantages, including ease of use, optimization, and even features thanks to the fact that the library "knows the future".
- One-Shot Play : Play exactly single step per 1 call. This is a mode for tight and precise integration with animation or surface collision system, that you see other heavier solutions in the Asset Store providing. While flexible, this mode loses several great features in Interval Play as well.
Here is an overview of related APIs for both modes.
// "Interval Play" APIs
StartInterval():void
StartInterval(ResolvingArgs resolvingArgs, TimingArgs timingArgs, StartArgs startArgs, ShotArgs shotArgs):void
UpdateIntervalResolvingArgs(ResolvingArgs resolvingArgs):void
UpdateIntervalShotArgs(ShotArgs shotArgs):void
UpdateIntervalTimingArgs(TimingArgs timingArgs):void
StopInterval(bool sudden):void
IsIntervalPlaying:bool
// "One-Shot Play" APIs
PlayOneShot():void
PlayOneShot(ResolvingArgs resolvingArgs, ShotArgs shotArgs):void
You can see arguments are similar for both modes and they have unique names. They are designed so you can easier make connections in understanding the methods.
In this page, we will talk about these arguments first and not any API you see.
Argument structs
Modular Footstep organizes arguments grouped in several struct
.
- Grouping and naming them make it easier to see which arguments are similar or different across different public APIs. Learn once then apply your knowledge in different methods.
- Method to update currently running footsteps can use the same name as these struct to group updates, instead of having to provide individual API to update each little field.
struct
are stack allocated and free cleanly without causing GC. One-Shot Play methods are likely rapidly called, it is important that each call is lightweight and does not use the heap (class
).
All these struct
has a 1+ arguments constructor prepared and you should always use it. C# struct
are slightly annoying that they are always allowed to exist without passing through a constructor, unlike class
that we can gatekeep user better to use the provided constructors.
This can cause "bad default" should you make mistake and skip using the constructors I provided. (Cannot force compilation error unlike class
.) For example volume field inside the struct starting at 0
is a worse default than 1
. Using the constructor, volume can be set to 1
correctly alongside other important fields. Tables below show what the constructor requests.
ResolvingArgs
This struct
asks for the essential 4 resolving assets that would be used in resolving into FootstepBehaviour
. Expect all APIs to start playing anything in Modular Footstep to need this one.
Additionally, it has a bool
to use an advanced feature Advanced/Secondary Behaviour.
Constructor Argument | Explanation |
---|---|
surface | One of the core assets. Contains the resolvers to take in the other 3 which the library uses to resolve into FootstepBehaviour and play. |
surfaceModifier | One of the core assets. Can be null , which is considered a unique item while resolving. |
stepper | One of the core assets. Can be null , which is considered a unique item while resolving. |
stepperModifier | One of the core assets. Can be null , which is considered a unique item while resolving. |
secondary | true to use the Secondary Behaviour on the resolved FootstepBehaviour instead of the primary one. You must also checked "Secondary Behaviour" on the FootstepBehaviour 's inspector, otherwise it will be forwarded to the primary one anyway. Default to false . |
TimingArgs
Only used in Interval Play. The constructor asks for a single float
to be wait time between each steps. It may sounds overkill to pack a single float
in a struct
, but this is a unique thing to Interval Play and needs a separated struct
grouping.
Additionally, there is one more constructor taking in IReadOnlyList<float>
instead of just a single float
. This is an advanced feature called "irregular interval" which it linearly goes through interval numbers you provided and loop back. Some characters with unusual walk cycle may need this.
StartArgs
Only used in Interval Play. A yet another mini-struct
needed only 1 float
at the moment on its constructor : offset
.
The name of this struct
is such that should in the future there is something that only applies at the moment of starting, they would be added here without being a breaking change.
Offset is unexpectedly important in Interval Play since no one on earth starts walking immediately on down step! It can be used to sync up the "take off" animation of the character which may have unusual length until the character gets into the walk cycle. You can adjust how long to wait until the first step is heard.
Usually, this value is very close to the main interval time. But you could nudge it to be slightly longer or shorter to fot an exact animation blending speed from standing to walking you have.
Even in a game with relatively cartoonish sprite walking animation, in my opinion, it almost always sounds better to have non zero offset. It maybe jarring when the player repeatedly tap move key and release, without offset the player would repeatedly hear the step every time despite the character not moving that much.
ShotArgs
This argument applies on each step. One-Shot Play is already a single step. Interval Play use this argument on every scheduling trigger.
Yet again, this struct
's constructor is currently only accepting a single float
: volume
. Using the constructor ensures that the volume
starts at 1.0
(a good default).
The name of this struct
is such that should in the future there is more per-shot arguments, they would be added here without being a breaking change.
Default Arguments
On the inspector of FootstepSource
, you can also see this dropdown. Inside, it shows the name of all the struct
you learned. The content inside also corresponds to what you learned.
Generally, I recommend you to use API where you provide all the arguments via scripting. But there are some API that has 0 arguments :
// "Interval Play" APIs
StartInterval():void // <---
// StartInterval(ResolvingArgs resolvingArgs, TimingArgs timingArgs, StartArgs startArgs, ShotArgs shotArgs):void
// UpdateIntervalResolvingArgs(ResolvingArgs resolvingArgs):void
// UpdateIntervalShotArgs(ShotArgs shotArgs):void
// UpdateIntervalTimingArgs(TimingArgs timingArgs):void
// StopInterval(bool sudden):void
// IsIntervalPlaying:bool
// "One-Shot Play" APIs
PlayOneShot():void // <---
// PlayOneShot(ResolvingArgs resolvingArgs, ShotArgs shotArgs):void
These API instead use serialized arguments you can edit on Inspector save with the scene. But the nature of footstep programming is not this rigid, it is likely not used often.
Still, I provide these for parity with AudioSource
, which allows pre-assigning AudioClip
and serialize many configurations then call Play()
. Maybe you have some creative use for it, including activating the API using parameterless UnityEvent
.
Explore the APIs of both modes
Having learned about the purpose of each argument, you are ready to take a look at an actual APIs.