Custom C++ Engine ⢠SDL2 & WebAssembly
Play as Sir Rad, a knight who abandons his post defending the castle to perform sick stunts instead. The core technical objective of this university project was to architect a custom 2D engine from scratch in C++ and tie custom audio tracks (including my own vocals) directly to the gameplay mechanics.
void Collision::UpdateGrid()
{
for (size_t i = 0; i < spatialGrid.size(); i++) {
spatialGrid[i].clear();
}
for (size_t i = 0; i < engine->allcharacters.size(); i++) {
Character* c = engine->allcharacters[i];
if (!c->GetSpawned()) continue;
CalculateHitZone(c);
///flattening a 2d grid to a 1d array index for cache locality
int bucketIndex = c->collisionZone[0] + (c->collisionZone[1] * hitZoneDepth);
spatialGrid[bucketIndex].push_back(c);
}
}
void Collision::CheckCollision(Character* thisChar)
{
int bucketIndex = thisChar->collisionZone[0] + (thisChar->collisionZone[1] * hitZoneDepth);
std::vector& localZone = spatialGrid[bucketIndex];
int thisLX = thisChar->GetPosX();
int thisRX = thisChar->GetPosX() + thisChar->GetSizeW();
int thisTY = thisChar->GetPosY();
int thisBY = thisChar->GetPosY() + thisChar->GetSizeH();
for (size_t i = 0; i < localZone.size(); i++)
{
Character* other = localZone[i];
if (other == thisChar) continue;
int listLX = other->GetPosX();
int listRX = other->GetPosX() + other->GetSizeW();
int listTY = other->GetPosY();
int listBY = other->GetPosY() + other->GetSizeH();
if (thisRX > listLX && thisLX < listRX && thisTY < listBY && thisBY > listTY)
{
thisChar->Collide(other);
}
}
}
void GameEngine::Step()
{
static Uint32 lastTime = SDL_GetTicks();
static float timeAccumulator = 0.0f;
const float TIME_STEP = 16.667f; // Fixed 60Hz update step
Uint32 currentTime = SDL_GetTicks();
float frameTime = (float)(currentTime - lastTime);
lastTime = currentTime;
// Spiral of Death preventer (Capped at 100ms)
if (frameTime > 100.0f) {
frameTime = 100.0f;
}
timeAccumulator += frameTime;
Input();
// Fixed timestep physics loop
while (timeAccumulator >= TIME_STEP) {
Update();
totalTime += TIME_STEP;
timeAccumulator -= TIME_STEP;
}
Render();
#ifndef __EMSCRIPTEN__
// Native Desktop frame-limiting delay
if (TIME_STEP - aTimer.getTicks() >= 0) {
SDL_Delay(TIME_STEP - aTimer.getTicks());
}
aTimer.resetTicksTimer();
#endif
}
//inside the main.cpp (SirRad.cpp)
#ifdef __EMSCRIPTEN__
#include
GameEngine* globalGame = nullptr;
void MainLoop()
{
if (globalGame) {
globalGame->Step();
}
}
#endif
//inside the main to start the emscripten loop or basic loop, I have a splash screen
#ifdef __EMSCRIPTEN__
globalGame = new GameEngine(window);
emscripten_set_main_loop(MainLoop, 60, 1);
#else
GameEngine theGame(window);
///game of life splash screen not included in emscripten version
theGame.Splash();
theGame.GameLoop();
SDL_Quit();
#endif