This was my final major project at university, a 3D tower defence game built in Unreal Engine. I built everything myself: code, 3D assets, textures, UI, and gameplay.
Like most tower defence games, the goal is to build defences along a path to hold off waves of increasingly tough enemies. The emphasis was on the engineering side: building the game’s systems, class architecture, and procedural generation rather than visuals.

Architecture
The whole thing is built around an object-oriented class hierarchy. There’s a parent tower actor with all the shared logic (targeting, rotation, upgrade system, placement validation) and child classes that override the attack behaviour for each type. Same pattern for enemies: a parent enemy class handles health, movement along the spline, and death, with child classes defining stats per tier.
The game loop ties several systems together:
- Wave manager handles spawn timing, enemy composition, and difficulty scaling. Each wave increases enemy health, speed, and count based on a curve. Spawn intervals shrink as waves progress.
- Economy system ticks currency (called Solar) on a timer. Solar Panels add to the tick rate. Killing enemies grants bonus currency. Tower purchase and upgrade costs are defined per tower type and tier.
- Targeting system sits on the parent tower class. Each tower scans for enemies within its range, then picks a target based on the player’s selected mode: closest, strongest, or furthest along the path. Each mode runs a different comparison over the enemy array.
- GameMode orchestrates the session: tracks wave state, player health, win/lose conditions, and coordinates between the UI and gameplay systems.
There are four tower types, each with its own targeting and damage system:



- Cannon interpolates the turret rotation toward the target and only fires once the angle is within 2 degrees. The projectile is a simple Actor with a collision sphere and straight-line movement.
- Rocket Launcher fires homing projectiles using Unreal’s projectile movement component. The interesting bit is retargeting: if the original target dies mid-flight, the missile scans for the next enemy in range and redirects. If there’s nothing left, it self-destructs.
- Laser does continuous damage via a line trace each tick. A cylindrical mesh scales from the tower to the hit point to visualise the beam, with damage multiplied by delta time for frame-rate-independent DPS.
- Solar Panel is passive, no combat logic. Just adds to the economy tick rate. Early investment in solar panels helps the player progress later into the game.
Each tower supports multi-tier upgrades that modify damage, fire rate, scale, material, and rotation speed. A colour system (green, blue, purple, red, yellow, black) gives a visual indicator of both tower and enemy strength at a glance.




Procedural map generation
This was probably the most interesting part technically. Most tower defence games have fixed, hand-built maps. I wanted every playthrough to feel different.
The spline path
The path is built using Unreal’s Spline Component. Points are added iteratively, evenly spaced along the x-axis, with random y-coordinates within the map bounds. Spline mesh components are added between each pair of points, using the position and tangent data from the spline to get smooth curves.

One headache was collision. The spline mesh components didn’t trigger overlap or hit events properly, which meant towers and trees could be placed directly on the road. The fix was adding box collisions at regular intervals along the path. Not very elegant, but it worked.

Environment scattering
Trees and rocks are placed using vertical raycasts from above the terrain to find valid spawn positions. Each hit returns the surface normal, which is compared against the world up vector via dot product to get the slope angle. Anything steeper than 15 degrees from horizontal is rejected, which stops vegetation spawning on cliff faces.
Spawn positions are also weighted by distance from the road. Objects are more likely to appear further from the path, which keeps the playable area clear and gives the road visual breathing room without needing a hard exclusion zone.

After placement, an overlap check removes any objects that intersect with each other or with the road. A recursive retry system then fills any gaps to hit the target density, with a max recursion limit as a safety net. Each object gets randomised scale, rotation, and material hue within defined ranges to break up visual repetition.
Implementation

The project uses a mix of Blueprints and C++. Most gameplay systems (towers, enemies, wave logic, UI) are in Blueprints, with C++ used for the more computationally intensive parts like the environment scattering. The class hierarchy is object-oriented throughout: parent classes define shared interfaces and logic, child classes specialise. Defensive programming patterns like null checks before accessing references and duplicate-add guards on arrays kept things stable as the project grew.
The game was packaged as a Windows 64-bit executable. Main optimisation step was stripping unused assets from the project to reduce the build size.


What I’d do differently now
Looking at this with a few years of industry experience:
- The environment scattering is basically a simple version of what PCG does natively now. If I rebuilt this today, the procedural map generation would be a PCG graph.
- The spline collision workaround (box collisions at intervals) is a hack. There are better approaches with custom collision geometry.
- The wave difficulty scaling was done by feel and playtesting. A proper difficulty curve with maths behind it would be more robust.
- More of the config (tower stats, wave scaling parameters, upgrade costs) should be driven by data assets rather than hardcoded values.
For a university project focused on learning how games are built from the ground up, I’m happy with how it turned out. It was performant, the mechanics all work, and it was fun to play!