Skip to content
suryanarayanrenjith edited this page Jul 26, 2026 · 2 revisions

AI

Home · Enemies · World · Game-Systems

Enemy behavior combines per-enemy perception, squad-style approach lanes, bullet dodging, attack state machines, per-archetype behavior blocks, a swarm-wide tactical director, and adaptive difficulty. Most expensive decisions are throttled or allocation-conscious so combat remains viable with many entities.

Behavior states

The decision system exposes patrol, hunt, attack, and investigate as active gameplay states. The type definition also includes idle, retreat, coordinate, and ambush, but the current decision path does not select retreat: damaged enemies keep pressing the player rather than fleeing.

State Trigger Behavior
Patrol No sight, sound, or alert Moves around a small local patrol ring.
Investigate Stored disturbance / last known position Travels to the disturbance, then falls back to patrol.
Hunt Player seen, heard, or sufficiently alerted Uses a stable per-enemy approach lane to form a surround.
Attack Melee enemy sees the player within close range Commits toward a slightly led target and starts the telegraphed attack cycle.

Squad approach and navigation

Each enemy receives a stable flank sign, flank strength, speed trim, and—in the Ranged case—standoff distance. Melee units bend their approach from different sides at long range, then reduce the bend inside about five units to commit directly into melee. This avoids a single-file rush and avoids endless orbiting.

Ranged support enemies hold a 14–21 unit kiting ring in their AI layer, then use their separate bolt rules when they have an appropriate 6–50 unit line of sight.

Steering combines terrain repulsion, tangential wall sliding, personal-space separation, and stuck recovery. Tanks and Bosses get larger personal-space values. Navigation uses map collision props rather than a baked navigation mesh; no NavMesh or A* asset pipeline was found.

Body turn rate is per-archetype. Most enemies square up to the player quickly enough that circling them is not a viable tactic; the Bulwark deliberately turns at roughly a quarter of that rate, which is what makes flanking its frontal shield an achievable answer rather than a race the player always loses.

Perception and aggro

  • Enemy vision uses a cone and terrain line-of-sight test, though live enemy configuration grants 360° vision with a 500-unit nominal range.
  • Hearing responds to movement and gunfire; sound memory lasts five seconds.
  • Night reduces the perception system's default visual range multiplier to 70%, although live high range and engagement culling also apply.
  • Difficulty scales aggro distance, reaction time, and the range in which expensive AI stays active.
  • Trees and collidable props block Sniper and Sentinel line of sight.

Bullet dodging

Bullet dodging scans projectiles within 15 units (20 for Fast enemies), estimates closest approach, and only reacts to threatening trajectories. Dodges have a base two-second cooldown, reaction-time gate, success probability, and a sideways/backward randomized escape direction. Wave number increases dodge skill and shortens the cooldown; Hard reacts faster than Easy.

Attack logic

Melee attacks have wind-up, strike, and recovery animation phases. Damage is allowed once in the strike phase, with range and frontal-arc checks plus an overlap fallback. The system animates arm swings, torso rotation, and a short forward lunge so attacks are telegraphed rather than passive contact damage.

Snipers and Revenants use their own energy-bolt logic; Snipers do not enter the melee attack path. Revenants combine gold-bolt attacks with a close-range melee option.

Per-archetype behavior

The four tactical archetypes run their own small state machines on top of the shared steering, evaluated once per frame per enemy without per-frame allocation. The behavior tree itself only understands the five base profiles, so each specialist maps onto the closest one for steering purposes — the Bulwark and Splitter steer like Tanks, the Leaper like a Fast flanker, and the Howler like a Ranged support unit — while its distinctive behavior lives in its own block. Full mechanics are in Enemies.

Swarm-wide tactical direction

A solo-only director sits above the individual enemies. It reads the player's dominant strategy from rolling averages of pace, engagement range, and camping behavior, then publishes a single shared directive — flank bias, encircle pressure, rush bias, target-prediction lead, and hold range — that every enemy folds into its own decision. It is O(1) per tick rather than per-enemy planning, and it emits an occasional kill-feed callout so an adaptation is legible rather than merely felt. Multiplayer passes a neutral directive.

Spawning and adaptive systems

The wave spawner distributes each batch around the player at evenly spaced bearings, at a distance scaled by the wave's shape (see Gameplay). Every spawn path passes through the shared concurrent-enemy cap.

Adaptive difficulty records hits, accuracy, kills, health, and survival behavior. In Adaptive mode it periodically updates future enemy health, damage, spawn rate, and a smoothed speed target. It is an implementation-driven dynamic system, not a fixed difficulty preset.

The director, adaptive difficulty, and the other periodic systems run on real elapsed-time accumulators. They were previously gated on a frame counter that is clamped after the third frame, which meant none of them could ever fire; the accumulators are also framerate-independent, so a 120 Hz display no longer runs them at twice the intended cadence.

Performance behavior

Enemy meshes are pooled and reuse geometry/materials. High, medium, low, and culled LODs transition at 45, 70, and 100 units, with shadows disabled beyond 40 units. Enemies are only damageable while their high-detail representation is active; this prevents long-range shots against minimal distant stand-ins. The Howler is the single exception, since it holds position at the back of the pack and would otherwise be unkillable on low presets.

All ten archetypes share one material shape, so adding an archetype costs no additional shader programs. Every type is rendered once during shader warmup, so a species' first spawn mid-wave never stalls on program linking.

Implementation references: src/utils/AIBehaviorSystem.ts, src/utils/EnemyPerception.ts, src/utils/AttackSystem.ts, src/utils/BulletDodging.ts, src/utils/TacticalDirector.ts, src/utils/EnemyArchetypes.ts, src/utils/AdaptiveDifficultySystem.ts, src/utils/SmartEnemyManager.ts.

Clone this wiki locally