---
title: "Add 3D rigid body physics in C#"
url: https://recursiveai.org/onegame/cookbook/3d-rigid-body-physics/
description: "Add 3D rigid body physics in C# with onegame: a runnable .NET 10 console example using the published physics package, with real output and a download."
version: "1.26.0"
---

# Add 3D rigid body physics in C#

**onegame** is a free, open-source game engine for .NET from Recursive AI. MIT or Apache-2.0, no editor required.

[NuGet](https://www.nuget.org/packages/RecursiveAI.OneGame.Physics) · [GitHub](https://github.com/recursive-ai-oss/onegame) · [Docs](https://recursiveai.org/onegame/docs/) · [Download example (.zip)](https://recursiveai.org/onegame/cookbook/3d-rigid-body-physics/3d-rigid-body-physics.zip)

This console example drops a sphere onto a static floor and reads its resting pose without opening a window.

```shell
dotnet add package RecursiveAI.OneGame.Physics
```

Requires [.NET 10](https://dotnet.microsoft.com/download/dotnet/10.0) (net10.0); .NET 9 and earlier aren’t supported.

```csharp
using OneGame.Core;
using OneGame.Physics;

var world = new World(1, new EntityRegistry());
var space = PhysicsSpace3D.AddTo(world);
space.AddBox(new FVec3(40, 1, 40),
    new FVec3(0, -1, 0),
    new BodyOptions3D { Kind = BodyKind.Static });
var ball = space.AddSphere(Fixed.One,
    new FVec3(0, 6, 0));
for (var tick = 0; tick < 300; tick++)
    world.Step();
Console.WriteLine($"Pose: {space.Transform(ball).Position}");
Console.WriteLine($"Vertical velocity: {space.Velocity(ball).Y}");
```

Unzip [the example](https://recursiveai.org/onegame/cookbook/3d-rigid-body-physics/3d-rigid-body-physics.zip), then `dotnet run`.

```text
Pose: (0, 0.499931013, 0)
Vertical velocity: 0
```

`Fixed` and `FVec3` are deterministic fixed-point scalar and 3D vector types: use `Fixed.FromInt(2)` or `new FVec3(2, 0, 0)` for integers, and convert a float with `Fixed.FromDouble(value)` outside sim code.

## The full program

The download mirrors the transform into a synced entity property and runs 300 ticks so the sphere can settle on the floor.

`OneGame.Generated.project.EntityTypes` is generated from the assembly name `project` by the package’s entity source generator.

```csharp
using OneGame.Core;
using OneGame.Physics;

var registry = new EntityRegistry();
OneGame.Generated.project.EntityTypes.Register(registry);
var world = new World(1, registry);
var space = PhysicsSpace3D.AddTo(world);
space.AddBox(new FVec3(40, 1, 40),
    new FVec3(0, -1, 0),
    new BodyOptions3D { Kind = BodyKind.Static });
var entity = new FallingBall {
    Body = space.AddSphere(Fixed.One, new FVec3(0, 6, 0))
};
world.Add(entity);
for (var tick = 0; tick < 300; tick++)
    world.Step();
Console.WriteLine($"Mirrored pose: {entity.Pose.Position}");
Console.WriteLine($"Vertical velocity: {space.Velocity(entity.Body).Y}");

[Entity]
public partial class FallingBall : Entity
{
    [Synced] public partial BodyRef Body { get; set; }
    [Synced] public partial Transform3 Pose { get; private set; }
    protected override void OnTick() =>
        Pose = PhysicsSpace3D.Of(World!)!.Transform(Body);
}
```

```text
Mirrored pose: (0, 0.499931013, 0)
Vertical velocity: 0
```

## Variations

**Change the initial height.** Replace `new FVec3(0, 6, 0)` in the program with:

```csharp
new FVec3(0, 10, 0)
```

With that change, the program prints:

```text
Mirrored pose: (0, 0.499931026, 0)
Vertical velocity: 0
```

## Related recipes

[Move a 3D character controller in C#](https://recursiveai.org/onegame/cookbook/3d-character-controller/) · [Drive a 3D vehicle physics controller in C#](https://recursiveai.org/onegame/cookbook/drive-3d-vehicle/) · [Raycast a 3D physics world in C#](https://recursiveai.org/onegame/cookbook/raycast-3d-world/)

---

## The short answer

Add `RecursiveAI.OneGame.Physics`, register `PhysicsSpace3D` on a `World`, add bodies and advance the world with `world.Step()`. Dynamic bodies are the default. The snippet at the top adds a sphere, steps until it rests on a static floor and reads its transform. There is no graphics-device requirement for this console simulation.

`AddTo` installs both the hidden physics table and the post-entity stepping system. Calling `world.Step()` therefore advances physics too. Don’t call `space.Step()` a second time for that same world tick. A standalone `new PhysicsSpace3D()` has no world system; you must step it yourself instead.

## What is rigid body physics?

In this API, a rigid body has a shape, position, rotation and velocity. A dynamic body responds to gravity and contacts. A static body provides unmoving collision geometry, such as a floor. `BodyOptions3D.Kind` selects static, kinematic or dynamic behavior. See the [physics guide](https://recursiveai.org/onegame/docs/physics/#3d-spaces) for the supported 3D setup.

`AddBox` takes the box’s size and position; `AddSphere` takes a radius and position. These are simulation shapes, not rendered meshes. Adding a sphere won’t put a visible sphere on screen. Keep the collision representation and your rendered art aligned, but create them through their respective APIs.

The defaults use meters, Y-up gravity of −9.81 units per second squared, 60 ticks per second and four solver substeps. Those are the defaults in `PhysicsOptions3D`, not settings inferred from your render loop. Use identical simulation settings on every node in a networked game.

## How do I use 3D rigid body physics in a C# game?

Create the space in your game’s `RegisterSystems`, so worlds created to load saves have the physics table too. Add bodies during `Setup`. Store the returned `BodyRef` on the owning entity rather than assuming a body’s position is its identity. `Position`, `Rotation`, `Velocity` and `Transform` read the physics state; `Transform` returns position, rotation and unit scale.

The physics space is the source of truth. Its table is hidden, so clients receiving entity replicas don’t automatically receive that table. Mirror the body’s position and rotation into synced entity properties in `OnTick`, then use those properties in the view. The [published 3D example](https://github.com/recursive-ai-oss/onegame/blob/5759c4257b68bbdb8fc99ac73c4681cf23968da3/examples/physics/3d/Game.cs) follows that pattern for its bodies and character.

Entity ticks run before the physics step. A pose read in `OnTick` therefore describes the previous completed step, not the step about to happen. This ordering matters when comparing a view’s mirrored pose against a fresh read directly from the space.

Physics state is saved, restored and hashed with the world. Keep simulation changes in sim code, not in a draw callback, and let the renderer read the mirrored state. Reading a transform does not move a body, create a mesh or register a view.
