3D Free Grounder
Categories:
GS_PhysicsRayGrounderComponent is the standard grounder for walking characters. Each physics tick it casts a ray downward from the unit’s capsule base, evaluates the slope, applies gravity when airborne, and updates the MoverContext with ground normal and grounding state.
Grounding mode name: "Free"
For usage guides and setup examples, see The Basics: GS_Unit.

Contents
- How It Works
- Ground Check
- Grounding Move
- Grounding State Changes
- Editor-Exposed Settings
- Extension Guide
- See Also
How It Works
Each post-physics tick, the grounder runs two operations in order:
GroundCheck()— determines contact, slope, and normalGroundingMove()— applies gravity or snap force based on contact result
Ground Check
GroundCheck() casts a sphere (matching the capsule base radius) downward from the unit’s feet:
- If the ray hits geometry within
groundCheckDistance:- Computes slope angle from the hit normal vs. world up.
- Updates
MoverContextRequestBus::SetGroundNormal(hitNormal). - If slope angle ≤
maxWalkAngle(from the MoverContext): reports Grounded. - If slope angle >
maxWalkAngle: reports Sliding. - Resets coyote timer.
- If no hit:
- Increments
coyoteTimer. - If
coyoteTimer < coyoteTime: still reports Grounded (coyote grace period). - If
coyoteTimer ≥ coyoteTime: reports Falling.
- Increments
Grounding Move
GroundingMove() applies vertical forces based on the current state:
Grounded: Applies a downward TimedSpringDamper to keep the unit snapped to the surface without bouncing.
Falling: Applies manual gravity — adds gravityScale * AZ::Physics::DefaultGravity to the rigid body’s linear velocity each frame:
AZ::Vector3 velocity = rigidBody->GetLinearVelocity();
velocity.SetZ(velocity.GetZ() + gravity * delta);
rigidBody->SetLinearVelocity(velocity);
Sliding: Does not override vertical velocity — the Free Mover’s AccelerationSpringDamper handles the slide direction entirely.
Grounding State Changes
GroundingStateChange(newState) is called whenever the ground state changes:
| State | Value | Trigger | Action |
|---|---|---|---|
| Falling | 0 | Lost ground contact beyond coyote time | SetContextState("grounding", 0) |
| Grounded | 1 | Ray hit within walkable angle | SetContextState("grounding", 1) |
| Sliding | 2 | Ray hit but slope > maxWalkAngle | SetContextState("grounding", 2), ChangeMovementMode("Slide") |
When returning to Grounded from Sliding, the grounder calls ChangeMovementMode("Free") to restore locomotion.
Editor-Exposed Settings
| Field | Default | Description |
|---|---|---|
groundCheckDistance | 0.15 | Raycast distance below the capsule base to detect ground. |
capsuleRadius | 0.3 | Radius of the sphere used for the downward cast (should match capsule). |
coyoteTime | 0.12 | Seconds of grace period before reporting Falling after losing ground contact. |
gravityScale | 1.0 | Multiplier on AZ::Physics::DefaultGravity applied when airborne. |
snapHalflife | 0.05 | Spring halflife for the ground-snap TimedSpringDamper. Smaller = tighter snap. |
Extension Guide
Extend GS_PhysicsRayGrounderComponent to add custom ground detection or state reactions.
#pragma once
#include <Source/Unit/Grounder/GS_PhysicsRayGrounderComponent.h>
namespace MyProject
{
class MyGrounder : public GS_Unit::GS_PhysicsRayGrounderComponent
{
public:
AZ_COMPONENT_DECL(MyGrounder);
static void Reflect(AZ::ReflectContext* context);
protected:
void GroundingStateChange(AZ::u32 newState) override;
};
}
void MyGrounder::GroundingStateChange(AZ::u32 newState)
{
// Call base to handle mode switching
GS_PhysicsRayGrounderComponent::GroundingStateChange(newState);
if (newState == 0)
{
// Unit became airborne — trigger jump animation, etc.
}
}
See Also
- Grounders — Grounder base class and class hierarchy
- Slide Mover — Activated when this grounder reports Sliding state
- Mover Context — Receives ground normal and state from this grounder
- Springs Utility —
TimedSpringDamperused for ground snap
Get GS_Unit
GS_Unit — Explore this gem on the product page and add it to your project.