Inspiration

Our team has always been aware that ocean pollution is one of the most pressing environmental crises of our time. 8 million tons of plastic enter the ocean every year, and most people never see it. We wanted to bring attention to this issue in an unconventional way: not through a lecture or an infographic, but through an experience.

The idea was simple: what if players could explore a beautiful, immersive 3D ocean, and then stumble upon the ugly reality of trash scattered across the seabed? We designed the waste to disrupt the scene on purpose. When you're navigating a gorgeous underwater world full of coral reefs, shipwrecks, and schools of fish, a plastic bottle on the ocean floor feels wrong. That natural discomfort is the point, it gives players an organic inclination to clean it up. And when they do, they're rewarded not with points, but with knowledge: real facts about ocean pollution and a thank-you from the developers for caring. It's a hidden easter egg, not a forced message.

We wanted to prove that awareness doesn't have to be boring. It can be a multiplayer adventure with your friends. 🤝

What it does

Deep Blue Scavengers is a real-time multiplayer 3D game where players pilot ROV submersibles across a vast procedural ocean floor. You dive in with a callsign, pick a hull color, and explore, collecting treasure chests scattered across the seabed for points while competing on a live leaderboard. 🏆

But the ocean isn't pristine. Scattered among the treasures are pieces of trash: plastic bottles, crushed cans, glass bottles, that disrupt the otherwise beautiful environment. Players who choose to collect this waste discover a hidden layer of the game: after cleaning up 5 pieces, they receive an awareness overlay with real ocean pollution statistics and a personalized thank-you message. There's no HUD counter, no hint. It's a genuine easter egg that rewards curiosity and conscience.

The world is shared. You see other players' submarines in real time, complete with headlamps, lanterns, and boost trails. You can open a tactical map, ping locations for your friends, and coordinate dives together. The ocean itself is alive with boids-driven fish schools, procedural coral reefs, environmental bubbles, and marine snow particles, all rendered in WebGL with a simulation-grade HUD overlay.

How we built it

The server is written in Go(lang), chosen for its goroutine concurrency model. Each connected player spawns two dedicated goroutines (read pump + write pump) for non-blocking WebSocket I/O. A central Hub coordinates broadcasts using a single-threaded event loop with sync.RWMutex-protected client maps. The game engine runs on a fixed tick rate (20 ticks/sec), completely decoupled from WebSocket handlers, so the tick loop never blocks on I/O. ⚡

All communication uses a custom binary WebSocket protocol, no JSON. Every message type (PlayerMove, TreasureSpawn, SchoolUpdate, etc.) is a compact binary frame (typically 18-30 bytes) with little-endian encoding and IEEE 754 floats. This keeps bandwidth minimal at high tick rates.

MongoDB is the backbone of our persistent state and real-time event system 🍃:

  • Spatial Partitioning with $geoWithin and $nearSphere: The world is divided into a 4x4 sector grid. Every entity query (players, treasure, fish schools) is filtered through $geoWithin on GeoJSON Polygon boundaries, so we never scan an entire collection. Proximity checks for treasure collection use $nearSphere with 2dsphere indexes. All coordinates are stored as GeoJSON Points with custom MarshalBSON/UnmarshalBSON to convert between game coordinates and WGS84.

  • Multi-Document ACID Transactions for Scoring: Treasure collection is wrapped in a multi-document transaction with readConcern: snapshot and writeConcern: majority. The atomic sequence: claim treasure (FindOneAndUpdate status to "collected") → increment player score ($inc) → decrement sector count, all in one transaction. This prevents race conditions where two players try to collect the same item. We also built a sequential fallback path for single-node deployments.

  • Change Streams for Event-Driven Spawning: We use zero polling. MongoDB Change Streams watch for treasure inserts and collection events. When new treasure is inserted into the database, the stream fires, the server encodes a TreasureSpawn binary frame, and broadcasts it to the relevant sector via WebSocket. Resume tokens ensure no events are lost on reconnect, with automatic exponential backoff.

  • Time Series Collections for Telemetry: Player movement telemetry is stored in a time series collection (match_events) with granularity: seconds and a 24-hour TTL. High-frequency position samples are batched (InsertMany, unordered) with w:1 write concern. We accept possible loss on failover because telemetry is non-critical, while score events use w:majority.

  • Aggregation Pipelines: Leaderboard rankings use $match → $sort → $limit → $project routed to SecondaryPreferred replicas. Sector heatmaps aggregate match events by sector with $group and time-window $match. A $geoNear aggregation stage computes nearest-treasure with distance fields.

  • JSON Schema Validation: All collections enforce $jsonSchema validators with required fields, type constraints, and enum values (e.g., treasure status must be "available" or "collected"). GeoJSON sub-schemas are reused across collections.

  • Strategic Indexing: Partial filter indexes on treasure (only index status: "available" items), compound indexes on (active, sector_id) for player lookups, a unique case-insensitive username index using ICU collation, and 2dsphere indexes on every location field.

  • Read/Write Concern Tuning: Critical paths (treasure collection, scoring) hit the primary with w:majority. Analytics queries (leaderboard, heatmap, school startup) route to SecondaryPreferred replicas. Telemetry writes use w:1. Connection pooling is tuned: 50 max, 5 min, 30s idle timeout, retry reads/writes enabled.

