Loading
Personal Project
Eurekiel: Galaxy Tetris Destroyer

Eurekiel: Galaxy Tetris Destroyer is a 2D hybrid game built from scratch in C++ on a custom engine. The player controls a spaceship that shoots enemies while managing falling Tetris pieces on a grid. The spaceship orients toward the mouse cursor, enemies spawn in waves, and Tetris blocks can be destroyed by bullets or cleared by completing lines. I built every system from the ground up, including the entity framework, event bus, particle effects, UI layer, and a data-driven content pipeline.

Starship Banner
The game combines spaceship combat with Tetris block mechanics in a single playfield

The game features a full main menu system with animated transitions. The UI layer is built on a custom WidgetManager that handles widget lifecycle, input routing, and render ordering across both screen-space and world-space cameras.

0:00
/0:00
Main menu UI with animated transitions and widget management

Spaceship Mouse Control

The player ship constantly orients toward the mouse cursor. I implemented this by converting the screen-space mouse position into world-space coordinates using the engine’s dual-camera system (a 1600x800 screen camera and a 200x100 world camera). The ship’s orientation angle is calculated via atan2 from the ship position to the converted mouse world position, giving smooth and responsive aiming.

0:00
/0:00
Player spaceship orientation follows the mouse cursor through screen-to-world coordinate conversion

Tetris Block System

Breakable Blocks and Collision

Each Tetris piece (Tetromino) is composed of individual Cube entities placed on a grid. Cubes have health and can be damaged by player bullets. When a cube’s health reaches zero, it is destroyed and removed from the grid. The grid tracks occupancy per cell, and destroying part of a Tetromino leaves the remaining cubes in place.

0:00
/0:00
Shooting individual blocks out of a Tetris piece, leaving remaining cubes on the grid

Destroying Entire Tetrominos

When all cubes belonging to a single Tetromino are destroyed, a TetrominoAllChildDieEvent fires through the event system. This awards bonus points to the player, rewarding aggressive play.

0:00
/0:00
Destroying all blocks of a Tetromino grants extra bonus points

Line Clear Algorithm

The grid implements a line-clear algorithm similar to classic Tetris. When an entire row of cells is occupied, the row is cleared and all blocks above shift down. The scoring scales with the number of lines cleared simultaneously, rewarding the player for setting up multi-line clears. The PointGainEvent broadcasts the score change to the UI and wave system.

0:00
/0:00
Line clear mechanic with score multiplier based on the number of lines cleared at once

Vertical Tetris Movement

Players can use the mouse wheel to move the active Tetris piece vertically, adding a strategic layer to block placement. This input is processed through the event system via TetrominoRequestOperateEvent, which validates the move against grid boundaries before applying it.

0:00
/0:00
Mouse wheel controls vertical movement of the active Tetris piece

Wave System

The LevelHandler manages wave progression through a score threshold system. Each wave defines which enemy types spawn, their spawn rates, and the score required to advance. When the player’s accumulated score reaches the threshold, the next wave unlocks with new enemy types and increased difficulty. The wave configuration is driven by FLevel data structures that designers can tune without modifying code.

0:00
/0:00
Wave progression triggered by reaching score thresholds, unlocking new enemy types

Enemy Types

Beetle

The Beetle is a slow-moving enemy that drifts toward the player at a constant speed. It serves as the baseline threat in early waves, teaching players to aim and manage space.

0:00
/0:00
Beetle enemy slowly tracking toward the player ship

Wasp

The Wasp is a faster, more aggressive enemy that accelerates toward the player. It applies increasing velocity over time, creating pressure and forcing the player to prioritize targets.

0:00
/0:00
Wasp enemy accelerating toward the player with increasing speed

2D Particle System

I built a custom 2D particle system with physics-based simulation. The ParticleHandler manages particle pools, and each particle has configurable properties including lifetime, velocity, acceleration, color interpolation, and scale curves defined in FParticleProperty. Particles are used for bullet impacts, explosions, and visual feedback throughout the game.

