This is a clone of the popular browser game Agar.io, made for a class. Here's the GitHub repository for the project. The code sucks. I know. I made it in a week and had never done anything like it before. I learned a lot, but I don't want to look at it again. Definitely my first vibe coded project, haha. I guess these days coding has sort of been trivialized. This is the readme and what it looks like. Maybe one of these days can figure out how to embed the actual game in an iframe or something, but for now, enjoy the documentation and the screenshots.
Overview
There is a popular internet game called Agar.io (www.agar.io), which is a battle royale-esque survival game. You are a circular cell in an arena with other cells. In this arena, there are "food" particles that you eat to get bigger, allowing you to grow in size and eventually consume other players. The last player standing wins the game.
This project is a C++ implementation of that game built on top of the Enviro physics and event-driven framework. It features dynamic physical scaling, autonomous AI enemies, and a complete game-state loop.
Goals
This simulation has three big components behind it:
- Autonomous Navigation: Path finding towards resources.
- Evasive Maneuvers: Logic to detect and flee from larger predators.
- Dynamic Scaling: Using Enviro to update physical properties in real time.
Key Challenges
There are some challenges to implementing some of the logic in this game. Building a dynamic game inside a strict event-driven architecture presented several deep C++ and memory management challenges:
1. Heap Corruption on Boot (fastbins & Segmentation fault)
The Challenge: Attempting to pre-populate the arena with 20 pieces of food inside the spawner's init() or start() functions caused random catastrophic server crashes. This occurred because dynamically instantiating agents (add_agent) forces the underlying std::vector to resize and reallocate memory while the Enviro server is still iterating through that same list to boot the game.
The Solution: Implemented Staggered Spawning and an Event Queue. The spawner waits until the update() loop (after the server is fully stable) and spawns agents frame-by-frame, ensuring smooth memory allocation without iterator invalidation.
2. The "Double Free" and Global Listener Trap
The Challenge: When an agent is eaten, calling remove_agent(id()) destroys the physical body. However, the Enviro Event Manager retains the watch listeners registered in init(). If an event fired a millisecond later, the server attempted to execute a listener on a deleted agent's memory, resulting in a std::bad_function_call or double-free segfault.
The Solution: Implemented the Tombstone Pattern (Object Ghosting). Agents are never actually deleted from memory. Instead, when an agent dies, it teleports entirely off-screen to (10000, 10000) and toggles an is_dead boolean flag. This flag immediately short-circuits all future event listeners and update() loops, safely retiring the object without pulling memory out from under the global server.
3. Event-Driven Spatial Awareness
The Challenge: In Enviro, Process controllers cannot directly access the global server state to find other agents, making traditional "distance to nearest food" loops impossible.
The Solution: Embraced the publish-subscribe architecture. Food and cells continuously broadcast their coordinates via emit(Event("cell_pos", {...})). AI controllers passively listen to these broadcasts, updating their local target vectors without ever directly querying the physics engine.
Installation
Clone the repository:
git clone <it's on my page>cd 520-Assignments/final-project/docker run -p80:80 -p8765:8765 -v $PWD:/source -it klavins/enviro:v1.61 bash- Make sure that (in docker environment) you are in
source/final_projectbefore proceeding.
How To Run
In terminal:
esm startmake cleanmakeenviro
Navigate to http://localhost and play!
Behavior
This primitive version of Agar.io starts with four cells, with you controlling the blue cell. You use the WASD or arrow keys to control the cell in an omnidirectional manner. You go around the map eating food particles to increase in size. You can eat players smaller than you and equal in your size. You die to players bigger than yourself. The number on your cell is your score or how many particles you've eaten. First to 50 wins, or if the player loses, game over.
You can play immediately again after you're done by pressing enter.
Sources
Google Gemini 3.1 Pro: Utilized for advanced C++ debugging, memory management strategies (identifying segfaults, double-frees, and the Tombstone pattern), and Enviro/Elma architectural logic.