DEV Community

MUHAMMAD AREEB
MUHAMMAD AREEB

Posted on

Building a C++ CLI Arcade: The Mini Games Project

Banner: CLI Arcade Experience


🎮 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
Enter fullscreen mode Exit fullscreen mode

Core Components:

  1. Makefile: Orchestrates the build process.
  2. main.cpp: Entry point that handles user flow and audio.
  3. UserManager: Manages user profiles and high scores.
  4. 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;
}
Enter fullscreen mode Exit fullscreen mode

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;
    }
}
Enter fullscreen mode Exit fullscreen mode

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();
    }
}
Enter fullscreen mode Exit fullscreen mode

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:

  1. ANSI Escape Codes:
   cout << "\033[31m"; // Set text color to red
   cout << "\033[2J";  // Clear screen
Enter fullscreen mode Exit fullscreen mode
  1. Segmented Rendering: Only color specific parts of ASCII art.
  2. 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 afplay on macOS, mpv on Linux, and wmplayer on 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();
}
Enter fullscreen mode Exit fullscreen mode

🎮 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)