diff --git a/src/Asteroid.c b/src/Asteroid.c index 1af6bd9..66b035c 100644 --- a/src/Asteroid.c +++ b/src/Asteroid.c @@ -722,22 +722,67 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt) multiplierToStringP, V2(0, 0), 0, V4(1.0f, 1.0f, 1.0f, 1.0f), 3, 0); /* Process multiplier bar updates */ - f32 barTimerPenalty = 1.0f; - if (world->timeSinceLastShot < 1.5f) + if (!common_isSet(world->flags, gameworldstateflags_player_lost)) { - barTimerPenalty = 0.1f; + f32 barTimerPenalty = 1.0f; + if (world->timeSinceLastShot < 1.5f) + { + barTimerPenalty = 0.1f; + } + + world->scoreMultiplierBarTimer += (barTimerPenalty * dt); + world->timeSinceLastShot += dt; + + if (world->scoreMultiplierBarTimer > + world->scoreMultiplierBarThresholdInS) + { + world->scoreMultiplierBarTimer = 0; + world->scoreMultiplier++; + + if (world->scoreMultiplier > 9999) + world->scoreMultiplier = 9999; + } } + } - world->scoreMultiplierBarTimer += (barTimerPenalty * dt); - world->timeSinceLastShot += dt; + if (common_isSet(world->flags, gameworldstateflags_player_lost)) + { + Font *arial40 = asset_fontGet(&state->assetManager, "Arial", 40); - if (world->scoreMultiplierBarTimer > - world->scoreMultiplierBarThresholdInS) + char *gameOver = "Game Over"; + v2 gameOverP = v2_scale(state->renderer.size, 0.5f); + renderer_stringFixedCentered( + &state->renderer, &state->transientArena, arial40, "Game Over", + gameOverP, V2(0, 0), 0, V4(1, 1, 1, 1), 0, 0); + + v2 gameOverSize = asset_fontStringDimInPixels(arial40, gameOver); + v2 replayP = V2(gameOverP.x, gameOverP.y - (gameOverSize.h * 1.2f)); + + renderer_stringFixedCentered( + &state->renderer, &state->transientArena, arial40, + "Press enter to play again or backspace to return to menu", replayP, + V2(0, 0), 0, V4(1, 1, 1, 1), 0, 0); + + if (platform_queryKey(&state->input.keys[keycode_enter], + readkeytype_one_shot, 0.0f)) { - world->scoreMultiplierBarTimer = 0; - world->scoreMultiplier++; + // TODO(doyle): Extract score init default values to some game + // definitions file + world->score = 0; + world->scoreMultiplier = 5; + world->scoreMultiplierBarTimer = 0.0f; + world->scoreMultiplierBarThresholdInS = 2.0f; - if (world->scoreMultiplier > 9999) world->scoreMultiplier = 9999; + addPlayer(world); + + world->flags ^= gameworldstateflags_player_lost; + } + else if (platform_queryKey(&state->input.keys[keycode_backspace], + readkeytype_one_shot, 0.0f)) + { + common_memset((u8 *)world, 0, sizeof(*world)); + state->currState = appstate_StartMenuState; + return; } } @@ -780,11 +825,13 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt) renderflag_no_texture | renderflag_wireframe); } +#ifdef DENGINE_DEBUG if (platform_queryKey(&state->input.keys[keycode_left_square_bracket], readkeytype_repeat, 0.2f)) { addAsteroid(world, (rand() % asteroidsize_count)); } +#endif ASSERT(world->entityList[0].id == NULL_ENTITY_ID); for (i32 i = 1; i < world->entityIndex; i++) @@ -807,6 +854,17 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt) DEGREES_TO_RADIANS((entity->rotation + 90.0f)); v2 direction = V2(math_cosf(rotation), math_sinf(rotation)); ddP = direction; + + AudioVorbis *thrust = + asset_vorbisGet(&state->assetManager, "thrust"); + AudioRenderer *audioRenderer = + getFreeAudioRenderer(world, thrust, 3); + if (audioRenderer) + { + audio_vorbisPlay(&state->transientArena, + &state->audioManager, audioRenderer, + thrust, 1); + } } if (platform_queryKey(&state->input.keys[keycode_space], @@ -1003,6 +1061,14 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt) colliderB = collideEntity; } + // Assumptions made that the collision detect system relies on + ASSERT(entitytype_ship < entitytype_asteroid_small); + ASSERT(entitytype_asteroid_small < entitytype_asteroid_medium); + ASSERT(entitytype_asteroid_medium < entitytype_asteroid_large); + ASSERT(entitytype_asteroid_large < entitytype_bullet); + ASSERT(entitytype_asteroid_small + 1 == entitytype_asteroid_medium); + ASSERT(entitytype_asteroid_medium + 1 == entitytype_asteroid_large); + if (colliderA->type >= entitytype_asteroid_small && colliderA->type <= entitytype_asteroid_large) { @@ -1092,7 +1158,6 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt) ASSERT(colliderB->type == entitytype_bullet); deleteEntity(world, collisionIndex); - deleteEntity(world, i--); world->asteroidCounter--; @@ -1126,6 +1191,36 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt) continue; } + else if (colliderA->type == entitytype_ship) + { + if (colliderB->type >= entitytype_asteroid_small && + colliderB->type <= entitytype_asteroid_large) + { + world->flags |= gameworldstateflags_player_lost; + + if (collideEntity->type == entitytype_ship) + { + deleteEntity(world, collisionIndex); + } + else + { + deleteEntity(world, i--); + } + + AudioVorbis *explode = + asset_vorbisGet(&state->assetManager, "bang_large"); + AudioRenderer *audioRenderer = + getFreeAudioRenderer(world, explode, 3); + if (audioRenderer) + { + audio_vorbisPlay(&state->transientArena, + &state->audioManager, audioRenderer, + explode, 1); + } + + continue; + } + } } RenderFlags flags = renderflag_wireframe | renderflag_no_texture; @@ -1219,13 +1314,11 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt) menuState->newResolutionRequest = TRUE; v2 newSize = resolutionArray->ptr[menuState->resStringDisplayIndex]; - - GameWorldState *world = GET_STATE_DATA( - state, &state->persistentArena, GameWorldState); - renderer_updateSize(renderer, &state->assetManager, newSize); // TODO(doyle): reset world arena instead of zeroing out struct + GameWorldState *world = GET_STATE_DATA( + state, &state->persistentArena, GameWorldState); common_memset((u8 *)world, 0, sizeof(GameWorldState)); debug_init(newSize, *arial15); } @@ -1327,10 +1420,9 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt) GameWorldState *world = GET_STATE_DATA(state, &state->persistentArena, GameWorldState); - addPlayer(world); - state->currState = appstate_GameWorldState; world->flags |= gameworldstateflags_level_started; + addPlayer(world); } else if (platform_queryKey(&inputBuffer->keys[keycode_o], readkeytype_one_shot, KEY_DELAY_NONE)) diff --git a/src/Renderer.c b/src/Renderer.c index 3e37565..b7af94b 100644 --- a/src/Renderer.c +++ b/src/Renderer.c @@ -35,6 +35,10 @@ INTERNAL void shaderUse(u32 shaderId) { glUseProgram(shaderId); } void renderer_updateSize(Renderer *renderer, AssetManager *assetManager, v2 windowSize) { renderer->size = windowSize; + // renderer->displayScale = + // V2(windowSize.x * 1.0f / renderer->referenceScale.x, + // windowSize.y * 1.0f / renderer->referenceScale.y); + // NOTE(doyle): Value to map a screen coordinate to NDC coordinate renderer->vertexNdcFactor = V2(1.0f / renderer->size.w, 1.0f / renderer->size.h); @@ -48,7 +52,7 @@ void renderer_updateSize(Renderer *renderer, AssetManager *assetManager, v2 wind renderer->shaderList[i] = asset_shaderGet(assetManager, i); shaderUse(renderer->shaderList[i]); shaderUniformSetMat4fv(renderer->shaderList[i], "projection", - projection); + projection); GL_CHECK_ERROR(); } @@ -59,6 +63,7 @@ void renderer_updateSize(Renderer *renderer, AssetManager *assetManager, v2 wind void renderer_init(Renderer *renderer, AssetManager *assetManager, MemoryArena_ *persistentArena, v2 windowSize) { + renderer->referenceScale = V2(1280, 720); renderer_updateSize(renderer, assetManager, windowSize); /* Create buffers */ diff --git a/src/dengine.c b/src/dengine.c index a684433..33f3c6f 100644 --- a/src/dengine.c +++ b/src/dengine.c @@ -19,10 +19,12 @@ INTERNAL void keyCallback(GLFWwindow *window, int key, int scancode, int action, { GameState *game = CAST(GameState *)(glfwGetWindowUserPointer(window)); +#if 1 if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { glfwSetWindowShouldClose(window, GL_TRUE); } +#endif switch (key) { diff --git a/src/include/Dengine/AssetManager.h b/src/include/Dengine/AssetManager.h index 27cb366..3dacf44 100644 --- a/src/include/Dengine/AssetManager.h +++ b/src/include/Dengine/AssetManager.h @@ -26,11 +26,9 @@ typedef struct AssetManager void asset_init(AssetManager *assetManager, MemoryArena_ *arena); -/* - ********************************* - * Texture Operations - ********************************* - */ +//////////////////////////////////////////////////////////////////////////////// +// Texture Managing +//////////////////////////////////////////////////////////////////////////////// const SubTexture asset_atlasGetSubTex(TexAtlas *const atlas, const char *const key); Texture *asset_texGet(AssetManager *const assetManager, const char *const key); @@ -49,11 +47,9 @@ u8 *asset_imageLoad(i32 *width, i32 *height, i32 *bpp, const char *const path, void asset_imageFree(u8 *image); -/* - ********************************* - * Animation Asset Managing - ********************************* - */ +//////////////////////////////////////////////////////////////////////////////// +// Animation Asset Managing +//////////////////////////////////////////////////////////////////////////////// void asset_animAdd(AssetManager *const assetManager, MemoryArena_ *const arena, const char *const animName, TexAtlas *const atlas, char **const subTextureNames, const i32 numSubTextures, @@ -61,21 +57,17 @@ void asset_animAdd(AssetManager *const assetManager, MemoryArena_ *const arena, Animation *asset_animGet(AssetManager *const assetManager, const char *const key); -/* - ********************************* - * Audio - ********************************* - */ +//////////////////////////////////////////////////////////////////////////////// +// Audio +//////////////////////////////////////////////////////////////////////////////// AudioVorbis *const asset_vorbisGet(AssetManager *const assetManager, const char *const key); const i32 asset_vorbisLoad(AssetManager *assetManager, MemoryArena_ *arena, const char *const path, const char *const key); -/* - ********************************* - * Everything else - ********************************* - */ +//////////////////////////////////////////////////////////////////////////////// +// Everything else +//////////////////////////////////////////////////////////////////////////////// const i32 asset_xmlLoad(AssetManager *const assetManager, MemoryArena_ *const arena, const PlatformFileRead *const fileRead); diff --git a/src/include/Dengine/Asteroid.h b/src/include/Dengine/Asteroid.h index 00f923f..32ccf6f 100644 --- a/src/include/Dengine/Asteroid.h +++ b/src/include/Dengine/Asteroid.h @@ -19,8 +19,10 @@ enum AppState enum GameWorldStateFlags { - gameworldstateflags_init = (1 << 0), + gameworldstateflags_init = (1 << 0), gameworldstateflags_level_started = (1 << 1), + gameworldstateflags_player_lost = (1 << 2), + gameworldstateflags_create_player = (1 << 3), }; typedef struct GameWorldState diff --git a/src/include/Dengine/Renderer.h b/src/include/Dengine/Renderer.h index e585da7..bc55fdc 100644 --- a/src/include/Dengine/Renderer.h +++ b/src/include/Dengine/Renderer.h @@ -68,6 +68,7 @@ enum VertexBatchState { typedef struct Renderer { + // rendererf u32 shaderList[shaderlist_count]; u32 activeShaderId; @@ -81,6 +82,13 @@ typedef struct Renderer v2 vertexNdcFactor; v2 size; + // NOTE(doyle): Reference scale is the size chosen to have the best + // playability based on the sizes of the entity given to the system. Any + // other resoluions will be scaled through the renderer so that objects + // remain the same size in different resolutions. + f32 displayScale; + v2 referenceScale; + RenderGroup groups[128]; i32 groupsInUse; i32 groupCapacity;