Stagger
GTA V / Euphoria style balance loss for R15 characters. Call Stagger.Begin on the server and the character lurches in a direction, stutter-stepping to get their feet back under them while the arms come out and the torso swings with the momentum. Little by little the steps catch up, and the character either recovers and stands normally again, or runs out of balance and ragdolls, staying down for a while (or until you call Stagger.Recover) before standing back up.
It is built on the joints Roblox already gives every character with the Avatar Joint
Upgrade: AnimationConstraint for animation and BallSocketConstraint for the limits. No
joint is ever replaced or added. While staggering the upper body is physically simulated with
a soft AngularStrength (a "muscle"), so it lags behind the procedural pose and reacts to the
movement the way NaturalMotion's characters do, and when the character falls every joint goes
limp and the ball sockets take over.
Networking. The server is the authority: it decides when a stagger starts and ends,
switches the joints (which replicate), and broadcasts state with
Packet. The balance model runs on whoever owns the character's
physics and the outcome is reported back: the player's own client for a player, and for an
NPC the nearest player's client (within Stagger.DriverRange), which is given network
ownership of the body for the duration so the stagger and the ragdoll are simulated at full
rate instead of replicated from the server. With nobody near, the server drives the NPC.
Controllers are managed by a Binder, so every staggering character
carries the Staggering tag for the duration.
Require the module once on the server and once on every client (a shared ModuleScript under
ReplicatedStorage.Packages, which Wally gives you). Requiring it is all the setup there is.
-- Server
local Stagger = require(ReplicatedStorage.Packages.Stagger)
explosion.Touched:Connect(function(hit)
local character = hit.Parent
if character:FindFirstChildOfClass("Humanoid") then
local away = (character:GetPivot().Position - explosion.Position)
Stagger.Begin(character, away, { Preset = "Heavy", Intensity = 1.5 })
end
end)
Stagger.StateChanged:Connect(function(character, state)
if state == Stagger.State.Ragdoll then
print(character.Name, "hit the floor")
end
end)
-- Client: nothing to call, just make sure it is required somewhere.
require(ReplicatedStorage.Packages.Stagger)
Requires StarterPlayer.AvatarJointUpgrade to be on (the default for new experiences).
Characters still rigged with Motor6D are skipped with a warning.
Types
BeginOptions
interface BeginOptions {Preset: string?--
Name of a preset from Stagger.Presets or Stagger.RegisterPreset. Default "Default".
Intensity: number?--
Scales the shove: 1 is the preset as tuned, 0.5 a nudge, 2 a truck. Default 1.
Seed: number?--
Seed for the balance model's randomness (0 to 65535). Random when omitted.
}Properties
State
This item is read only and cannot be modified. Read OnlyStagger.State: {Idle: number,Staggering: number,Ragdoll: number,Recovering: number}
The states a character moves through. Idle (0) is not staggering. Staggering (1) is
stutter-stepping to regain balance. Ragdoll (2) is on the floor, fully simulated.
Recovering (3) is standing back up (or the short settle after recovering on their feet)
before returning to Idle.
StateNames
This item is read only and cannot be modified. Read OnlyStagger.StateNames: {[number]: string}Stagger.StateNames[Stagger.State.Ragdoll] == "Ragdoll".
TAG
This item is read only and cannot be modified. Read OnlyStagger.TAG: string
"Staggering": the CollectionService tag every character carries from Stagger.Begin (or
Stagger.Ragdoll) until it is back to Idle.
ATTRIBUTE
This item is read only and cannot be modified. Read OnlyStagger.ATTRIBUTE: string
"StaggerState": the server writes the numeric state to this attribute on the character so
other systems (and non-scripted things like UI) can read it.
DriverRange
Stagger.DriverRange: number
How close (studs) a player has to be to an NPC to be handed its stagger to drive and
simulate. Keep it well inside your streaming radius, since that player needs the NPC
streamed in. Beyond it the server drives. Default 128.
Presets
This item is read only and cannot be modified. Read Only
The built-in presets (Default, Light, Heavy, Drunk) plus anything you registered.
See Config for every field.
StateChanged
This item is read only and cannot be modified. Read OnlyFires on every peer when a character changes state: (character, newState, oldState).
Fell
This item is read only and cannot be modified. Read OnlyFires on every peer when a character hits the floor (enters Ragdoll).
Recovered
This item is read only and cannot be modified. Read OnlyFires on every peer when a character is done: back to Idle, on their feet.
Binder
This item is read only and cannot be modified. Read Only
The Binder that owns the controllers, for InstanceBound / InstanceUnbound or
GetInstances(). It is manual-only: do not Bind through it yourself.
Functions
Begin
This item only works when running on the server. ServerStagger.Begin(options: BeginOptions?) → boolean--
false if the character is not a supported rig, is dead, or is ragdolled.
Starts a stagger. The character lurches along direction (flattened to the ground) and
begins stutter-stepping. Whether they recover or fall is up to the balance model, tuned by
the preset and Intensity. Calling it on a character that is already staggering hits them
again: a fresh lurch from the new direction. Calling it on a ragdolled character does nothing.
Ragdoll
This item only works when running on the server. ServerStagger.Ragdoll() → boolean--
false if the character is not a supported rig or is dead.
Drops the character straight into the ragdoll, skipping the stagger (or cutting one short).
Uses the preset's RagdollDuration to decide when they get up; 0 means they stay down
until Stagger.Recover.
Recover
This item only works when running on the server. Server
Ends the stagger or ragdoll: the character stands up now (Recovering), then returns to
Idle after the preset's GetUpDuration. Does nothing for an Idle character.
Stop
This item only works when running on the server. Server
Cancels everything immediately: joints restored, controls back, straight to Idle with no
get-up. Use it when something else takes over the character (a cutscene, a seat, a teleport).
RegisterPreset
Registers (or replaces) a preset for Stagger.Begin's Preset option. Register the same
presets on the server and the client, since the client needs the tuning to run the balance
model for its own character. Unknown keys and wrong types raise an error.
Stagger.RegisterPreset("Slippery", Stagger.Presets.Default, { MisstepChance = 0.8, StepMomentumKeep = 0.85 })
GetState
Stagger.GetState(character: Model) → number--
One of Stagger.State; Idle for anything that is not staggering.
IsStaggering
GetController
The live Controller for a character, or nil when it is Idle. On the driving peer its
Balance field is the running Balance model, handy for debugging or for feeding extra
bumps with Balance:Disturb.
GetCharacters
IsSupported
Stagger.IsSupported(character: Instance) → boolean--
Whether the character is an R15 rig on AnimationConstraints.