tgames

Crates.iotgames
lib.rstgames
version0.3.3
created_at2024-04-28 17:35:37.240071+00
updated_at2026-01-22 12:01:40.386788+00
descriptionA collection of little terminal games
homepage
repositoryhttps://github.com/enfmarinho/tgames.git
max_upload_size
id1223397
size5,100,649
Eduardo Marinho (enfmarinho)

documentation

README

๐Ÿ•น๏ธ tgames

Rust License Cargo

tgames demo

A terminal-based mini-games emulator.

๐ŸŽฎ List of games

  • Snake
  • Tetris
  • 2048
  • Minesweeper
  • Flappy Bird

๐Ÿ› ๏ธ Technical Highlights

tgames is built with scalability in mind. It uses a Trait-based abstraction to handle game logic, allowing for easy expansion.

  • State Machine Architecture: Uses a centralized game loop and state machine to handle transitions between different game logics seamlessly.
  • High-Performance Rendering: Leverages Ratatui for optimized terminal drawing and immediate-mode UI rendering, allowing for smooth, high-frequency updates with minimal CPU overhead
  • Non-Blocking Input: Implemented a multi-threaded event loop using MPSC channels to decouple input polling from game logic, ensuring a fluid, non-blocking frame rate regardless of user activity.
  • Easy Extension: Adding a new game is as simple as adding a variant to the Games enum and implementing the GameManager trait for a new struct. No changes to the core engine are required

๐Ÿš€ Adding a New Game

The engine uses the Strategy Pattern to remain decoupled from game logic. To add a new game, simply implement the GameManager trait and register it in the central dispatcher.

Implement the Trait

impl GameManager for MyNewGame {
    fn process_events(&mut self) -> Result<()> { /* Handle non-blocking input */ }
    fn update(&mut self) -> Result<()>         { /* Physics & Logic */ }
    fn render(&mut self, terminal: &mut ...)   { /* Draw to TUI via Ratatui */ }
    fn reset(&mut self)                        { /* Re-initialize state */ }
    fn ended(&self) -> bool                    { /* Game Over condition */ }
    fn kill_execution(&self) -> bool           { /* Kill game execution condition */ }
}

Register the game

Add the variant to the Games enum. The engine handles the lifecycle and state transitions automatically. New games are registered within the run_game dispatcher:

fn run_game(&mut self) -> Result<()> {
    // more code...
    match game {
        Games::MyNewGame => self.game_instance[index]
            .get_or_insert_with(|| Box::new(MyNewGame::new()))
            .run(&mut self.terminal),
        // Other games logic...
        _ => { /* ... */ }
    }
    // more code...
}

๐Ÿ“ฆ Installation

The installation can be done via cargo, just use:

cargo install tgames

๐Ÿฆ€ Why Rust?

I chose Rust for this project not just for its modern syntax, but for the specific guarantees it provides for systems-level development:

  • Fearless Concurrency: Rustโ€™s ownership model ensured that my multi-threaded input handling remained data-race free, allowing for a stable, non-blocking game loop.

  • Deterministic Resource Management: Rust allows for precise control over heap allocations. This ensures that the runtime execution and memory footprint of the program to remain highly predictable.

  • Zero-Cost Abstractions: The Trait-based architecture used in tgames allows for high-level modularity without sacrificing the performance of the underlying machine code.

  • Learning: Beyond the technical requirements, I chose Rust out of curiosity and desire to master a modern approach to systems design. I wanted to move away from manual memory management and learn the Borrow Checker to improve my ability to write memory-safe software.

Commit count: 157

cargo fmt