StijnHogerwerf
About Me Get to Know me.
I'm a creative Game Developer based in Amsterdam, the Netherlands
Graduated Game Developer with a passion for gameplay programming, modular engine systems, and technical problem solving. I enjoy building scalable and maintainable systems while continuously improving my skills as a developer.
Your Image
My Services
service-one

Unity

Most of my projects were made in Unity. So I am the most comfortable working with it.

service-two

Scrum

While working on these projects I used the SCRUM workflow

My Skills
C#
Novice
Expert
C++
Novice
Expert
Kotlin
Novice
Expert
Java
Novice
Expert
Blender
Novice
Expert
Godot
Novice
Expert
Aseprite
Novice
Expert
My Projects Some Of My Work
portfolio-fourth

Graduation Project

Modular Engine Architecture is a research-driven C++ game engine project focused on designing a lightweight and maintainable engine architecture for Grimmwyrd Studios. The project explored how modular subsystem design, performance-oriented architecture, and scalable workflows can improve development efficiency compared to large commercial engines such as Unreal Engine.

portfolio-second

Airport Architect

Airport Architect is a grid-based airport builder game in which you build and manage your airport, continuously expand it, and become the ultimate Airport Tycoon.

portfolio-third

Shadowed Escape

Shadowed Escape is a horror survival game where players explore a dark forest, gathering car parts to repair their vehicle, and evade a sound-sensitive monster that hunts based on noise and light.

portfolio-first

Go Home

Go home is a 3rd person strategy based hack and slash tower defense game where you as the captain must go from planet to planet to collect resources and to get back to your home planet.

Graduation Project Design a modular C++ Engine
This thesis project focused on researching, designing, and prototyping a lightweight modular C++ game engine for Grimmwyrd Studios. The goal of the project was to investigate how a custom engine architecture could improve performance, maintainability, extensibility, and development workflows compared to large commercial engines such as Unreal Engine.

My role in this project was as a engine programmer and software architect. My responsibility was to research modern engine architectures, analyze technical tradeoffs between existing engines, and design a modular subsystem architecture for rendering, physics, input handling, and resource management. In addition, I developed a prototype implementation in C++ to validate the proposed architecture and evaluate how modular design principles could support scalable and maintainable engine development.
portfolio-first

Architecture

During the research phase of the project, multiple architectural approaches were analyzed, including Object-Oriented Programming (OOP), component-based architectures, node-based systems, and Entity-Component-System (ECS). Each approach provided different advantages, but not all of them fully supported the modularity, scalability, and maintainability requirements identified for the engine architecture.

Traditional object-oriented architectures often rely on deep inheritance hierarchies, which can become difficult to maintain as projects grow in complexity. Node-based structures provide clear scene hierarchies, but large scenes can become increasingly difficult to manage. Component-based approaches improve modularity, but they frequently combine data and behaviour within the same structures, which can reduce flexibility when systems expand.

Based on these findings, the Entity-Component-System (ECS) architecture was selected as the foundation of the engine prototype. In the ECS model, entities act as identifiers, components store data, and systems process entities containing specific component combinations. By separating data from behaviour, ECS reduces tight coupling between systems and allows engine subsystems to operate independently. This modular structure improves extensibility and allows new gameplay systems or engine features to be introduced without requiring major architectural changes.

Another important reason for selecting ECS was its suitability for performance-oriented system design. Because component data can be stored in contiguous memory structures, systems can process large numbers of entities efficiently using modern CPU caching techniques. The architecture also simplifies integration with external systems by keeping gameplay state structured and data-driven rather than tightly embedded within object hierarchies.

Through researching and implementing ECS architecture, I gained experience with data-oriented design, modular engine architecture, scalable system organization, and performance-focused runtime structures in C++. This project strengthened my understanding of modern game engine architecture and maintainable large-scale system design.

ECS
Data-Oriented Design
Engine Architecture
portfolio-first

Engine Core

