Guide

Game projectile systems explained

Harbor Outpost's twin-stick horde mode peaked at 420 simulated bullets per second across four players. Each shot spawned a new GameObject, ran a discrete overlap check every frame, and despawned on hit — frame time spiked to 28 ms on mid-tier laptops and players reported “ghost hits” in co-op. The fix was not tuning damage; it was rebuilding the projectile layer: pooled entities, swept sphere casts along velocity segments, server-side rewind for lag compensation, and a hard cap on active projectiles per owner. P99 frame time fell to 16 ms and disputed hit reports dropped 73%. Weapon feel (recoil, spread, time-to-kill) lives in weapon systems; this guide covers the engine underneath — hitscan versus simulated ballistics, integration and gravity, collision detection, piercing and homing behaviors, object pooling, multiplayer authority, the Harbor Outpost refactor, a technique decision table, pitfalls, and a production checklist alongside our shooter design guide and multiplayer netcode guide.

Hitscan versus simulated projectiles

A hitscan weapon resolves hits the instant the trigger is pulled: cast a ray from muzzle to max range, apply damage to the first valid target. It is deterministic, cheap, and common in competitive FPS where sub-frame accuracy matters. Players perceive hitscan as “instant” even though the server still validates line-of-sight and anti-cheat rules.

A simulated projectile spawns a moving entity with position, velocity, and lifetime. Each tick advances the transform and tests collision along the motion segment. Simulated shots enable travel time, arcing lobs, readable tracers, and mechanics like leading moving targets — at the cost of CPU for integration and collision, plus netcode complexity when clients predict locally.

Hybrid designs are common: rifles hitscan, grenades simulated; or hitscan with cosmetic tracers that do not affect damage. Pick based on genre readability and performance budget, not realism alone. Twin-stick and bullet-hell games almost always simulate because shot density is the gameplay.

When each model fits

Model Best for Tradeoff
Hitscan ray Tactical FPS, snipers, fast TTK duels No lead time; needs lag rewind on server
Kinematic bullet Twin-stick, shmups, ARPG skills Many entities; pooling mandatory
Physics rigidbody Grenades, debris, chaos sandboxes Non-deterministic; hard in multiplayer
Beam / continuous Lasers, flamethrowers, healing streams Per-frame overlap along segment

Trajectory integration

Most action games use kinematic integration: you own position and velocity; physics engine does not apply forces unless you opt in. Per-frame update for a straight bullet:

position += velocity * delta_time;
lifetime -= delta_time;
if (lifetime <= 0) recycle(projectile);

Gravity adds velocity.y -= g * dt for arcing shots. Tune g per weapon class so lobs feel readable at game scale, not Earth-accurate. Drag (velocity *= 1 - k*dt) softens long-range shots in RPGs without switching to full ballistics tables.

Use fixed timestep for simulation (e.g. 60 Hz) even when render framerate varies. Variable dt on fast bullets causes tunneling through thin colliders. Sub-stepping (multiple integration steps per frame) is cheaper than shrinking colliders below art bounds.

Homing and curved paths

Homing missiles steer toward a target each frame: velocity = rotate_toward(velocity, dir_to_target, turn_rate * dt). Cap turn rate so players can dodge; expose lock-on delay so counterplay exists. Sine-wave or helical offsets (function of time) add visual interest without full navigation meshes. Document whether homing retargets on death or sticks to the original lock — players notice silent retargets instantly.

Collision detection that does not miss

Testing overlap only at the projectile's point position each frame misses hits when speed × dt exceeds target thickness — the classic tunneling bug. Fix with sweep tests: cast from last position to new position along the motion segment.

hit = sphere_cast(
  from = prev_position,
  to   = position,
  radius = projectile_radius,
  mask = hostile_layers
);
if (hit) apply_damage(hit); recycle(projectile);

Match projectile_radius to VFX so players trust what they see. Layer masks separate friendly fire rules, environment-only shots, and pierce-through shields. For 2D games, segment-vs-AABB or swept circles against tilemaps follow the same pattern; see tilemap collision for grid alignment pitfalls.

Piercing, bouncing, and area effects

  • Pierce — maintain a hit_ids set per projectile; decrement pierce count on new victims; do not recycle until count hits zero or lifetime ends.
  • Bounce — reflect velocity on surface normal; cap bounces; reduce speed per bounce to prevent infinite hallway ping-pong.
  • Explosion on impact — overlap sphere at impact point; separate damage falloff from direct hit; use one authoritative explosion on server in multiplayer.