The frontend uses PlayCanvas (WebGL) with a full post-processing pipeline, procedural terrain via layered FBM noise, instanced coral/rock placement, and a boids fish schooling system that runs entirely client-side (the server only sends school center points to save bandwidth). The HUD is a custom HTML overlay styled as an industrial ROV telemetry display with compass ribbon, depth gauge, pitch ladder, and CRT scanlines. 🎮

Challenges we ran into

Race conditions in treasure collection were the hardest problem. Two players clicking the same treasure at the same tick creates a classic double-spend. We solved it with MongoDB's multi-document ACID transactions, but then hit a second challenge: transactions aren't supported on time series collections, so we had to log the collection event outside the transaction boundary while keeping the claim-and-score atomic. 😅

Binary protocol debugging was painful. When a single byte offset is wrong, you don't get a nice error, you get garbage coordinates and submarines teleporting to the South Pole. We had to write dedicated encode/decode test suites with known byte sequences.

Balancing server authority with client responsiveness. The server validates all movement (speed caps, surface boundary), but the client needs to feel instant. We implemented client-side prediction with server reconciliation: the client moves immediately, the server confirms or corrects, and the client replays unacknowledged inputs.

Change stream reliability. MongoDB change streams can drop on network blips or replica set elections. We implemented resume token persistence and exponential backoff reconnection to guarantee zero event loss.

Accomplishments that we're proud of

  • đŸ—ī¸ 69 distinct MongoDB features in production use, from $geoWithin spatial queries to change streams to time series telemetry to ACID transactions with snapshot isolation. This isn't a CRUD app with MongoDB bolted on; the database is a core architectural component driving real-time game events.

  • 🌍 The hidden environmental message. No one is told to collect trash. There's no counter, no quest marker. Players discover it organically because the waste disrupts the beautiful scene they're exploring. The awareness overlay that appears after collecting 5 pieces has real statistics and a personalized thank-you. It's subtle, and that's why it works.

  • ⚡ Sub-30ms tick latency with 20+ concurrent players, binary WebSocket payloads, and zero-polling event architecture. The server tick loop never touches the network or database directly; all I/O is asynchronous.

  • 🎮 A complete multiplayer experience: real-time position sync, shared treasure state, tactical map with ping system, hull color customization, and a full simulation-grade HUD, built and deployed in a hackathon timeframe.

What we learned

  • 🍃 MongoDB is a legitimate real-time game backend when you use it correctly. Geospatial queries with 2dsphere indexes, change streams instead of polling, time series for telemetry, and ACID transactions for state integrity. These aren't features you expect to use together in a game, but they compose beautifully.

  • đŸ“Ļ Binary protocols matter. Switching from JSON to a custom binary format cut our per-message size by 70-80% and eliminated serialization overhead entirely. At 20 ticks/sec with dozens of players, this is the difference between smooth and unplayable.

  • â™ģī¸ Environmental messaging works best when it's not forced. We debated adding a trash counter to the HUD and decided against it. Making it a hidden discovery made it more impactful. Playtesters who found it talked about it more than any other feature.

  • đŸĻĢ Go's concurrency model is ideal for game servers. Goroutines per client, mutex-protected shared state, channels for coordination, and a decoupled tick loop. It maps perfectly to the real-time multiplayer problem.

What's next for Deep Blue Scavengers

  • 🏆 Persistent leaderboards and seasonal events using MongoDB's aggregation pipelines. Weekly cleanup challenges where collective trash collection unlocks new ocean facts.
  • 🐋 More diverse marine life with animated species (whales, dolphins, mantas already have GLB models loaded) and ecosystem health that visually degrades as trash accumulates in a sector.
  • 🤝 Cooperative missions where players must coordinate to clean large debris fields, using the existing ping system for tactical communication.
  • 📱 Mobile support with touch controls and adaptive quality scaling (already have a 3-tier adaptive quality system that adjusts pixel ratio and shadows based on frame rate).
  • 🌐 Real-world ocean data integration, pulling live pollution data from ocean monitoring APIs to influence in-game trash density by region.
Share this project:

Updates