The Engine Core serves as the central control structure of the modular C++ game engine, responsible for initializing the engine, managing the main update cycle, and coordinating communication between subsystems such as rendering, physics, input handling, and resource management. By centralizing system execution, the engine maintains a consistent and predictable update order while improving maintainability and reducing dependencies between subsystems.

At the center of the Engine Core is the Game Loop, which continuously updates the game state during runtime. Each iteration processes player input, updates ECS systems and game logic, performs physics calculations, and renders the updated frame to the screen. The loop combines delta time and a fixed timestep to balance smooth frame-independent updates with stable and deterministic physics simulation behaviour.

Within the ECS architecture, the Engine Core executes systems sequentially based on the components attached to entities. For example, movement systems process entities containing position and velocity components, while rendering systems handle graphical components. This structure enforces a clear separation between data and behaviour while ensuring all gameplay systems remain synchronized during execution.

Through developing this system, I gained practical experience designing modular engine architecture, implementing a custom game loop, and integrating ECS-based system execution in C++. This project strengthened my understanding of maintainable engine design, subsystem communication, and scalable runtime architecture for game development.

Game Loop
ECS Systems
Runtime Architecture
portfolio-first

Render Engine

The Render Engine is responsible for converting the internal game world representation into visual output displayed on the screen. The system processes transformations, meshes, textures, lighting data, and camera information before sending rendering instructions to the graphics hardware through a graphics API. Because rendering is one of the most performance-critical subsystems of a game engine, the architecture was designed with a strong focus on modularity, efficiency, and long-term maintainability.

To simplify system organization and support different rendering workflows, the rendering architecture is separated into dedicated 2D and 3D rendering modules. The 2D renderer handles sprite-based objects such as user interfaces, particle effects, and screen-aligned graphics using textured quads and sprite batching techniques to reduce GPU draw calls and improve rendering performance. The 3D renderer processes mesh geometry, camera projection, depth buffering, and shader-based lighting calculations to render environments and three-dimensional objects.

To improve portability and extensibility, the engine introduces a graphics abstraction layer between the rendering systems and the underlying graphics API. Instead of directly communicating with a platform-specific API, the rendering systems interact with a generic rendering interface that supports interchangeable backend implementations. This abstraction allows the engine to support multiple graphics APIs and simplifies cross-platform deployment for both PC and console environments without requiring changes to the higher-level rendering architecture.

Separating the 2D and 3D rendering pipelines improves maintainability by isolating rendering responsibilities and reducing unnecessary subsystem dependencies. The modular architecture also allows additional rendering features and graphical techniques to be integrated without restructuring the entire rendering system. Through designing this Render Engine architecture, I gained experience with rendering pipeline organization, graphics abstraction layers, shader-based rendering concepts, batching optimization techniques, and scalable renderer design in C++.

Rendering Pipeline
Graphics Abstraction
2D & 3D Rendering
portfolio-first

Input System

The Input System is responsible for processing player interactions and translating hardware signals into gameplay actions that can be used throughout the engine. The architecture was designed to support multiple input devices, including keyboards, mice, and controllers, while remaining modular and independent from platform-specific implementations.

To achieve this, the engine introduces an input abstraction layer that converts raw API-specific inputs into engine-defined input codes. Instead of gameplay systems directly interacting with hardware-specific input values, all systems communicate through a unified engine input interface. This separation improves maintainability and allows the underlying input API to be replaced without modifying gameplay logic or higher-level engine systems.

The system also includes an input mapping layer that connects engine-defined inputs to gameplay actions such as movement, jumping, or interaction events. Multiple hardware inputs can be mapped to the same gameplay action, simplifying support for different input devices and allowing control schemes to be modified without changing gameplay code.

To improve flexibility and subsystem communication, the Input System operates using an event-driven architecture. When a mapped action is triggered, an event is dispatched through the engine’s event system, allowing subscribed systems such as movement, gameplay logic, or user interface systems to respond independently. During each iteration of the game loop, the engine collects hardware input, translates the signals through the abstraction layer, processes the input mappings, and dispatches the resulting events to subscribed systems.

