DEV Community

Cover image for Behind the Scenes: Building "Ghost in the Grid" - A 2D Emergent Hide-and-Seek Simulation
Harish Kotra (he/him)
Harish Kotra (he/him)

Posted on

Behind the Scenes: Building "Ghost in the Grid" - A 2D Emergent Hide-and-Seek Simulation

In this technical deep dive, we'll explore the architecture and implementation of Ghost in the Grid, a 2D simulation where autonomous agents compete in a high-stakes game of hide-and-seek. We'll cover the physics, the AI decision-making, and the robust vision system that makes the game feel fair and challenging.

The Architecture: A Modular Approach

The core of the simulation is built on a modular, object-oriented architecture. We chose Matter.js for the physics engine and React for the UI and rendering.

1. The Simulation Engine (Engine.ts)

The Engine class is the heart of the project. It orchestrates the physics world, manages game phases, and handles the rendering loop.

  • Preparation Phase: The Hider has a limited time to move tools (boxes, planks, ramps) and create a hiding spot.
  • Search Phase: The Seeker is released and begins its systematic search.
  • Over Phase: Triggered when the Hider is spotted or time runs out.

2. Autonomous Agents (Agent.ts)

Both the Hider and Seeker inherit from a base Agent class. This class handles:

  • Path Following: A simple list of points the agent tries to reach.
  • Force-Based Movement: Instead of setting positions directly, we apply forces to the physics bodies, leading to more natural, momentum-based movement.
  • Rotation Smoothing: Agents rotate towards their movement direction, but we interpolate the angle to prevent jittery visuals.
// Agent.ts - Force-based movement
const desiredSpeed = Math.min(dist * 0.1, maxSpeed);
const currentSpeed = Matter.Vector.magnitude(this.body.velocity);
const forceMag = (desiredSpeed - currentSpeed) * 0.05;

const dir = Matter.Vector.normalise(diff);
if (!isNaN(dir.x) && !isNaN(dir.y)) {
  const force = Matter.Vector.mult(dir, Math.max(0, forceMag));
  Matter.Body.applyForce(this.body, this.body.position, force);
}
Enter fullscreen mode Exit fullscreen mode

The Vision System: Beyond Simple Raycasting

One of the most challenging parts was making the Seeker's vision feel "fair." A simple raycast from center to center often led to the Seeker winning through tiny gaps or seeing the Hider from across the map.

Multi-Point Detection

To fix this, we implemented a multi-point detection system. The Seeker must see at least two points on the Hider's body (e.g., center and one edge) to confirm a sighting.

Spotting Timer & Reaction Time

We also added a 500ms spotting delay. The Seeker must maintain line-of-sight for this duration to win. This simulates a "reaction time" and gives the Hider a split second to duck back into cover.

// Engine.ts - Spotting logic
if (canSeeNow) {
  this.spottingTimer += dt;
  if (this.spottingTimer >= this.MAX_SPOTTING_TIME) {
    this.isSpotted = true;
    this.phase = GamePhase.OVER;
  }
} else {
  this.spottingTimer = Math.max(0, this.spottingTimer - dt * 0.5); // Fade spotting slowly
}
Enter fullscreen mode Exit fullscreen mode

AI Decision Making

The Hider's Strategy

The Hider isn't just running away. During the preparation phase, it identifies "strategic points" (gaps in the environment) and uses tools to "plug" them. It prioritizes creating an enclosed space in a corner.

The Seeker's Strategy

The Seeker uses a systematic search pattern, visiting corners and central points. However, it also has a Suspicion System. If it "senses" the Hider nearby or investigates a tool, it will circle around it to peek behind obstacles.

Challenges & Stability

Building a physics-based simulation in a browser comes with its own set of challenges:

  • Physics Explosions: Large forces or NaN values can fling bodies to infinity. We added defensive checks and delta-time capping to ensure stability.
  • Rendering vs. Physics: Ensuring the visual "vision cone" perfectly matches the mathematical raycasting was crucial for player trust.

Ghost in the Grid demonstrates how simple rules—raycasting, force-based movement, and basic state machines—can lead to complex, emergent behaviors. Whether you're interested in game AI, physics simulations, or just want to see a robot hide in a corner, this project offers a solid foundation for further exploration.

Example Output 1

Example Output 2

Example Output 3

Example Output 4

Check out the code on GitHub and start building your own autonomous agents!

Top comments (0)