Daemon Windows
A multi-window action game that turns the Windows desktop into a shrinking battlefield, with wave-based survival, a shop upgrade system, and real Win32 windows as game objects.
Overview
Daemon Windows is an experimental action game that breaks out of the single-window paradigm. Instead of rendering inside one viewport, the game spawns real OS windows — the player lives inside one, enemies can each have their own, and the shop opens as a separate window. The player’s window continuously shrinks, creating mounting pressure to eliminate enemies and collect coins before running out of space.
The core loop is wave-based survival: triangle-shaped enemies chase the player across the desktop, bullets fly between windows, defeated enemies drop coins, and between waves the player spends coins in a shop to upgrade fire rate, damage, projectile count, piercing, homing, and more. Boss waves arrive every 5 rounds with scaled difficulty.
Built as a personal project exploring unconventional game design, the game runs on a custom Daemon Engine providing DirectX 11 rendering, FMOD audio, and a widget UI system — extended here with a WindowSubsystem that manages the creation, animation, positioning, and destruction of native Win32 windows as first-class game objects.
Architecture
The game extends the Daemon Engine with two custom subsystems: WindowSubsystem for multi-window management and WidgetSubsystem for in-window UI. The Gameplay layer owns the state machine, entity system, and wave/upgrade managers. All communication flows through the Engine’s EventSystem.
| Module | Description |
|---|---|
| Gameplay | Game state machine, entity base class, Player/Triangle/Bullet/Coin/Shop entities |
| WaveManager | Progressive difficulty with base × 1.2^(wave-1) scaling, boss waves every 5 rounds |
| UpgradeManager | 7 upgrade types × 5 levels with 1.5× cost scaling per level |
| WindowSubsystem | Win32 window creation, animation, entity↔window bidirectional mapping, focus management |
| WidgetSubsystem | ButtonWidget text labels rendered on child windows |
Features
Multi-Window Gameplay
The WindowSubsystem creates and manages real Win32 child windows at runtime. Each entity can optionally own a window — the player always has one, and enemies spawn with or without windows randomly. Windows track their owning entities, follow entity positions on screen, and support smooth animated resizing and repositioning via interpolation. Each child window gets its own DirectX swap chain for independent rendering.
Wave-Based Survival with Shop Upgrades
The WaveManager drives progressive difficulty: each wave spawns base × 1.2^(wave-1) enemies, with boss waves every 5 rounds. Between waves, the player opens the Shop (a separate OS window) to spend collected coins on 7 upgrade types:
| Upgrade | Effect |
|---|---|
| Fire Rate | Faster bullet cooldown |
| Damage | Higher bullet damage |
| Projectile Count | More bullets per shot |
| Bullet Spread | Wider shot pattern |
| Bullet Size | Larger hit area |
| Piercing | Bullets pass through enemies |
| Homing | Bullets track nearest enemy |
Window Shrinking Mechanic
The player’s window continuously shrinks frame-by-frame via AnimateWindowPositionAndDimensions, compressing the playable area. The shrink stops when the client dimensions reach 2.5× the player’s physics radius, preventing a zero-size window. Enemy windows with the hasChildWindow flag also shrink. This creates a ticking clock — clear enemies and progress before the window becomes too small to maneuver.
Event-Driven Architecture
All game state transitions, collisions, wave progression, and upgrades flow through the Engine’s EventSystem with named events and typed arguments. OnCollisionEnter dispatches per-entity collision responses, OnWaveStart/OnWaveComplete manage wave lifecycle, OnUpgradePurchased confirms purchases, and OnEntityDestroyed triggers coin drops. Entities subscribe and unsubscribe independently without direct references to each other.
Code
The WindowSubsystem bridges game entities to real Win32 windows — creating an HWND, wrapping it in a game Window object, registering a DirectX swap chain, and establishing bidirectional entity↔window mapping:
WindowID WindowSubsystem::CreateChildWindow(EntityID const owner,
String const& windowTitle,
int const x,
int const y,
int const width,
int const height)
{
// Check if entity already owns a window
auto existingIt = m_actorToWindow.find(owner);
if (existingIt != m_actorToWindow.end())
return existingIt->second;
HWND hwnd = CreateOSWindow(windowTitle, x, y, width, height);
if (!hwnd)
return INVALID_WINDOW_ID;
WindowID newId = m_nextWindowID++;
std::unique_ptr<Window> newWindow = std::make_unique<Window>(config);
newWindow->SetWindowHandle(hwnd);
newWindow->SetDisplayContext(GetDC(hwnd));
newWindow->SetWindowDimensions(Vec2((float)width, (float)height));
newWindow->SetWindowPosition(Vec2((float)x, (float)y));
m_windowList.emplace(newId, WindowData{std::move(newWindow), {owner}});
m_actorToWindow[owner] = newId;
if (g_renderer)
g_renderer->CreateWindowSwapChain(*m_windowList[newId].m_window);
ShowWindow(hwnd, SW_SHOW);
return newId;
}
Technical Specifications
| Component | Technology |
|---|---|
| Language | C++20 (MSVC) |
| Graphics | DirectX 11, HLSL |
| Window Management | Win32 API (multi-HWND, per-window swap chains) |
| Audio | FMOD |
| Engine | Custom Daemon Engine |
| Platform | Windows (x64) |
Related Projects
Game Dev
Daemon Engine
A custom C++20 game engine with V8 JavaScript scripting, DirectX 11 rendering with bloom pipeline, multithreaded JobSystem, FMOD 3D spatial audio, TCP/UDP networking, and a publish/subscribe event system.
Game Dev
Daemon Libra
A 2D top-down tank shooter with heat-map AI pathfinding, procedural map generation via worm algorithms, and bouncing bullet physics, built on a custom C++ engine.
Game Dev
Daemon Starship
A 2D space shooter with fixed-size entity pools, dual-radius collision, and 5 progressive enemy waves, built on a custom C++ engine.