← Back to ExaFabs

Survival Arena: Enemy AI That Hunts Intelligently

9 min read AI / Combat 2026

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:

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:

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.

What This System Is NOT

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.

Why This Works

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

Campaign & Events

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