Guidance / Manual
State System
7.1 AudioState Overview
Location: Events/AudioState.cs
Purpose: Change multiple audio parameters based on game mode.
Properties
string StateName { get; } // Unique identifier
string StateGroup { get; } // Mutually exclusive group
IReadOnlyList<BusVolumeProperty> BusVolumes { get; } // Bus volume changes
IReadOnlyList<SwitchProperty> SwitchValues { get; } // Switch changes
IReadOnlyList<RTPCProperty> RtpcValues { get; } // RTPC changes
IReadOnlyList<EffectProperty> EffectProperties { get; } // Mixer effect changes
7.2 State Groups
Concept: States in the same group are mutually exclusive.
Example:
State Group: "Location"
├── State: "Normal"
├── State: "Underwater"
└── State: "Cave"
State Group: "GameplayState"
├── State: "Menu"
├── State: "Playing"
└── State: "Paused"
Behavior:
- Only one state per group is active at a time
- Setting “Underwater” makes it the group’s active state in place of “Normal” or “Cave”
- Different groups can have active states simultaneously
- Setting a state applies its own values only. Nothing from the previous state is undone, so give each state in a group a value for every bus, switch and RTPC its siblings change (“Normal” sets the SFX bus back to 0 dB, for example). The exception is a state whose Bus Volume Mode is Offset (below): its bus offsets go back when it ends.
- State names are unique across all groups
- Setting the state that is already active does nothing
AudioManager.ClearState(group, transitionTime)leaves a group’s state without setting another: an Offset state’s offsets go back; nothing else is undone
Bus Volume Mode: Set Level or Offset
| Bus Volume Mode | The dB values mean | Leaving the state |
|---|---|---|
| Set Level (default, as before 3.1) | Each bus’s level: written into its Volume, the same value the bus inspector and SetBusVolume set (so in the editor it stays in the asset after Play) |
Nothing is put back |
| Offset | How far each bus moves, in a slot of its own on top of its Volume and the player’s volume (§6.8). The asset is never changed. | The offsets go back, over the next state’s (or ClearState’s) transition time |
Use Offset for mix states, so they never undo a Settings page:
State Group "Mode":
Mix_Single (Offset, no bus volumes)
Mix_LocalSplit (Offset: Hero -3 dB, Speed -3 dB)
AudioManager.Instance.SetState("Mix_LocalSplit", 0.5f); // Hero moves -3 dB over 0.5 s
AudioManager.Instance.SetState("Mix_Single", 0.5f); // and back
- Offset states in different groups add up on a bus (Split −3 dB and Nitro +2 dB: −1 dB); leaving one takes only its part away.
- The offset moves in a straight line in dB over the transition time, on unscaled time, in Pepper’s per-frame step. A bus shows it as
StateOffsetDb(and in its inspector in Play mode). - A state’s switches, RTPCs and effect properties work the same in both modes.
7.3 State Properties
BusVolumeProperty
[Serializable]
public class BusVolumeProperty
{
public AudioBus bus;
public float volumeDb;
}
Example:
State: "Underwater"
BusVolumes:
- SFX Bus: -9 dB (muffle sounds)
- Music Bus: -12 dB (distant music)
- Dialogue Bus: -6 dB (slightly muffled)
SwitchProperty
[Serializable]
public class SwitchProperty
{
public string switchGroup;
public string switchValue;
}
Example:
State: "Underwater"
SwitchValues:
- switchGroup: "Location", switchValue: "Underwater"
- switchGroup: "Reverb", switchValue: "LargeHall"
RTPCProperty
[Serializable]
public class RTPCProperty
{
public string parameterName;
public float value;
}
Example:
State: "Combat"
RtpcValues:
- "MusicIntensity": 1.0
- "HeartbeatIntensity": 0.8
EffectProperty
[Serializable]
public class EffectProperty
{
public AudioBus bus;
public string propertyName;
public float value;
}
Example:
State: "Underwater"
EffectProperties:
- Bus: Master, Property: "ReverbMix", Value: 0.8
- Bus: SFX, Property: "LowpassCutoff", Value: 1000.0
7.4 State Transitions
Transition Time: Controls how smoothly parameters change.
public void SetState(string stateName, float transitionTime = 0.5f)
{
if (!states.TryGetValue(stateName, out var nextState)) return; // logs a warning
if (activeStatesByGroup.TryGetValue(nextState.StateGroup, out var current) && current == nextState)
return; // already active
activeStatesByGroup[nextState.StateGroup] = nextState;
nextState.Apply(transitionTime);
}
Apply Implementation (simplified):
public void Apply(float transitionTime)
{
var manager = AudioManager.Instance;
// Bus volumes (Set Level): transition over transitionTime, or set at once when it is 0.
// (An Offset state's bus volumes are moved by SetState and ClearState, which know the group.)
foreach (var busVol in BusVolumes)
{
if (transitionTime > 0f) manager.TransitionBusVolume(busVol.bus, busVol.volumeDb, transitionTime);
else busVol.bus.SetVolume(busVol.volumeDb);
}
// Switches: always immediate (switches don't transition)
foreach (var sw in SwitchValues)
manager.SetSwitch(sw.switchGroup, sw.switchValue);
// RTPCs: transition over transitionTime too, or set at once when it is 0
foreach (var rtpc in RtpcValues)
{
if (transitionTime > 0f) manager.TransitionRTPC(rtpc.parameterName, rtpc.value, transitionTime);
else manager.SetRTPC(rtpc.parameterName, rtpc.value);
}
// Mixer effect properties: transition over transitionTime
foreach (var effect in EffectProperties)
manager.SetBusEffectProperty(effect.bus, effect.propertyName, effect.value, transitionTime);
}
Two quick state changes and RTPCs: a newer RTPC transition on the same parameter replaces the one running (
TransitionRTPC, §3.4), so changing state again before the first transition ends moves the value from where it is to the new state’s value. Bus volume transitions replace each other the same way.Effect properties are found by name: the mixer must expose a parameter called
<BusName>_<Property>, for exampleSFX_LowpassCutoff.
7.5 Common State Patterns
Underwater State:
StateGroup: "Location"
StateName: "Underwater"
BusVolumes:
- SFX: -9dB
- Music: -12dB
- Ambience: -6dB
SwitchValues:
- "Location": "Underwater"
RtpcValues:
- "Underwater": 1.0
TransitionTime: 1.5s
Pause State:
StateGroup: "GameplayState"
StateName: "Paused"
BusVolumes:
- SFX: -20dB
- Music: -12dB
- UI: 0dB (unchanged)
TransitionTime: 0.3s
Combat State:
StateGroup: "CombatState"
StateName: "InCombat"
RtpcValues:
- "MusicIntensity": 1.0
- "HeartbeatIntensity": 0.7
TransitionTime: 2.0s From the Pepper.SFX 3.1 guides (USER_GUIDE.md). Something wrong or unclear? Tell me.