Q by Noflex

Roguelike platformer on a custom C++/ECS engine

Scroll to explore
Game · Engine programming

The ECS core, parallel systems and enemy AI of a roguelike platformer.

Q is a side-view roguelike platformer where you fight through randomly arranged rooms to collect the cube bricks of a station adrift in orbit. Team Noflex built it on a custom C++ engine — my part was the ECS architecture, its parallel system scheduler, and the enemy AI.

Role
Engine — ECS, parallelism & enemy AI (also team PM)
Focus
ECS architecture · multithreaded systems · enemy AI
Stack
C++ · custom ECS · worker-thread scheduler
Overview

Cube, in orbit

The concept takes the trapped-in-a-shifting-maze premise of the film Cube and lifts it into science fiction: the maze is a derelict station on orbit, broken into rooms that are arranged differently every run. The player drops in, clears each room and pushes on to collect every cube brick.

Because layouts and encounters are rebuilt per run, the underlying systems had to spin entities up and tear them down cheaply every time — which is where the ECS and its parallel scheduling earned their keep.

Concept render — the station in orbit
Core — ECS & parallelism

A data-oriented engine that scales across threads

01

Entity Component System

I built the ECS core: entities are ids, behaviour lives in plain components, and systems iterate over the data. Splitting gameplay this way kept it composable and made building or clearing a room — for every run — a cheap, uniform operation.

02

Cache-friendly data layout

Components are stored in packed, contiguous arrays so the hot per-frame loops stream through memory instead of chasing pointers — the groundwork that makes the parallel pass actually pay off.

03

Parallel system scheduler

Independent systems run across worker threads so per-frame work scales past a single core, rather than ticking everything serially on the main thread.

04

Contention-free partitioning

Work is partitioned so threads operate on disjoint data, with synchronisation kept to the explicit hand-off points between systems — avoiding shared-state races while keeping the threads busy.

Enemy AI

A state machine per enemy, nine of them

I wrote the enemy AI as a finite-state machine framework: every state — Searching, Chasing, Attacking, Missing, Hurting, Dying — is its own class, and the enemy-state system ticks whichever state is active each frame. Switching state just swaps the live state’s function pointers, guarded by the thread-pool mutex so it stays safe under the parallel scheduler.

Transitions are driven by three signals: a sight raycast (a view cone plus a sight distance), weapon-range hits, and collisions. Seven enemy types and two bosses share that backbone but specialise it into very different behaviour.

Warrior

Chases the last-seen player and jumps when it meets a cliff or wall, freezes into its attack at weapon range, wanders when the player is point-blank, and returns to searching once it loses sight.

FlameThrower

Chases like the Warrior, but stops and idles at platform edges instead of jumping so it never walks off, then attacks once the player is in range.

Scout

While chasing, a ~1-second timer auto-fires its attack state, launching a projectile at the player, then it slips back into the chase.

Turret

Never moves: it loops its attack, spawning a bullet aimed straight at the player each cycle, and drops to idle the moment it loses line of sight.

Tanker

Arms then defends — invincible while the shield is up — rotating to keep facing the player, and lowers the shield again when it loses sight.

Engineer

Runs away from the player, then summons a Turret and dies in the act — a sacrificial spawner that turns space into turret fire.

Bomber

Follows an A* path that re-plans every 0.1s to navigate platforms, then self-destructs on contact with a Lua-scripted explosion.

Assassin

A boss whose change-pattern hub picks one of four attack states at random each cycle, then loops back, throwing melee hitboxes up close.

Magician

A boss with the same random four-pattern hub as the Assassin, but ranged — each pattern spawns its own projectile volley.

Role

Engine work, and steering the team

My scope

On the code side I owned exactly three things end to end — the ECS architecture, the parallel system scheduler and the enemy AI. The rest of the engine was built by teammates.

Product manager

I also led team Noflex as PM — owning concept, scope and schedule, and carrying the build through the course milestones (concept proof, pre-production, pre-alpha, alpha, beta, final).

Stack

What I worked in

Engine
C++Custom ECSMultithreading
Gameplay
Enemy AIState machines

The ECS, its parallel scheduler and the enemy AI behind a roguelike shipped with team Noflex.