🎮 Introduction: The Nostalgic Arcade Experience
Remember the thrill of plugging quarters into arcade cabinets, the neon glow, the hum of the machine? That magic is what inspired Mini Games: a modern CLI arcade that brings retro gaming nostalgia to your terminal.
Why CLI? Because it’s the ultimate hacker’s playground—no graphics libraries, just pure programming power. And why C++? Because it’s fast, flexible, and lets you get as low-level as you want.
This project is more than just games—it’s a showcase of what you can do with terminal manipulation, user management, and real-time animations. Let’s dive in!
🎮 The Concept: Designing a Multi-Game Arcade
The vision was simple: create a collection of retro-inspired games that feel like a cohesive arcade experience. But how?
Key Features:
- 6 Games: From number guessing to Hangman, each game has its own personality.
- User Profiles: Persistent user data with high scores.
- Animations: Real-time generated intro sequences.
- Audio: Background music and sound effects.
Why C++ and CLI?
- Performance: No overhead of graphics libraries.
- Customizability: Full control over terminal output.
- Educational: Demonstrates low-level programming concepts.
🛠️ Architecture: Building the Game Framework
The project is structured like a well-organized game engine, with clear separation of concerns.
Project Structure:
.
├── Games/ # Individual game implementations
├── Screens/ # UI screens (login, hub, etc.)
├── UserManagement/ # User profile and high score system
├── Utils/ # Core utilities (terminal control, audio)
├── audio/ # Audio files
└── README.md # Documentation
Core Components:
- Makefile: Orchestrates the build process.
- main.cpp: Entry point that handles user flow and audio.
- UserManager: Manages user profiles and high scores.
- Audio System: Handles background music and sound effects.
Why This Structure?
- Modularity: Easy to add new games or features.
- Maintainability: Clear separation of concerns.
- Scalability: Can easily expand to more games or features.
🎮 Game Development: Implementing the Arcade
Each game is a self-contained module with its own logic and ASCII art. Let’s look at two examples:
1. Number Guesser
void drawHotColdMeter(int guess, int secret, int w) {
int diff = abs(guess - secret);
int barWidth = 20;
int hotness = (int)((1.0 - (float)diff / 100) * barWidth);
string bar = "[";
for(int i=0; i<barWidth; ++i) {
if (i < hotness) bar += "#";
else bar += "-";
}
bar += "]";
cout << centerText(bar, w) << endl;
}
This game features a dynamic "hot/cold" meter that visually shows how close you are to the target number.
2. Hangman
void drawHangman(int wrong, int w) {
if (wrong >= 1) {
cout << centerText(" | O ", w) << endl;
}
if (wrong >= 4) {
cout << centerText(" | /|\\ ", w) << endl;
}
if (wrong >= 6) {
cout << centerText(" | / \\ ", w) << endl;
}
}
The Hangman game uses ASCII art to draw the hanging figure as the player makes wrong guesses.
Challenges:
- Cross-Platform Compatibility: Ensuring terminal control works on Windows, Linux, and macOS.
- Performance: Optimizing animations to run smoothly at 15 FPS.
🎮 User Management: Profiles and High Scores
User data is stored in a JSON file, with each user having their own set of high scores. The UserManager class handles all database operations.
void UserManager::updateScore(const string& gameName, int score) {
if (!currentUser) return;
if (currentUser->highScores.find(gameName) == currentUser->highScores.end() ||
score > currentUser->highScores[gameName]) {
currentUser->highScores[gameName] = score;
saveUsers();
}
}
Features:
- Persistent Profiles: Users can log in and return to their progress.
- Score Tracking: Each game tracks high scores.
- User Creation: New users can join the fun.
🎮 CLI Magic: Terminal Control and Animations
The terminal is treated like a canvas, with ANSI escape codes controlling every aspect of the output.
Key Techniques:
- ANSI Escape Codes:
cout << "\033[31m"; // Set text color to red
cout << "\033[2J"; // Clear screen
- Segmented Rendering: Only color specific parts of ASCII art.
- Frame-Based Animation: Generate smooth animations using timed loops.
Why This Approach?
- No Dependencies: Uses only standard libraries.
- Cross-Platform: Works on any system with a terminal.
🎮 Adding Polish: Music and Sound Effects
The audio system uses platform-specific tools to play background music and sound effects.
Key Features:
- Background Music: Loops infinitely with dynamic volume control.
-
Cross-Platform Support: Uses
afplayon macOS,mpvon Linux, andwmplayeron Windows. - Clean Shutdown: Ensures no audio files are left hanging.
void playBgMusicLoop(const std::string& filepath, float volume) {
if (!GameSettings.audioEnabled) return;
bgMusicRunning = true;
currentMusicPath = filepath;
currentVolume = volume;
std::thread([filepath, duration]() {
while (bgMusicRunning && GameSettings.audioEnabled) {
startAfplayWithVolume(filepath, currentVolume);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}).detach();
}
🎮 Lessons Learned: Reflections and Future Plans
What Worked Well:
- Modular Design: Made it easy to add new features.
- Terminal Control: Delivered impressive visual effects without graphics libraries.
- User Management: Provided a solid foundation for persistence.
What Would I Change?
- Simpler Audio System: Cross-platform audio was more complex than expected.
- Better Documentation: Would add more comments and guides for contributors.
Future Plans:
- More Games: Expand the arcade collection.
- Multiplayer: Add network capabilities for head-to-head gameplay.
- Improved Graphics: Experiment with Unicode characters for better visuals.
🎮 Conclusion: The Mini Games Journey
Building Mini Games was a thrilling journey into the heart of terminal programming. It’s more than just a collection of games—it’s a demonstration of what’s possible with creativity and low-level programming.
If you’re inspired, check out the GitHub repo and try your hand at creating your own CLI games. Who knows? The next retro arcade hit might just be yours!
🎮 Until next time, keep coding and keep gaming!

Top comments (0)