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.
Overview
Daemon Starship is a classic 2D space shooter built in C++20 on the custom Daemon Engine. The player pilots a thrust-based starship through 5 progressive waves of enemies — beetles that chase directly, wasps that accelerate toward the player, and asteroids that drift with angular rotation — in a 200×100 unit wraparound world. Shooting, dodging, and surviving earns a score tracked on a persistent top-100 leaderboard saved to disk.
This was my first C++ project — built before I knew about templates or std::vector. Every entity system uses fixed-size arrays with manual pool management, which turned out to be a strong foundation for consistent frame times. The dual-radius collision system and a particle debris system with velocity inheritance round out the core gameplay feel.
Highlights
The fixed-size entity pools (up to 200,000 debris particles, 100 bullets, 30 asteroids) were an assignment requirement, but they ended up teaching me more about memory layout than any textbook could. Because I didn’t know about std::vector or templates at the time, I wrote raw pre-allocated arrays with manual index tracking for every entity type. The result was zero heap allocation during gameplay and consistent 60 FPS — not because I was optimizing, but because I didn’t know the “easier” way.
The original code had the same for-loop pattern copy-pasted for every entity type in every function — Update, Render, DebugRender, DeleteGarbage:
// Before: same loop repeated for every entity type, in every function
void Game::RenderEntities() const {
for (int bulletIndex = 0; bulletIndex < MAX_BULLETS_NUM; bulletIndex++) {
if (!m_bullets[bulletIndex]) continue;
m_bullets[bulletIndex]->Render();
}
for (int asteroidIndex = 0; asteroidIndex < MAX_ASTEROIDS_NUM; asteroidIndex++) {
if (!m_asteroids[asteroidIndex]) continue;
m_asteroids[asteroidIndex]->Render();
}
// ... repeated for beetles, wasps, debris, boxes
}
I later refactored these using C++20 templates to eliminate the duplication. A single ForEachInPool helper deduces the pool’s element type and size at compile time, then iterates only over non-null slots:
// The template that replaced every hand-written loop
template <typename T, int N>
void Game::ForEachInPool(T* (&pool)[N], auto&& fn) {
for (int i = 0; i < N; ++i) {
if (!pool[i]) continue;
fn(pool[i]);
}
}
With that in place, every function that used to repeat the same loop 6 times collapsed to one-liners:
// After: one lambda, all pools
void Game::RenderEntities() const {
auto render = [](Entity const* e) { e->Render(); };
ForEachInPool(m_bullets, render);
ForEachInPool(m_asteroids, render);
ForEachInPool(m_beetles, render);
ForEachInPool(m_wasps, render);
ForEachInPool(m_debris, render);
ForEachInPool(m_boxes, render);
}
The dual-radius collision system was also required, but the implementation came from a game-feel insight I had during development. Each entity carries a conservative physicsRadius for actual hit detection and a liberal cosmeticRadius for visual bounds and off-screen culling. The reason: with a single radius, players would sometimes visually collide with an enemy but take no damage, or get hit by something that looked like a near miss. Separating the two radii let me tune the feel independently from the visuals — tighter physics for fairness, looser cosmetic for visual feedback.
What I Learned
The most fun surprise came from going beyond the assignment. I added destructible boxes that spawn enemies after taking enough hits — this created emergent risk/reward gameplay where players had to decide whether to clear boxes early or focus on existing threats. The persistent scoreboard was another revelation — writing scores to disk with C++ file I/O felt like magic at the time because I genuinely didn’t know the language could do that.
Gallery
Technical Specifications
| Component | Technology |
|---|---|
| Language | C++20 |
| Graphics | DirectX 11, HLSL |
| 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 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.