Pooling, budgets, and performance

Spawning and destroying thousands of projectiles per minute triggers allocator pressure and GC stalls in managed engines. Pre-allocate a pool per projectile type; on fire, pull from pool, reset state, enable render; on recycle, disable and return. Harbor Outpost uses pools of 128 for standard bolts and 32 for rare charged shots.

Enforce per-owner caps (e.g. max 40 live bullets per player) so one autofire bug cannot melt the server. Sort draw calls by material/atlas when shot counts reach hundreds; batch VFX particles separately from hit logic. Profile with worst-case horde scenarios, not empty test ranges.

Multiplayer authority and lag compensation

In authoritative-server shooters, the client may render predictive tracers immediately, but damage applies only after server confirmation. Three patterns:

  1. Server-spawned only — client sends “fire at time T, aim vector V”; server spawns and simulates. Highest fairness; higher latency feel.
  2. Client projectile + server validate — client shows shot; server reruns hitscan or short rewind to confirm. Common in co-op PvE with forgiving windows.
  3. Lag compensation rewind — on server hitscan/projectile check, rewind other players to positions at shooter's command time, then restore. Essential for PvP feel; document in netcode guides.

Replicate minimal state: spawn event, seed, weapon id, origin, direction — not every frame's position for every bullet. For dense bullet hell, consider deterministic patterns driven by seed so clients simulate identically after one RPC. Never trust client-reported hit lists without server geometry checks.

Harbor Outpost twin-stick refactor (worked example)

Problem. Four-player horde mode: 420 peak bullets/sec, Instantiate per shot, discrete OverlapCircle per bullet per frame, no per-player cap. P99 frame time 28 ms; 19% of co-op sessions logged hit disputes when latency exceeded 80 ms.

Change. (1) Pools of 128 standard / 32 charged projectiles. (2) Fixed 60 Hz sim with swept circle casts. (3) Server rewind 100 ms on damage validation for client-fired shots. (4) Cap 36 live bullets per player; oldest recycled on overflow. (5) Piercing bolts carry HashSet<uint> hit_ids, max pierce 3.

Results. P99 frame time 16 ms on same hardware profile. GC alloc per second from projectiles fell from 8.2 MB to 0.1 MB. Hit dispute tickets down 73%. Weapon DPS tables unchanged — only simulation and net validation moved.

Projectile technique decision table

Game context Recommended approach Why
Competitive PvP FPS Hitscan + server rewind Fair, low entity count
Twin-stick / bullet hell Kinematic + sweep + pools Density requires zero alloc
Co-op ARPG skills Simulated + server validate Readable arcs; forgiving latency
Physics comedy sandbox Rigidbody grenades, capped count Chaos local or host-only
Mobile shooter Hitscan or low-cap kinematic Thermal and battery limits

Common pitfalls

  • Tunneling at high speed — point tests without sweeps; fix with segment casts or sub-steps.
  • Instantiate per bullet — GC spikes in horde modes; pool and recycle.
  • Mismatched VFX and hitbox — players distrust unfair hits; radius should match tracer width.
  • Client-only damage — trivial to cheat; server must validate geometry.
  • Unbounded pierce loops — one shot damaging the same target every frame; use per-projectile hit sets.
  • Variable dt on simulation — different paths at 30 vs 144 FPS; fixed timestep for gameplay sim.
  • Replicating every bullet transform — bandwidth explosion; replicate fire events or seeds instead.

Production checklist

  • Choose hitscan vs kinematic per weapon class; document in data tables.
  • Use sweep collision along motion segments; fixed sim timestep.
  • Pool projectiles; set per-owner and global active caps.
  • Match collision radius to visible tracer/VFX.
  • Implement pierce/bounce with hit-id deduplication and bounce limits.
  • Server-authoritative damage with rewind or validate for multiplayer.
  • Profile worst-case bullet count scenarios on min-spec hardware.
  • Log disputed hits separately from weapon balance metrics.
  • Pair with aim assist and weapon spread from weapon systems, not here.
  • Expose debug draw for sweeps during playtest builds.

Key takeaways

  • Projectile systems simulate motion and collision; weapon systems tune feel and DPS.
  • Sweep tests along velocity segments prevent tunneling at high speed.
  • Pooling and per-player caps are mandatory when shot counts reach hundreds per second.
  • Multiplayer requires server validation; rewind or deterministic seeds reduce disputes.
  • Harbor Outpost cut P99 frame time from 28 ms to 16 ms by pooling sweeps and capping live bullets.

Related reading