A real-time Snake arcade game written in modern-ish C++ and rendered with OpenGL 1.x / GLUT (FreeGLUT). The engine is a single-binary, zero-asset game featuring a persistent menu system, three difficulty tiers with escalating frame rates and obstacle density, super-food spawns, procedural obstacle generation (5 shapes), screen-edge wrap-around, and on-disk high-score + recent-score persistence — all drawn from primitive 2D primitives (squares, circles, rounded rectangles, lines, text) with a hand-rolled 2.5D shadow pass.
| Area | Detail |
|---|---|
| Rendering | 1024×800 window, 16 px grid cells, double-buffered GLUT, 16 px shadow offset for a subtle 2.5D look |
| Snake model | 3-plane body array snakeBody[3][maxLength][1] → [active][x][y], head = index 0; body follows head with one-step lag; wraps around all four edges |
| Food system | 5 food slots with per-slot respawn timers (15·FPS frames); super-food appears on an independent 60·FPS-frame timer and is worth ×4 points (20 vs 5). Spawn validation rejects cells occupied by other foods (row / column / diagonal sweeps) and the snake's own body |
| Obstacles | Up to 3 procedural obstacles (one per difficulty tier) in 5 shapes: vertical line, horizontal line, U, L, and ∠. Each has a 30·FPS-frame lifetime, is validated against food, the snake body, and sibling obstacles (AABB corner/containment tests), then rasterized into a per-cell kill map |
| Difficulty tiers | Easy 5 FPS · 1 obstacle · Hard 15 FPS · 2 obstacles · Insane 30 FPS · 3 obstacles |
| Menu | 6-entry menu (Start / Resume / Change Level / High Scores / Game History / Exit) with arrow-key cursor, decorative crawling menu snake, and a resume-confirmation dialog that prevents clobbering an active game |
| Persistence | highscore.txt (single int, beaten-record message on game-over) and scores.txt (rolling last-3 session scores, shown in Game History) |
| Input | GLUT special-key + keyboard callbacks; direction changes reject 180° reversals; P pauses (returns to menu), Esc exits or navigates back |
game-release.cpp ── Engine: GLUT callbacks, state machine, all game logic
│
├── Display() per-frame renderer: clears the buffer, then branches
│ on gameState to compose the visible scene
├── NonPrintableKeys() arrow keys: steer in play, move menu cursor
├── PrintableKeys() Enter / Esc / P: state transitions
└── Timer() glutTimerFunc tick @ 1000/FPS ms → re-posts Display
util.cpp / util.h ── Drawing toolkit + palette
│
├── DrawSquare / DrawCircle / DrawRoundRect / DrawLine / DrawTriangle / Torus2d
├── DrawString() text blitting
├── GetRandInRange() range-constrained RNG (seeded via InitRandomizer())
└── colors[160][3] named palette indices (RED = 5, WHITE = 149,
custom game colors 140–154 for snake, food, UI)
Makefile / CMakeLists.txt ── Build (Linux X11/FreeImage link, or Windows GLUT)
install-libraries.sh ── One-shot apt installer (Debian/Ubuntu)
highscore.txt / scores.txt ── Runtime persistence (recreated on demand)
glClearthe 1024×800 canvasDrawBackground()— static 16 px checker of olive-green cells (cached after first draw)InitSnake()— first-frame bootstrap of the body array (length 3, center of field)BodySnake()— shift every body segment to its predecessorDirection()— advance the head by 16 px alongdirection(0 = right, 1 = down, 2 = left, 3 = up), wrap at edgesDisplayFood()— tick per-food respawn timers, spawn validated food / super-foodDrawSnake()— head as layered circles (body, head, eyes, pupil), body as shaded squaresObstacles()— respawn timers, shape generation, collision validation, kill-map rasterizationCollision()— head-vs-body, head-vs-obstacle →gameOver; head-vs-food → grow, score, historyDisplayScore()— digit-reversal string builder for the HUDglutSwapBuffers()
stateDiagram-v2
[*] --> menu
state menu {
[*] --> Menu
}
menu --> confirmation : Enter «Start Game» while a game is running
menu --> play : Enter «Start Game» (fresh) · or «Resume Game»
menu --> difficulty : Enter «Change Level»
menu --> highscore : Enter «High Scores»
menu --> history : Enter «Game History»
menu --> [*] : Enter «Exit» · or Esc
confirmation --> play : Enter (abort previous game)
confirmation --> menu : Esc
difficulty --> difficulty : Enter (apply Easy 5fps/1 · Hard 15fps/2 · Insane 30fps/3)
difficulty --> menu : Esc
highscore --> menu : Enter / Esc
history --> menu : Enter / Esc
play --> menu : P or Esc (pause)
play --> gameOver : head hits own body or obstacle
gameOver --> menu : Enter / Esc
| Key | In play |
In menus |
|---|---|---|
| ↑ / ↓ / ← / → | Steer snake (180° reversal ignored) | Move cursor (wrap-around) |
| Enter | — | Select highlighted item / confirm dialog |
| Esc | Pause → menu | Back · Exit from main menu |
| P | Pause → menu | — |
| Event | Points |
|---|---|
| Regular food | +5 |
| Super-food (gold, independent 60·FPS timer) | +20 |
Every eaten food grows the snake by one segment and pushes the session score into scores.txt (last 3 games, oldest evicted). A higher session score than highscore.txt updates the record and the game-over panel announces You beat the previous high score.
- C++11 compiler (
g++or MSYS2/MinGWg++) - GLUT — FreeGLUT (or the system GLUT)
- OpenGL / GLU dev headers
- X11 dev headers (Linux) · FreeImage (optional, linked by the Makefile)
Debian/Ubuntu one-shot:
./install-libraries.sh
# or manually:
sudo apt-get install freeglut3-dev libglew-dev libgl1-mesa-dev libfreeimage-devMSYS2 (Windows)
pacman -S mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-freeglut mingw-w64-ucrt-x86_64-glewmake # builds ./game-release (CXXFLAGS: -g3 -Wall -fmessage-length=0)
make clean # removes objects and the binaryThe Makefile links GLUT, GLU, GL, X11, and FreeImage from standard system / SUSE-X (/sw/lib) paths.
cmake -S . -B build
cmake --build build
./build/game-release # highscore.txt / scores.txt are copied beside the binaryg++ -g3 -Wall -fmessage-length=0 -std=c++11 \
game-release.cpp util.cpp \
-o game-release \
-lGLU -lGL -lglut -lX11 -lfreeimage./game-release # opens the "Snake game" GLUT windowRequires an X server / desktop session (on Windows, run under WSLg or MSYS2).
├── game-release.cpp # engine: state machine, game loop, input, rendering
├── util.cpp / util.h # drawing primitives, palette, RNG helpers
├── Makefile # native make build (Linux/X11 toolchain)
├── CMakeLists.txt # CMake build (cross-platform)
├── install-libraries.sh # apt dependency installer
├── highscore.txt # persisted record score
├── scores.txt # last three session scores
└── .github/
├── copilot-instructions.md
└── repo-metadata.json
- The game writes
highscore.txt/scores.txtin the current working directory — run from the repo root. - No automated test suite; validate changes by building, playing a session, and toggling through the menu states.
- The window is fixed at 1024×800; the playfield is 64×48 cells with a 2-cell HUD strip along the bottom.