Table of Contents

Class CharacterMover2D

Namespace
Stride.CommunityToolkit.Box2D
Assembly
Stride.CommunityToolkit.Box2D.dll

A platformer character that is not a rigid body: a capsule the game moves itself, Quake style, with Box2D asked only what it touches. Ported from the Box2D.NET samples' Mover (MIT, (c) 2022 Erin Catto, (c) 2025 Choi Ikpil).

public sealed class CharacterMover2D : IBox2DSimulationUpdate
Inheritance
CharacterMover2D
Implements

Examples

var mover = new CharacterMover2D(new Vector2(2, 8)) { Entity = hero };
simulation.RegisterSimulationUpdate(mover);

// per frame
mover.Throttle = (input.IsKeyDown(Keys.D) ? 1 : 0) - (input.IsKeyDown(Keys.A) ? 1 : 0);
if (input.IsKeyPressed(Keys.Space)) mover.Jump();

Remarks

Each step: ground friction and acceleration towards Throttle times MaxSpeed, gravity, then a pogo - a shape cast straight down whose hit distance drives a spring that floats the capsule at PogoRestLength above the ground and tells it whether it is standing; then up to five rounds of collecting contact planes (b2World_CollideMover), solving a translation that respects them (b2SolvePlanes) and sweeping it (b2World_CastMover); finally the velocity is clipped against those planes so it stops pushing into walls.

Register it with RegisterSimulationUpdate(IBox2DSimulationUpdate) and it steps itself after every fixed physics step, so kinematic platforms and the mover agree on time. Set Throttle and call Jump() from your frame update; give it an Entity and it writes the transform after each step.

The mover collides with shapes whose category bits pass CollideFilter. Shapes carry the sample's categories by default: give the level StaticCategory, moving platforms DynamicCategory, things the mover should kick but walk through DebrisCategory. How hard a shape pushes back is per shape, through SetResponse(B2ShapeId, float, bool).

Constructors

CharacterMover2D(Vector2, float, float)

Creates a mover standing at position.

public CharacterMover2D(Vector2 position, float halfHeight = 0.5, float radius = 0.3)

Parameters

position Vector2

World-space centre of the capsule.

halfHeight float

Half the distance between the capsule's two centres.

radius float

The capsule's radius.

Fields

DebrisCategory

Category bit for loose things the mover passes through and can kick.

public static readonly ulong DebrisCategory

Field Value

ulong

DynamicCategory

Category bit for moving obstacles the mover collides with and stands on: elevators, bridges.

public static readonly ulong DynamicCategory

Field Value

ulong

MoverCategory

Category bit for movers; a mover overlaps others but does not sweep against them, which is what makes the push soft.

public static readonly ulong MoverCategory

Field Value

ulong

StaticCategory

Category bit for the level: chains, floors, walls.

public static readonly ulong StaticCategory

Field Value

ulong

Properties

Accelerate

Acceleration towards the wanted speed, as a multiple of MaxSpeed per second.

public float Accelerate { get; set; }

Property Value

float

AirSteer

Fraction of Accelerate available in the air.

public float AirSteer { get; set; }

Property Value

float

Bottom

World-space lower centre of the capsule.

public Vector2 Bottom { get; }

Property Value

Vector2

CastFilter

What the mover sweeps against. Not other movers, so two movers push each other softly rather than blocking.

public B2QueryFilter CastFilter { get; set; }

Property Value

B2QueryFilter

CollideFilter

What the mover collects contact planes from. Level, moving obstacles and other movers by default.

public B2QueryFilter CollideFilter { get; set; }

Property Value

B2QueryFilter

Entity

The entity whose transform follows the mover, if any.

public Entity? Entity { get; set; }

Property Value

Entity

Friction

Ground friction, in units of 1 per second.

public float Friction { get; set; }

Property Value

float

Gravity

Downward acceleration on the mover. Separate from the world's gravity, since the mover is not a body.

public float Gravity { get; set; }

Property Value

float

GroundPushForce

Force pressed into whatever the mover stands on, newtons, so a bridge sags under it.

public float GroundPushForce { get; set; }

Property Value

float

HalfHeight

Half the distance between the capsule's two centres.