Through designing this Input System architecture, I gained experience with event-driven programming, input abstraction layers, modular system communication, and cross-platform input handling in C++. This project strengthened my understanding of scalable engine architecture and maintainable gameplay system integration.

Event-Driven Architecture
Input Mapping
Cross-Platform Input
portfolio-first

Resource Management

The Resource Management System is responsible for loading, storing, and providing access to game assets used throughout the engine. These resources include textures, images, audio files, and other runtime data required by different engine subsystems. The architecture was designed to improve maintainability, workflow efficiency, and modular access to resources across the engine.

To simplify project organization and ensure consistent asset access, all resources are stored within a dedicated Assets directory inside the project structure. This standardized layout allows the engine to reliably locate and load assets without requiring complex file path management within gameplay or engine systems.

The engine introduces a dedicated resource management layer that acts as an abstraction between the file system and the engine subsystems. Instead of directly interacting with files, systems access resources through predefined loading functions such as texture, image, or audio loaders. These functions handle locating the asset, loading it into memory, and returning a usable resource object to the requesting system. By centralizing resource loading within a single subsystem, the engine maintains a clear separation between asset storage and gameplay logic.

The modular design also improves extensibility by allowing new resource types to be integrated without restructuring existing systems. Additional loading functionality can be added to the resource manager while maintaining the same external interface for the rest of the engine. The architecture also creates opportunities for future optimizations such as asset caching, memory management improvements, and asynchronous resource loading.

Through designing this Resource Management System, I gained experience with file handling, asset pipelines, abstraction layers, modular engine architecture, and scalable resource loading systems in C++. This project strengthened my understanding of maintainable engine workflows and centralized asset management within modern game engine development.

Asset Management
File Handling
Modular Systems
portfolio-first

Physics System

The Physics Engine is responsible for simulating the physical behaviour of entities within the game world, including movement, collision detection, and collision response. The system was designed as an independent subsystem within the engine architecture to ensure that physics calculations remain modular, maintainable, and separate from gameplay logic.

Within the ECS architecture, entities that require physical behaviour contain physics-related components such as position, velocity, and collider components. The engine supports simple geometric colliders, including box and circle colliders, which are used to efficiently detect intersections and interactions between entities. By processing entities through component-based physics systems, the engine maintains a clean separation between data and behaviour while supporting scalable entity management.

During each physics update cycle, the system updates entity movement, performs collision detection, and calculates collision responses to prevent objects from overlapping. Collision calculations update the position and velocity data stored within the entity components, allowing other systems such as rendering and gameplay logic to use the updated world state. To maintain stable and deterministic simulation behaviour, the physics engine operates using a fixed timestep rather than frame-dependent delta time updates.

Running physics calculations at a constant interval improves collision reliability and prevents inconsistencies caused by fluctuating frame rates. The modular ECS-based architecture also allows additional collider types and future physics features to be integrated without requiring major structural changes to the engine.

Through designing this Physics Engine architecture, I gained experience with collision systems, fixed timestep simulation, ECS-driven physics workflows, component-based entity processing, and scalable runtime system design in C++. This project strengthened my understanding of deterministic simulation behaviour and modular physics architecture within modern game engines.

Collision Detection
Fixed Timestep
Physics Systems
Airport Architect Build your own Airport
This was a school project where my team and I needed to make a game to teach students about the background of an airport. We decided that the player builds and manages their own airport terminal. This game is inspired by prison architect.

In this project, my main role was programmer. My responsibility was to implement features carefully and ensure they were bug-free for a smooth player experience. I also served as the notetaker in meetings with our client and teachers, documenting discussions and feedback. This helped our team review and improve our work based on constructive input.
portfolio-first

Object Pool

