Most survival games use hardcoded enemy patterns. Survival Arena's eight AI personality archetypes use a weighted state machine to create genuinely emergent behaviors—each personality hunts differently, reacts unpredictably, and creates tactical depth through elegant system design rather than scripting.
Eight AI Personalities That Hunt Differently
Rather than scripted behaviors, each enemy archetype is defined by weighted personality traits that feed into a unified decision-making system. The same state machine, eight different hunters:
🔥 Berserker
Relentless aggression. Chase bias 70%, aggression boost +40%. Enters rage mode at low HP and never retreats—designed to overwhelm through sheer momentum.
🛡️ Guardian
Defensive and tactical. Flee bias 30%, power-up hunter (35% priority). Retreats intelligently and hunts power-ups when health drops—the thinking player's nightmare.
🗡️ Assassin
Precision striker. Targets the weakest enemy first, then switches to burst speed (1.3x) when within 2x attack range. Hit-and-run lethality.
🏕️ Camper
Edge-dwelling opportunist. Passive first 20 seconds, hugs arena boundaries, then unleashes aggressive flanking attacks. Patience paid off.
🎯 Hunter
Lock-and-load specialist. Target locks for 12 frames with 40% chance to lock the player. +20% accuracy boost. Once fixed, rarely misses.
🃏 Trickster
Chaos incarnate. Erratic zigzag movement (±1.2 radian rotation at 5Hz), random dodge angles. Unpredictable and slippery.
🐺 Predator
Pack tactics. Circle-strafe using sinusoidal orbital movement. Hunts isolated enemies. Creates encirclement patterns through pure geometry.
🦅 Scavenger
Opportunistic hoarder. 50% power-up priority bias. Only engages in combat when powered up. Passive but extremely dangerous when buffed.
Core System Architecture
The magic isn't in complex AI—it's in a unified weighted state machine. Four core mechanics drive all eight personalities:
⚙️ Weighted State Machine
Four states (Chase, Flee, Powerup, Wander) compete based on personality weights and current HP. State decisions update every 0.4-0.6 seconds plus 0.3s random jitter. Same engine, different weights = different hunters.
🎯 Polymorphic Target Selection
Each personality selects targets differently: nearest enemy, weakest player, locked target, isolated prey, or random. Assassins hunt weak; Predators hunt isolated; Hunters lock and track.
🏃 Chase Variants by Personality
Standard: Direct pursuit with mild prediction. Predator: Circle-strafe with sinusoidal orbit. Trickster: Erratic juke at 5Hz. Assassin: 1.3x burst speed within range. Camper: Edge-hugging retreat.
📈 Aggression Ramping
Aggression scales 0→1 over 12 seconds (20 seconds for Camper). Guarantees initial patience, eventual ferocity. Movement speed and attack frequency tie to aggression value.
Technical Deep Dive: Weighted State Machine
The Decision Loop
Rather than behavior trees or pathfinding, Survival Arena uses a single, unified weighted state machine. Every 0.4-0.6 seconds (plus 0.3s jitter), each enemy recalculates state weights and acts:
// Simplified AI Decision Loop (every 0.4-0.6s + 0.3s random)
function updateEnemyState(enemy) {
// Calculate state weights based on personality + HP
let chaseWeight = personality.chaseWeight * (1 + aggression);
let fleeWeight = personality.fleeWeight * (1 - hp/maxHp);
let powerupWeight = personality.puWeight * (1 - hp/maxHp);
let wanderWeight = 1.0; // baseline
// Select state with highest weight
let nextState = argmax([chaseWeight, fleeWeight, powerupWeight, wanderWeight]);
// Execute state action
switch(nextState) {
case CHASE:
let target = selectTarget(enemy.personality);
chaseTarget(enemy, target);
break;
case FLEE:
fleeTowardSafety(enemy);
break;
case POWERUP:
moveTowardClosestPowerup(enemy);
break;
case WANDER:
randomWalk(enemy);
break;
}
// Every update: try ability (2% chance when chasing)
if (state === CHASE && Math.random() < 0.02) {
useAbility(enemy, randomizedCooldown());
}
// Ramp aggression over 12s (20s for Camper)
aggression = Math.min(1.0, time / aggressionRampTime);
}
State Weights and Personality Modulation
The personality archetype is baked directly into state weights. Here's how the eight personalities emerge from the same state machine:
Berserker Personality:
chaseWeight: 3.0, fleeWeight: 0.1, puWeight: 0.0, wanderWeight: 0.5 — Always chases, never retreats.
Guardian Personality:
chaseWeight: 1.0, fleeWeight: 2.0, puWeight: 1.5, wanderWeight: 1.0 — Balances aggression with retreat and power-up hunting.
Assassin Personality:
chaseWeight: 2.5, fleeWeight: 1.5, puWeight: 0.5, wanderWeight: 0.8 + target selection: weakest enemy first.
The key insight: Instead of separate decision trees per archetype, one unified state machine with different weight configurations creates eight distinct hunting behaviors. No branching logic, no duplication—just weighted competition between four states.
Target Selection Variants
When in CHASE state, each personality selects targets differently:
- Nearest: Default. Find closest enemy (Berserker, Guardian).
- Weakest: Minimum HP. Burst damage specialist (Assassin).
- Locked: 12-frame lock with 40% chance to lock player (Hunter).
- Isolated: Circle-strafe target in low-density areas (Predator).
- Random: Pure chaos (Trickster).
Chase Movement Variants
Movement is direct vector-based (no A* pathfinding, no grid systems). Direction varies by personality:
function chaseTarget(enemy, target) {
let direction = normalize(target.pos - enemy.pos);
// Apply personality-specific movement
switch(enemy.personality) {
case STANDARD:
// Direct pursuit with mild prediction
let predictedPos = target.pos + (target.vx * prediction * 0.5);
direction = normalize(predictedPos - enemy.pos);
break;
case PREDATOR:
// Sinusoidal circle-strafe (perpendicular orbit)
let angle = Math.atan2(direction.y, direction.x);
angle += Math.sin(time * 2) * 0.4; // orbital modulation
direction = {x: Math.cos(angle), y: Math.sin(angle)};
break;
case TRICKSTER:
// Erratic juke: rotate ±1.2 radians at 5Hz
let randomAngle = (Math.random() - 0.5) * 1.2;
direction = rotateVector(direction, randomAngle + Math.sin(time * 5) * 0.3);
break;
case ASSASSIN:
// Burst speed within 2x attack range
let distance = length(target.pos - enemy.pos);
let burstSpeed = (distance < attackRange * 2) ? 1.3 : 1.0;
enemy.speed = baseSpeed * burstSpeed;
break;
case CAMPER:
// Flee toward arena edges
direction = normalize(getArenaEdge() - enemy.pos);
break;
}
// Move: direct vector movement (dx/len * speed)
enemy.pos += direction * enemy.speed;
}
Aggression Ramping Timeline
Aggression value ramps from 0 → 1.0 linearly over time. This affects movement speed, ability frequency, and state weight bias:
- Berserker, Guardian, Assassin, Predator, Trickster, Hunter, Scavenger: 12-second ramp
- Camper: 20-second ramp (deliberately patient)
Formula: aggression = min(1.0, elapsedTime / rampDuration)
Movement System: No Pathfinding
Enemies don't use A* pathfinding, grid-based movement, or influence maps. Movement is pure vector math:
// All movement is direct vector calculation
function updatePosition(enemy) {
let dx = targetDirection.x * enemy.speed;
let dy = targetDirection.y * enemy.speed;
// Normalize and apply speed
let length = Math.sqrt(dx * dx + dy * dy);
if (length > 0) {
enemy.pos.x += (dx / length) * enemy.speed;
enemy.pos.y += (dy / length) * enemy.speed;
}
}
This simplicity enables smooth, responsive movement and eliminates the computational overhead of pathfinding. The emergent tactical behavior comes from personality-modulated chase variants, not from grid-based spatial reasoning.
Bot Abilities and Cooldowns
When in CHASE state, enemies have a 2% chance per frame to activate an ability. Cooldowns are randomized per activation, creating unpredictable ability timing:
if (inChaseState && Math.random() < 0.02) {
// Select random ability
let ability = randomChoice([Shockwave, Teleport, Heal, ShadowClone]);
// Randomize cooldown between 3-8 seconds
ability.cooldown = 3 + Math.random() * 5;
executeAbility(enemy, ability);
}
Boss Hunt: ONI BOSS
When a Boss Hunt event triggers, the first spawned enemy becomes the ONI BOSS with 500 HP and 20 damage. But critically: same personality AI applies. The boss isn't a special case with unique logic—it's just a high-HP, high-damage instance of whatever personality archetype it inherited. This means a Berserker boss is a relentless, unkillable juggernaut, while a Trickster boss is chaos at scale.
No behavior trees. No hierarchical decision branching. No A* pathfinding. No grid-based shortest paths or tactical overlays. No influence maps. No spatial scoring grids. No swarm coordination. Bots are independent; no formation flying or team tactics. No machine learning. mlStore logs behavior but never trains. No adaptive difficulty. Waves don't learn your patterns—they're scaled only by level.
Eight weighted configurations applied to one unified state machine create eight distinct personalities. Each personality hunts differently—Berserkers rush, Guardians retreat, Assassins pick weak targets, Predators circle, Tricksters juke, Campers lurk, Hunters lock, Scavengers camp power-ups. The variation feels intelligent because the weights are distributed across meaningful behavioral axes (aggression, retreat bias, target preference, movement style). Emergent complexity from elegant constraints.
Full Game Feature Set
The weighted state machine is embedded in a complete survival arena game:
Game Mechanics
- Drag-to-move in a shrinking arena
- Auto-attack: Nearest enemy takes damage automatically
- Double-tap dodge: 0.12-second i-frame window for invincibility
- 4 Abilities: Shockwave, Teleport, Heal Burst, Shadow Clone with combo system
- Rage Mode: Triggered at 100 surge for power surge gameplay
Campaign & Events
- 100-Level Campaign: Boss encounters at levels 25, 50, 75, and 100
- 4 Event Modes: Giant (oversized enemies), Dash Fury (speed runs), Shrink Rush (accelerated arena shrink), Boss Hunt (survive the ONI)
- Online Multiplayer: Powered by Convex backend for real-time play
Eight Personalities, One Elegant System
Survival Arena's weighted state machine proves that sophisticated AI doesn't require complex systems—just elegant architecture. Eight personalities emerge from four states and personality weights. No trees, no pathfinding, no learning. Just pure game design.
Back to ExaFabs