Fixed timestep
Game logic advances using a controlled timestep so gameplay behaviour does not depend directly on how quickly frames are being rendered.
A real-time strategy game built from scratch in C# and MonoGame, with resource management, combat systems and an AI opponent.
Built with
An A-Level Computer Science project built from scratch in C# using MonoGame. DeadSteel combines real-time gameplay, resource management, unit spawning, combat and an AI opponent while requiring the underlying game loop, state management and entity systems to be designed independently.
DeadSteel is a real-time strategy game I built for A-Level Computer Science.
I deliberately avoided using a full game engine because I wanted to understand what was actually happening underneath the game.
That meant designing the game loop, entity management, resource systems, combat, AI decisions and rendering myself.
The player manages resources, builds units and fights an AI opponent in real time. The interesting part technically is that all of those systems have to operate continuously without the game becoming unstable or unresponsive.
A real-time game gives you a surprisingly strict constraint: everything has to happen quickly enough to maintain a consistent frame rate.
Every unit needs updating. The AI needs to make decisions. Inputs need processing. The game needs rendering.
If one system becomes too expensive, the entire game feels it.
I therefore had to think about both software architecture and performance rather than treating each feature independently.
I wanted my A-Level project to be something I would actually enjoy building.
A game gave me a reason to learn about object-oriented design, state management, algorithms and AI while having a visible result at the end.
More importantly, building it without a large engine forced me to understand the underlying systems instead of hiding them behind high-level tools.
The game is organised around a fixed update and draw cycle.
Game state is updated first, including player input, unit movement, resource production and AI decisions.
Rendering then displays that state without changing it.
Keeping those responsibilities separate made debugging significantly easier as the project grew.
Game loop
Controls the update and rendering cycle
Game state
Tracks units, resources, buildings and map state
Input system
Handles player commands and selections
AI system
Evaluates the game state and selects actions
Combat system
Movement, targeting and combat resolution
Renderer
Draws the world, units and interface
Game logic advances using a controlled timestep so gameplay behaviour does not depend directly on how quickly frames are being rendered.
Units are updated through structured collections rather than allowing increasingly deep object relationships to control the game loop.
The AI evaluates the current game state and chooses between economic and military actions rather than following a completely scripted sequence.
Units and buildings depend on accumulated resources and production times, creating a trade-off between investing in the economy and building military strength.
Code that worked perfectly with a small number of units started causing frame drops once the number of active entities increased.
I had to look at the cost of work happening every frame rather than simply adding more hardware.
My first AI was either too predictable or too strong.
The solution was not simply to give it better decisions. I also had to limit how quickly it could react and what information it could use so that the opponent felt challenging rather than artificial.
Allowing rendering code to modify game state created bugs that were difficult to reproduce.
Separating simulation from presentation made the overall system much easier to reason about.
When something runs every frame, a small inefficiency becomes a large one very quickly.
Good game AI needs constraints. Giving the opponent imperfect information and delayed reactions can make it more believable than simply increasing its power.
Separating what the game knows from how the game displays it is one of the most useful architectural patterns I took away from the project.