public float HalfHeight { get; }

Property Value

float

IsOnGround

Whether the pogo found ground under the feet in the last step.

public bool IsOnGround { get; }

Property Value

bool

IterationsLastStep

How many plane-solver iterations the last step took in total.

public int IterationsLastStep { get; }

Property Value

int

JumpSpeed

Upward speed given by Jump().

public float JumpSpeed { get; set; }

Property Value

float

MaxSpeed

Top speed on the ground, metres per second.

public float MaxSpeed { get; set; }

Property Value

float

MinSpeed

Below this speed the mover stops dead rather than creeping.

public float MinSpeed { get; set; }

Property Value

float

Planes

The contact planes found in the last step, for drawing.

public ReadOnlySpan<B2CollisionPlane> Planes { get; }

Property Value

ReadOnlySpan<B2CollisionPlane>

PogoDampingRatio

Damping ratio of that spring; under 1 gives a small bounce on landing.

public float PogoDampingRatio { get; set; }

Property Value

float

PogoEnd

Where the pogo cast ended in the last step: the hit point's height, or the full reach when it missed.

public Vector2 PogoEnd { get; }

Property Value

Vector2

PogoFilter

What counts as ground for the pogo.

public B2QueryFilter PogoFilter { get; set; }

Property Value

B2QueryFilter

PogoHertz

Stiffness of the spring that floats the mover above the ground.

public float PogoHertz { get; set; }

Property Value

float

PogoHit

Whether the pogo cast hit anything in the last step.

public bool PogoHit { get; }

Property Value

bool

PogoOrigin

Where the pogo cast started in the last step: the lower capsule centre.

public Vector2 PogoOrigin { get; }

Property Value

Vector2

PogoRestLength

How far above the ground the lower capsule centre rests. Three radii by default.

public float PogoRestLength { get; set; }

Property Value

float

PogoShape

The shape cast down to find the ground.

public PogoShape PogoShape { get; set; }

Property Value

PogoShape

Position

World-space centre of the capsule.

public Vector2 Position { get; }

Property Value

Vector2

Radius

The capsule's radius.

public float Radius { get; }

Property Value

float

StopSpeed

Below this speed ground friction removes a fixed amount per second instead of a fraction, so stopping is crisp.

public float StopSpeed { get; set; }

Property Value

float

Throttle

Walk input, -1 to 1: the fraction of MaxSpeed wanted, negative for left.

public float Throttle { get; set; }

Property Value

float

Top

World-space upper centre of the capsule.

public Vector2 Top { get; }

Property Value

Vector2

Velocity

Current velocity, metres per second.

public Vector2 Velocity { get; }

Property Value

Vector2

Methods

AfterSimulationUpdate(Box2DSimulation, float)

Called after the simulation has advanced.

public void AfterSimulationUpdate(Box2DSimulation simulation, float deltaTime)

Parameters

simulation Box2DSimulation

The simulation that was stepped.

deltaTime float

The time step in seconds.

Jump()

Asks for a jump. Honoured at the next step if the mover is on the ground, then forgotten, so call it on the key press rather than while the key is held.

public void Jump()

SetResponse(B2ShapeId, float, bool)

Sets how shapeId pushes a mover, in the shape's user data.

public static void SetResponse(B2ShapeId shapeId, float maxPush, bool clipVelocity)

Parameters

shapeId B2ShapeId

The shape.

maxPush float

See MaxPush.

clipVelocity bool

See ClipVelocity.

SimulationUpdate(Box2DSimulation, float)

Called before the simulation advances.

public void SimulationUpdate(Box2DSimulation simulation, float deltaTime)

Parameters

simulation Box2DSimulation

The simulation being stepped.

deltaTime float

The time step in seconds.

Step(B2WorldId, float)

Advances the mover by one step of deltaTime seconds in worldId. Called for you when registered with a simulation.

public void Step(B2WorldId worldId, float deltaTime)

Parameters

worldId B2WorldId

The world to collide with.

deltaTime float

Step length in seconds.

Teleport(Vector2)

Moves the mover to position and stops it.

public void Teleport(Vector2 position)

Parameters

position Vector2

New world-space centre.