top of page

Doomenstein
Abstract
Doomenstein is an academic game project inspired by Doom (1993), aiming to replicate its core gameplay and rendering features.
This project introduces modern rendering techniques like per-pixel lighting and uses XML to define game content such as levels, actors, and sprite animations. Through data-driven systems, the project supports rapid iteration for weapon, enemy, and player design.
Additional design features include a lock-on weapon with an animated reticle and advanced enemy behaviors like invisible skills and energy shields.
-
Game Genre: First-Person Shooter for PC
-
Role: Programmer
-
Team Size: Individual Academic Project
-
Language: C++
-
Engine: Duality Engine(My custom C++ game engine)

Vaporum_demo

Dynamically adapting UI Widget
Each widget contains a series of ImageBox and TextLine objects. The ImageBox adapts to the widget's size based on its percentage settings, ensuring the image scales dynamically within the widget.
The TextLine elements can function as buttons, each assigned a unique button index for keyboard or controller selection. Buttons also support customizable font color, hover color, and background color to provide visual feedback.
Each widget has a predefined screen height and width, which control its scaling behavior to maintain proper proportions across different screen resolutions.

Particle System
The particle manage all the emitters and is responsible of modifying the sorting the particles' order for rendering based on the camera's position.
Each emitter has a series of variables to control each particle's physics data when spawning them. The emitter also uses float range to control the randomness when spawning the particles.
For each particle it is a full camera opposing billboard, which rotates according to player's camera orientation.

Net System
My network system uses TCP to establish a connection between the server and the client. The helper functions IsClient() and IsServer() assist the Update() function in managing ClientState or ServerState, depending on whether the program is set to a specific NetSystemMode in the NetSystemConfig.
The sendBufferSize and receiveBufferSize determine the amount of data the NetSystem can send or receive in a single frame. Those data are stored in the sendQueue and recvQueue.
The function ReadCommandFromReceiveQueue() process incoming commands by executing them when it detects a predefined terminator.
Meanwhile, PackSendQueueWithCommands() and PrepareSendBuffer() handle outgoing data by packaging game commands into the buffer for the other player to execute.

Game Commands
These commands simplify how player input is executed in the game and make it possible to synchronize the player and server by simply sending these commands over the network.


Subscribing And Sending
By utilizing the event system and network system, we can subscribe to all game commands and transmit the subscribed command strings through the NetSystem.
![]() | ![]() | ![]() | ![]() |
---|---|---|---|
![]() | ![]() | ![]() | ![]() |
bottom of page