0:00
/0:00
Custom 2D particle system with physics-based emitters for visual effects

Sprite Sheet Resources

All game visuals are rendered from sprite sheets, with each sprite defined through the data-driven SpriteSheetDefinition system. This allows adding or modifying visual content by editing XML files rather than recompiling code.

Sprite Sheet Resources
Sprite sheet atlas used for all game entities, UI elements, and particle effects

System Architecture

The game is built on an event-driven architecture with clear separation between systems. The EventManager acts as a central message bus, decoupling the scoring, grid, wave, and entity systems from each other.

graph TD
    subgraph Core["Core Engine"]
        APP[App] --> GAME[Game Loop]
        GAME --> EM[EventManager]
        GAME --> RM[ResourceManager]
        GAME --> WM[WidgetManager]
    end

    subgraph Entities["Entity System"]
        PS[PlayerShip]
        BUL[Bullet]
        BEE[Beetle]
        WSP[Wasp]
        AST[Asteroid]
        TET[Tetromino]
        CUB[Cube]
    end

    subgraph Grid["Grid System"]
        GR[Grid] --> LC[Line Clear]
        GR --> OCC[Cell Occupancy]
    end

    subgraph Data["Data-Driven Definitions"]
        XML[XML Files] --> SPR[SpriteSheetDefinition]
        XML --> SND[SoundDefinition]
        XML --> TXR[TextureDefinition]
        XML --> TDF[TetrominoDefinition]
    end

    subgraph Systems["Game Systems"]
        LH[LevelHandler / Waves]
        PH[ParticleHandler]
        SC[Score System]
    end

    GAME --> Entities
    GAME --> Grid
    RM --> Data
    PS -->|fires| BUL
    BUL -->|damages| CUB
    CUB -->|occupies| GR
    TET -->|spawns| CUB
    LC -->|PointGainEvent| EM
    EM -->|score update| SC
    SC -->|threshold check| LH
    LH -->|spawn enemies| Entities
    CUB -->|death| PH

Data-Driven Content Pipeline

Game content is defined in XML files under Run/Data/Definitions/. Each definition type has a corresponding C++ loader class that parses the XML at startup:

  • SpriteSheetDefinition maps sprite names to atlas regions with frame dimensions and animation data
  • TetrominoDefinition defines the shape, color, and block layout of each Tetris piece type (I, J, L, O, S, T, Z)
  • SoundDefinition maps sound names to audio files with volume and playback settings
  • TextureDefinition registers texture assets with their file paths and sampling parameters

This separation means designers can add new Tetromino shapes, adjust sprite animations, or swap sound effects by editing XML without touching C++.

Design Philosophy

Event-Driven Decoupling — Systems communicate through a central EventManager rather than direct references. When a cube dies, it fires a CubeTouchBaseLineEvent. When a Tetromino loses all children, it fires TetrominoAllChildDieEvent. The score system, wave system, and UI all subscribe independently. This makes adding new reactive behaviors trivial without modifying existing code.

Data-Driven Content — All visual assets, audio, and Tetromino shapes are defined in XML. The C++ code provides the runtime systems, while XML definitions provide the content. This clean boundary means gameplay tuning and content creation happen without recompilation.

Dual-Camera Coordinate System — The engine runs two cameras simultaneously: a world camera (200x100 units) for gameplay entities and a screen camera (1600x800 pixels) for UI. Mouse input arrives in screen space and is converted to world space for gameplay interactions, keeping the coordinate systems clean and resolution-independent.

Component-Style Entity Design — All game objects inherit from a base Entity class that provides position, velocity, collision, health, and rendering. Specialized behaviors (mouse aiming for PlayerShip, acceleration for Wasp, grid occupancy for Cube) are added in subclasses, keeping the base lean and each entity focused on its unique behavior.

Physics-Based Particles — Rather than using pre-baked animations, the particle system simulates each particle with velocity, acceleration, and lifetime. This produces organic, varied visual effects from a small set of configurable parameters defined in FParticleProperty.