When you play the game longer, more characters appear on screen, which can impact performance. To handle this, I created a custom, generic Object Pool script that efficiently manages frequently used objects, like characters or projectiles, by recycling them instead of repeatedly creating and destroying them. This script is a generic object pool that can work with any object type, which helped me learn and apply C# generics for the first time. Using generics allowed me to make the pool versatile and reusable across different game elements, enhancing performance as the game progresses.

Generics
Object Pool
portfolio-first

Staff Management

To manage employees in the game, I created a dynamic staff management system that includes hiring, firing, and object pooling for efficient resource management. The systTo manage employees in the game, I created a dynamic Staff Management System that handles hiring, firing, and object pooling for efficient resource management. Each employee is represented by an Employee object, and their data is stored in a dictionary, making it easy to track and manage them by their unique ID.

The system utilizes an object pool to manage the creation and recycling of staff objects. When an employee is needed, the pool spawns a new one, and when an employee is no longer required, they are returned to the pool, optimizing memory usage and reducing the overhead of frequent instantiations. The hiring function checks if the player has enough funds before recruiting a new employee, while the firing function releases the employee's resources when they are let go.

The Staff Manager also includes a salary management system that calculates the total salary owed to all employees and processes their payments automatically. I ensured that all aspects of employee management are handled dynamically, with automatic adjustments for changes in the number of employees.

Through building this system, I learned how to manage dynamic objects and resources efficiently within a game, enhancing gameplay by reducing complexity and optimizing performance.

Dynamic Data Management
portfolio-first

Research Tree

To unlock upgrades and building blocks in the game, the player must complete research tasks. For this, I created a Research Tree that organizes research nodes, where each node represents a different upgrade or technology. To efficiently manage the research process, I developed the RDTreeManager and ResearchNode classes.

The RDTreeManager handles the activation, queuing, and execution of research tasks. It tracks the research nodes, their current state (available, in development, or completed), and manages the queue of tasks. When a node is completed, the manager automatically activates the connected nodes and progresses to the next task in the queue. The manager also ensures that research can be paused, switched, and resumed.

The ResearchNode class represents an individual research task. Each node is linked to other nodes, and when a research task is completed, it unlocks the next set of nodes. The research value is accumulated over time, and once the required value is reached, the node is considered complete. I also added functionality to queue and remove research tasks, ensuring that the research process flows smoothly without interruption.

This system allows for organized and dynamic management of research tasks, ensuring the player can unlock new technologies and progress through the game without feeling overwhelmed by complexity. Through building this, I learned how to create a functional research tree that drives progression and enhances the overall gameplay experience.

R&D Tree
Dynamic System
Shadowed Escape Escape the Terror
I needed to make and publish a game in 3 days for a school project. For this I wanted to make a horror game. So in the game you need to walk through a forest to find parts to repair your car. But there are monsters walking around who will react to sound and to light.

As this was an individual project, I took on the roles of both programmer and designer, handling all core aspects of the game’s development. To streamline the process and focus on coding and design, I sourced assets from the Unity Asset Store, which provided high-quality visuals and audio elements that I adapted to fit my project’s needs. This experience allowed me to practice balancing technical and creative responsibilities in a solo project.
portfolio-first

Enemy AI

To create a suspenseful and dynamic AI system for the monster in the game, I developed a behavior management system that reacts to player actions and environmental factors in real-time. This AI system features a range of monster states—including Roaming, TowardSound, and TowardPlayer—each of which determines how the monster interacts with the player, creating a more immersive horror experience.

In the Roaming state, the monster wanders randomly within a set radius around the player, moving to new locations periodically. This adds a layer of unpredictability, keeping the player on edge. The system includes mechanisms to detect sounds through a microphone input: if the player speaks too loudly or makes noise, the monster enters the TowardSound state and approaches the source of the sound, bringing an extra level of interactivity and tension. Additionally, the monster can detect the player's flashlight or proximity, triggering the TowardPlayer state, where it homes in directly on the player, heightening the threat.

