---
title: "2D physics in a C# game"
url: https://recursiveai.org/onegame/cookbook/2d-physics/
description: "Drop a box onto a static floor and apply an impulse with OneGame’s 2D physics package. Includes a runnable C# console project."
version: "1.24.0"
---

# 2D physics in a C# game

**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/2d-physics/2d-physics.zip)

Drop a box under gravity with `RecursiveAI.OneGame.Physics`, stable since 1.24.0 and versioned with the engine.

```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 physics = new PhysicsSpace2D();
var body = physics.AddBox(
    new FVec2(1, 1), new FVec2(0, 4));
physics.Step();
Console.WriteLine(physics.Position(body).Y < 4);
```

Prints:

```text
True
```

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

## The full program

The snippet at the top advances a standalone physics space once and prints whether the box fell. The full program attaches a space to a game world, which steps it once per tick.

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

CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
var world = new World(1, new EntityRegistry());
var physics = PhysicsSpace2D.AddTo(world);
physics.AddBox(new FVec2(20, 1),
    new FVec2(0, -Fixed.FromRatio(1, 2)),
    new BodyOptions { Kind = BodyKind.Static });
var crate = physics.AddBox(new FVec2(1, 1), new FVec2(0, 4));
for (int tick = 0; tick < 120; tick++) world.Step();
Console.WriteLine($"Landed: y={physics.Position(crate).Y.ToSingle():0.00}");
physics.ApplyImpulse(crate, new FVec2(4, 3));
for (int tick = 0; tick < 120; tick++) world.Step();
var position = physics.Position(crate);
Console.WriteLine($"After kick: x={position.X.ToSingle():0.00}, y={position.Y.ToSingle():0.00}");
Console.WriteLine($"Physics steps: {physics.StepCount}");
```

`dotnet run` prints:

```text
Landed: y=0.50
After kick: x=2.49, y=0.50
Physics steps: 240
```

Invalid physics options throw `ArgumentOutOfRangeException`; a physics save with another table format version is refused, and nothing is loaded half-way.

## Variations

### Keep a floor static

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

var physics = new PhysicsSpace2D();
var floor = physics.AddBox(new FVec2(20, 1),
    new FVec2(0, 0),
    new BodyOptions { Kind = BodyKind.Static });
physics.Step();
Console.WriteLine(physics.Position(floor).Y == 0);
```

```text
True
```

## Related recipes

[Record and replay](https://recursiveai.org/onegame/cookbook/record-and-replay/) · [Pathfinding](https://recursiveai.org/onegame/cookbook/pathfinding/)

---

## The short answer

Add `RecursiveAI.OneGame.Physics`, create a `PhysicsSpace2D`, and add bodies with shapes. A standalone space advances with `Step`. A space added with `PhysicsSpace2D.AddTo(world)` advances automatically once per world tick, after the entities. Use one stepping model, not both at once.

The downloadable program uses the world-managed model. It drops a dynamic box onto a static floor, lets it settle, applies an impulse and lets it settle again. It prints the resulting coordinates without requiring a renderer or a window.

## How do I use 2D physics in C#?

Use `FVec2` for positions and sizes and `Fixed` for scalar inputs. `Fixed` is a fixed-point number; `FVec2` contains two of them. Box sizes are full widths and heights, not half-extents. In the full program the floor is twenty units wide and one unit high, with its center half a unit below zero. Its top is therefore at zero.

The crate is one unit tall. Once it rests on that floor, its center is approximately half a unit above zero, which is why the program prints `y=0.50`. The default gravity points along negative Y. A screen coordinate system that points downward needs a conversion in view code; changing the display convention is different from changing gravity.

A world-managed space belongs in the game’s system registration, so a fresh world created to load a save also has the space. Bodies live in the space and entities can keep a synced `BodyRef`. Mirror the positions and angles needed by views into synced entity properties. The physics table is hidden authority state, not a table replicated directly to clients.

## What is the difference between static and dynamic bodies?

A dynamic body responds to gravity and impulses. That is the default for a box when no body options override it. A static body is appropriate for this example’s floor: it provides collision geometry without falling along with the crate. The variation shows that its position remains unchanged after a step.

An impulse is a one-time push. Apply it when the action occurs, as the full program does after the first settling interval. Applying the same impulse every tick would be a repeated series of pushes rather than the single kick illustrated here.

The physics system steps after entity updates. If an entity copies a body’s position during its update, that copy describes the previous physics step. Keep this order in mind when comparing entity properties with the space’s current coordinates or drawing a debug overlay.

## Which 2D physics features does the C# package support?

The package gives a game “2D and 3D rigid bodies, characters, vehicles, triggers and queries that behave the same on every node.” In 2D that means boxes, circles, capsules and polygons, characters with collide-and-slide movement, triggers, ray casts and collision layers. The 2D wrapper does not cover joints, chains and segments, shape casts and overlap queries yet. 3D spaces (`PhysicsSpace3D`) are a separate API. Check the feature you need before choosing this package for an existing game.

Physics is included in world saves, replay and state hashing. It is built on OnePhysics 1.0, whose 1.x promise it passes on: “Within 1.x, patch releases never change a result”, while “a minor release may change results”, and its changelog says so when one does. Physics saves and replays made with the preview packages before 1.24.0 are not promised to carry over; re-record them. An incompatible physics save is refused rather than partly loaded.

Do not mark a physics-reading command as predicted. A replica’s predicted world has no physics space. Treat physics as authority logic and send the view the mirrored information it needs. The [physics guide](https://recursiveai.org/onegame/docs/physics/) explains the snapshot boundary and available operations in detail.

Source: the [pinned library documentation](https://github.com/recursive-ai-oss/onegame/blob/5759c4257b68bbdb8fc99ac73c4681cf23968da3/docs/physics.md).
