Gameplay Showcase — Video Placeholder

C/C++ — SDL2 & OPENGL

Custom Rendering Pipeline

View Code

WHAT IT DOES

A fully custom 2D game built without any existing game engine. The rendering pipeline draws every sprite directly through raw OpenGL calls, coordinated by a fixed-timestep game loop that keeps physics and logic deterministic regardless of frame rate.

HOW IT’S BUILT

Wrote a thin abstraction over SDL2 for window/input handling, with OpenGL owning all draw calls. GLSL shaders handle sprite batching and color effects, while manual memory management in C/C++ keeps allocations explicit and predictable.

TECHNOLOGIES

C / C++

SDL2

OpenGL

GLSL

Screenshot Placeholder

GIF Placeholder

C++ — RENDER LOOP

Close code

Game Loop

Renderer Init

Shader Bind

Example
void Engine::Run()
{
const double fixedDeltaTime = 1.0 / 60.0;
double accumulator = 0.0;
double lastTime = GetTime();
 
while (m_isRunning)
{
double currentTime = GetTime();
double frameTime = currentTime - lastTime;
lastTime = currentTime;
accumulator += frameTime;
 
ProcessInput();
 
// Fixed-timestep updates keep physics deterministic
while (accumulator >= fixedDeltaTime)
{
UpdatePhysics(fixedDeltaTime);
UpdateLogic(fixedDeltaTime);
accumulator -= fixedDeltaTime;
}
 
Render();
SDL_GL_SwapWindow(m_window);
}
}

ARCHITECTURAL CHOICE

A fixed-timestep loop decouples simulation from rendering: physics and logic always advance in stable 1/60s steps, while rendering happens as fast as the display allows, keeping gameplay consistent across hardware.

Close code

Game Loop

Renderer Init

Shader Bind

Example
void Engine::Run()
{
const double fixedDeltaTime = 1.0 / 60.0;
double accumulator = 0.0;
double lastTime = GetTime();
 
while (m_isRunning)
{
double currentTime = GetTime();
double frameTime = currentTime - lastTime;
lastTime = currentTime;
accumulator += frameTime;
 
ProcessInput();
 
// Fixed-timestep updates keep physics deterministic
while (accumulator >= fixedDeltaTime)
{
UpdatePhysics(fixedDeltaTime);
UpdateLogic(fixedDeltaTime);
accumulator -= fixedDeltaTime;
}
 
Render();
SDL_GL_SwapWindow(m_window);
}
}

ARCHITECTURAL CHOICE

A fixed-timestep loop decouples simulation from rendering: physics and logic always advance in stable 1/60s steps, while rendering happens as fast as the display allows, keeping gameplay consistent across hardware.

Close code

Game Loop

Renderer Init

Shader Bind

Example
void Engine::Run()
{
const double fixedDeltaTime = 1.0 / 60.0;
double accumulator = 0.0;
double lastTime = GetTime();
 
while (m_isRunning)
{
double currentTime = GetTime();
double frameTime = currentTime - lastTime;
lastTime = currentTime;
accumulator += frameTime;
 
ProcessInput();
 
// Fixed-timestep updates keep physics deterministic
while (accumulator >= fixedDeltaTime)
{
UpdatePhysics(fixedDeltaTime);
UpdateLogic(fixedDeltaTime);
accumulator -= fixedDeltaTime;
}
 
Render();
SDL_GL_SwapWindow(m_window);
}
}

ARCHITECTURAL CHOICE

A fixed-timestep loop decouples simulation from rendering: physics and logic always advance in stable 1/60s steps, while rendering happens as fast as the display allows, keeping gameplay consistent across hardware.

ROLE & TIMELINE

Role: Solo Developer · Month Year – Month Year

CHALLENGES & SOLUTIONS

Without an engine, there is no built-in scene graph or asset pipeline — everything from texture loading to input polling had to be written and debugged manually. The biggest challenge was keeping the render loop stable across frame-rate spikes; solving it meant separating simulation time from render time entirely via the fixed-timestep architecture above.