To make this system efficient and realistic, I utilized Unity's NavMeshAgent for smooth pathfinding and character movement, along with an Animator for dynamically adjusting the monster's animations. By leveraging Unity's geometry utility functions, the monster also checks if the player is within its field of view, adding a layer of stealth challenge for the player.

Through building this AI system, I gained experience with advanced state management, real-time audio processing, and navigation control in Unity. This project helped me deepen my understanding of player-centered AI design, enhancing gameplay immersion by making the monster’s behavior feel reactive and lifelike.

AI State Management
Audio-Based AI Detection
portfolio-first

Mic Detection

This AudioLoudnessDetection class is a core component for creating an interactive enemy AI that responds to the player’s real-time microphone input, adding a unique and immersive element to gameplay. Here’s how it works:

The class captures audio from the player’s microphone, analyzes the loudness, and provides a value that reflects the player's current noise level. This loudness level can be used by the enemy AI to determine the player’s position if they make too much noise, adding a stealth and suspense dynamic.

Real-Time Sound Detection
Go Home Time to Survive
This was the first project I needed to make in unity. For this my team and I decided to make a hack-and-slash tower defence game. Where you need to defend your homebase against hordes of enemies.

My task in this project was a programmer.My responsibility was to implement features carefully and ensure they were bug-free for a smooth player experience.
portfolio-first

Enemy AI

The Enemy script manages the enemy's health, damage, movement, and knockback. It includes methods for taking damage, reducing health, and applying knockback using a NavMeshAgent for movement and a Rigidbody for physical interactions. The TakeDamage method reduces health, and the Die method destroys the enemy when health reaches zero. The KnockBack coroutine moves the enemy upon being hit, while the enemy's movement speed is controlled via the speed variable. This system ensures realistic combat and enemy behavior, responding to player actions effectively.

The Enemy Controller defines the behavior of an enemy character in a game, using a NavMeshAgent for movement and targeting different routes or the player. It includes a system for dynamically selecting one of several predefined routes, where the enemy moves between checkpoints. The RouteStart method sets up the initial route based on a spawner ID, choosing between different path routes. The TargetRoute methods control the enemy’s movement towards checkpoints along these routes, checking distances to determine when to proceed to the next point. The Attack method allows the enemy to switch to a "Melee" animation when within a stopping distance of the target, otherwise it moves towards the target with a "Walking" animation. Additionally, the FaceTarget method ensures the enemy faces the player or the current target. If the player comes within the lookRadius, the enemy will switch its target to the player. This system enables more immersive and dynamic enemy AI behavior, where the enemy can follow a route and switch to pursuing the player if the player gets too close.

Through this system, I gained hands-on experience with Unity’s NavMeshAgent and pathfinding tools, learning to create AI that navigates through waypoints and adapts to the environment. I implemented a flexible route system that allows enemies to follow different paths, making encounters unpredictable and dynamic. This project also deepened my understanding of modular AI design, where I could easily adjust the behavior and animations of the enemy, enhancing gameplay immersion.

AI State Management
NavMesh
portfolio-first

Spawner

This code is responsible for managing enemy spawning in waves within a game. It utilizes a list of spawn points (spawnerList) and a spawn radius (spawnRadius) to determine where enemies will appear on the map. The enemies are spawned at random intervals (newEnemySpawn) within a specific wave duration (maxTimeInWave), with the wave timer controlling when to trigger the next wave. The EnemySpawn() coroutine handles the process, ensuring that enemies are instantiated at random positions around selected spawners, and the number of enemies spawned (nEnemy) is controlled by the spawn logic. Additionally, the script includes logic for handling different spawn points, allowing for flexibility in how enemies are distributed across the level.

Wave Spawner
Contact Me
Get In Touch.
Email Me
Contact Info
name-icon
Name

Stijn Hogerwerf

location-icon
Location

Amsterdam, The Netherlands

phone-icon
Call

+31683920494

email-icon
Email

shogerwerf.work@gmail.com