Novolis Docs
novolis-physics / examples/ballistics.md

Ballistics example

dotnetphysicssimulationnovolis

Convention: +Y up, range along +X, set Z = 0 for a planar cannon.

Facade (simplest)

ProjectileBallisticSimulation applies uniform −Y gravity and optional quadratic drag:

using System.Numerics;
using Novolis.Physics.Ballistics;

var sim = new ProjectileBallisticSimulation(
    new ProjectileProfile(massKg: 10, referenceAreaM2: 0.01, dragCoefficient: 0.47));

var env = new ProjectileBallisticEnvironment(
    GravityMetersPerSecondSquared: 9.81,
    AirDensityKgPerM3: 1.225);

var state = new ProjectileState(
    new Vector3(0, 0, 0),
    new Vector3(100, 45, 0),
    massKg: 10);

for (var i = 0; i < 600; i++)
    state = sim.Step(state, dtSeconds: 1.0 / 60.0, env);

Pipeline (extensible)

Compose gravity and drag as separate IForceModel instances when you need custom forces or shared integrators:

using System.Numerics;
using Novolis.Physics.Abstractions;
using Novolis.Physics.Ballistics;
using Novolis.Physics.Motion;

var profile = new ProjectileProfile(10, 0.01, 0.47);
var ballisticEnv = new ProjectileBallisticEnvironment(9.81, 1.225);
var env = new Env(ballisticEnv, new ProjectileDragEnvironment(ballisticEnv.AirDensityKgPerM3));

var pipeline = new SimulationPipeline<ProjectileState, Env>(
    new ProjectileSemiImplicitIntegrator(),
    new UniformGravity(),
    new ProjectileQuadraticDragModel(profile));

var state = new ProjectileState(new Vector3(0, 0, 0), new Vector3(100, 45, 0), profile.MassKg);
for (var i = 0; i < 600; i++)
    state = pipeline.Step(state, env, 1.0 / 60.0, state.TimeSeconds);

readonly record struct Env(ProjectileBallisticEnvironment Ballistic, ProjectileDragEnvironment Drag);

sealed class UniformGravity : IForceModel<ProjectileState, Env>
{
    public ForceSample Evaluate(ProjectileState body, Env env, double timeSeconds) =>
        new(new Vector3(0, -body.MassKg * env.Ballistic.GravityMetersPerSecondSquared, 0), Vector3.Zero);
}

For default gravity + drag only, prefer the facade. Parity with the pipeline is covered by ProjectileDragPipelineParityTests in the unit project.

Sweeps against terrain

Use BallisticsQueries.SweepProjectileSphere (wrapper over IStaticWorld.SweepSphere) for line-of-sight and impact prediction. See INTEGRATION.md §3 for sweep limitations.