Physics

Altruist includes a built-in 3D physics engine (BEPU-based) for collision detection, rigid body simulation, and character controllers. However, physics is entirely optional — many game types don't need real-time collision detection and perform better without it.

When to Use Physics

Game TypePhysics?Why
FPS / action gamesYesReal-time collision, projectile tracing, character controllers
Racing / vehicle gamesYesRigid body dynamics, surface collision
Top-down RPG with grid movementNoDistance-based combat, grid walkability checks
MMO with large open worldsPartialPhysics for players (character controller), lightweight spawns for NPCs/monsters
Turn-based strategyNoNo real-time movement or collision needed

Note:

Disabling physics for entities that don't need it is a major performance optimization. A game with 10,000 entities using lightweight spawns will tick significantly faster than one with 10,000 physics bodies.

Physics-Based vs Heuristic-Based Games

Physics-Based

Entities have rigid bodies, colliders, and participate in the physics simulation. The engine resolves collisions, applies forces, and syncs transforms every tick.

// Spawn with full physics — body + colliders created
var profile = new HumanoidCapsuleBodyProfile(0.28f, 0.62f, 0f, isKinematic: true);
entity.BodyDescriptor = profile.CreateBody(entity.Transform);
entity.ColliderDescriptors = profile.CreateColliders(entity.Transform);
await world.SpawnDynamicObject(entity);

Use this when you need:

  • Real-time collision detection and response
  • Character controllers with gravity, slopes, and sweep collision
  • Projectile hit detection
  • Trigger volumes (enter/exit zones via physics)

Heuristic-Based (No Physics)

Entities are tracked spatially for visibility and queries, but have no physics body. Combat uses distance calculations, movement uses walkability grids, and collision is resolved through game logic rather than physics simulation.

// Lightweight spawn — spatial tracking only, no physics body
world.SpawnLightweight(entity);

Use this when you need:

  • Distance-based combat (attack range checks instead of collider overlap)
  • Grid-based or tile-based movement
  • Thousands of NPCs/monsters that only need position tracking
  • Server-validated movement using walkability maps

Note:

SpawnLightweight adds the entity to world partitions for spatial queries and visibility tracking — it works with FindAllObjects, GetNearbyObjectsInRoom, and the visibility tracker. The only difference is: no physics body, no colliders, no collision events.

Mixing Both Approaches

A common pattern is using physics for players and lightweight spawns for NPCs:

// Player — full physics with character controller
var profile = new HumanoidCapsuleBodyProfile(0.28f, 0.62f, 0f, isKinematic: true);
player.BodyDescriptor = profile.CreateBody(player.Transform);
player.ColliderDescriptors = profile.CreateColliders(player.Transform);
await world.SpawnDynamicObject(player);

// Monster — lightweight, uses distance checks for combat
world.SpawnLightweight(monster);

// Static world geometry — loaded from JSON with colliders
// Players collide with walls/terrain, monsters don't (they use walkability grid)

Note:

Lightweight entities have no physics colliders, but [CollisionHandler] still works for them — the combat system uses distance-based dispatch when physics is off. See Collision Handling.

Loading diagram...

Spawn Methods Reference

MethodPhysics BodyCollidersVisibilitySpatial QueriesUse Case
SpawnDynamicObjectYes (dynamic)YesYesYesPlayers, vehicles, projectiles
SpawnStaticObjectYes (static)YesYesYesWalls, terrain, buildings
SpawnLightweightNoNoYesYesNPCs, monsters, collectibles

Distance-Based Combat Example

For games that don't use physics collision, validate combat with distance checks:

[Gate("attack")]
public async Task OnAttack(AttackPacket packet, string clientId)
{
    var attacker = GetPlayerEntity(clientId);
    var target = world.FindObject(packet.TargetInstanceId);

    if (target == null) return;

    // Distance check instead of physics collision
    float dx = target.Transform.Position.X - attacker.Transform.Position.X;
    float dy = target.Transform.Position.Y - attacker.Transform.Position.Y;
    float distSq = dx * dx + dy * dy;

    float attackRange = 200f; // Game units
    if (distSq > attackRange * attackRange)
        return; // Too far

    // Apply damage
    if (target is MonsterEntity monster)
    {
        monster.Hp -= CalculateDamage(attacker);
        if (monster.Hp <= 0)
            monster.Expired = true;
    }
}

Note:

This approach is used by many classic MMOs — combat is validated by server-side distance checks rather than physics overlap. It scales to thousands of entities because there's no per-frame collision detection overhead.

Physics-Independent Features

Both the character controller and collision system work without physics enabled:

FeaturePhysics ONPhysics OFF
Character ControllerBEPU capsule castsHeightmap + collider math
Collision HandlersBEPU body overlapDistance-based dispatcher
Your codeIdenticalIdentical

The framework auto-selects the right backend based on altruist:game:physics:enabled. You never need to change your game code.

What's Under Physics

  • Movement & Character Controller — Kinematic character controller, gravity, capsule sweep, abilities (works with and without physics)
  • Collision Handling[CollisionHandler] and [CollisionEvent] with Enter/Stay/Exit/Hit lifecycle (works with and without physics)