From c33b37b0ea271d6f8321ee063b430173b4bbc3a8 Mon Sep 17 00:00:00 2001 From: Doyle Thai Date: Wed, 17 Aug 2016 20:37:56 +1000 Subject: [PATCH] Render battle damage on screen, draft implementation Crudely done to get an understanding of the kind of storage needed to store UI on screen that may have a limited life time. --- src/Common.c | 24 ++++ src/WorldTraveller.c | 206 +++++++++++++++++----------- src/include/Dengine/Common.h | 3 + src/include/Dengine/UserInterface.h | 22 ++- 4 files changed, 176 insertions(+), 79 deletions(-) diff --git a/src/Common.c b/src/Common.c index 13e4964..73b0728 100644 --- a/src/Common.c +++ b/src/Common.c @@ -21,6 +21,27 @@ i32 common_strcmp(const char *a, const char *b) return ((*a < *b) ? -1 : 1); } +char *common_memset(char *const ptr, const i32 value, const i32 numBytes) +{ + for (i32 i = 0; i < numBytes; i++) + ptr[i] = value; + + return ptr; +} + +INTERNAL void reverseString(char *const buf, const i32 bufSize) +{ + if (!buf || bufSize == 0 || bufSize == 1) return; + i32 mid = bufSize / 2; + + for (i32 i = 0; i < mid; i++) + { + char tmp = buf[i]; + buf[i] = buf[(bufSize-1) - i]; + buf[(bufSize-1) - i] = tmp; + } +} + void common_itoa(i32 value, char *buf, i32 bufSize) { if (!buf || bufSize == 0) return; @@ -40,4 +61,7 @@ void common_itoa(i32 value, char *buf, i32 bufSize) buf[charIndex++] = rem + '0'; val /= 10; } + + // NOTE(doyle): The actual string length may differ from the bufSize + reverseString(buf, common_strlen(buf)); } diff --git a/src/WorldTraveller.c b/src/WorldTraveller.c index 663cbdc..a8a837a 100644 --- a/src/WorldTraveller.c +++ b/src/WorldTraveller.c @@ -78,34 +78,17 @@ INTERNAL void rendererInit(GameState *state, v2 windowSize) glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); GL_CHECK_ERROR(); + +#ifdef DENGINE_DEBUG + DEBUG_LOG("Renderer initialised"); +#endif } -// TODO(doyle): Remove and implement own random generator! -#include -#include -void worldTraveller_gameInit(GameState *state, v2 windowSize) +INTERNAL void assetInit(GameState *state) { AssetManager *assetManager = &state->assetManager; MemoryArena *arena = &state->arena; - /* - ************************ - * INITIALISE GAME AUDIO - ************************ - */ - i32 result = audio_init(&state->audioManager); - if (result) - { -#ifdef DENGINE_DEBUG - ASSERT(INVALID_CODE_PATH); -#endif - } - - /* - ******************* - * INITIALISE ASSETS - ******************* - */ /* Create empty 1x1 4bpp black texture */ u32 bitmap = (0xFF << 24) | (0xFF << 16) | (0xFF << 8) | (0xFF << 0); Texture emptyTex = texture_gen(1, 1, 4, CAST(u8 *)(&bitmap)); @@ -144,7 +127,7 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize) "data/shaders/sprite.frag.glsl", shaderlist_sprite); - result = + i32 result = asset_loadTTFont(assetManager, arena, "C:/Windows/Fonts/Arialbd.ttf"); if (result) DEBUG_LOG("Font loading failed"); @@ -217,16 +200,12 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize) #ifdef DENGINE_DEBUG DEBUG_LOG("Sound assets initialised"); #endif +} - state->state = state_active; - state->currWorldIndex = 0; - state->tileSize = 64; - - /* Init renderer */ - rendererInit(state, windowSize); -#ifdef DENGINE_DEBUG - DEBUG_LOG("Renderer initialised"); -#endif +INTERNAL void entityInit(GameState *state, v2 windowSize) +{ + AssetManager *assetManager = &state->assetManager; + MemoryArena *arena = &state->arena; /* Init world */ const i32 targetWorldWidth = 100 * METERS_TO_PIXEL; @@ -235,8 +214,9 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize) v2 worldDimensionInTiles = V2i(targetWorldWidth / state->tileSize, targetWorldHeight / state->tileSize); #else - v2 worldDimensionInTiles = V2i(CAST(i32) (windowSize.w / state->tileSize) * 2, - CAST(i32) windowSize.h / state->tileSize); + v2 worldDimensionInTiles = + V2i(CAST(i32)(windowSize.w / state->tileSize) * 2, + CAST(i32) windowSize.h / state->tileSize); #endif for (i32 i = 0; i < ARRAY_COUNT(state->world); i++) @@ -338,11 +318,35 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize) pos = V2(renderer->size.w - (renderer->size.w / 3.0f), CAST(f32) state->tileSize); entity_addGenericMob(arena, assetManager, world, pos); + #ifdef DENGINE_DEBUG DEBUG_LOG("World populated"); #endif +} +// TODO(doyle): Remove and implement own random generator! +#include +#include +void worldTraveller_gameInit(GameState *state, v2 windowSize) +{ + i32 result = audio_init(&state->audioManager); + if (result) + { +#ifdef DENGINE_DEBUG + ASSERT(INVALID_CODE_PATH); +#endif + } + + state->state = state_active; + state->currWorldIndex = 0; + state->tileSize = 64; state->uiState.keyEntered = keycode_null; + state->uiState.keyMod = keycode_null; + state->uiState.keyChar = keycode_null; + + assetInit(state); + rendererInit(state, windowSize); + entityInit(state, windowSize); srand(CAST(u32)(time(NULL))); } @@ -985,6 +989,7 @@ INTERNAL void sortWorldEntityList(World *world, i32 numDeadEntities) listHasChanged = FALSE; for (i32 i = 0; i < numUnsortedEntities-1; i++) { + // TODO(doyle): Better sort algorithm Entity *entityA = &world->entities[i]; Entity *entityB = &world->entities[i+1]; if (entityA->type == entitytype_null || @@ -1002,6 +1007,20 @@ INTERNAL void sortWorldEntityList(World *world, i32 numDeadEntities) world->freeEntityIndex -= numDeadEntities; } +typedef struct DamageDisplay +{ + char damageStr[12]; + v2 pos; + f32 lifetime; +} DamageDisplay; + +typedef struct BattleState +{ + DamageDisplay damageDisplay[128]; +} BattleState; + +BattleState battleState = {0}; + void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) { if (dt >= 1.0f) dt = 1.0f; @@ -1172,53 +1191,79 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) Event event = eventQueue.queue[i]; switch(event.type) { - case eventtype_end_attack: + case eventtype_end_attack: + { + if (!event.data) continue; + + AttackSpec *attackSpec = (CAST(AttackSpec *) event.data); + Entity *attacker = attackSpec->attacker; + Entity *defender = attackSpec->defender; + + audio_playVorbis(arena, audioManager, attacker->audioRenderer, + asset_getVorbis(assetManager, audiolist_tackle), + 1); + + /* Get first free string position and store the damage str data */ + for (i32 i = 0; i < ARRAY_COUNT(battleState.damageDisplay); i++) { - if (!event.data) continue; + if (battleState.damageDisplay[i].lifetime <= 0.0f) + { + common_memset( + battleState.damageDisplay[i].damageStr, 0, + ARRAY_COUNT(battleState.damageDisplay[i].damageStr)); - AttackSpec *attackSpec = (CAST(AttackSpec *)event.data); - Entity *attacker = attackSpec->attacker; - Entity *defender = attackSpec->defender; + battleState.damageDisplay[i].lifetime = 1.0f; + battleState.damageDisplay[i].pos = defender->pos; + common_itoa( + attackSpec->damage, + battleState.damageDisplay[i].damageStr, + ARRAY_COUNT(battleState.damageDisplay[i].damageStr)); - audio_playVorbis( - arena, audioManager, attacker->audioRenderer, - asset_getVorbis(assetManager, audiolist_tackle), 1); - - char damageStr[12]; - common_itoa(attackSpec->damage, damageStr, - ARRAY_COUNT(damageStr)); - - // TODO(doyle): Incorporate UI into entity list or it's own list - // with a rendering lifetime value - renderer_string(renderer, &state->arena, - camera, font, - damageStr, defender->pos, V2(0, 0), - 0, V4(1, 1, 1, 1)); - - PLATFORM_MEM_FREE(&state->arena, attackSpec, - sizeof(AttackSpec)); - - break; - } - // NOTE(doyle): We delete dead entities at the end of the update - // loop incase a later indexed entity deletes an earlier indexed - // entity, the entity will exist for an additional frame - case eventtype_entity_died: - { - DEBUG_LOG("Entity died: being deleted"); - if (!event.data) continue; - - Entity *entity = (CAST(Entity *) event.data); - audio_stopVorbis(&state->arena, audioManager, - entity->audioRenderer); - entity_clearData(&state->arena, world, entity); - numDeadEntities++; - break; - } - default: - { - break; + break; + } } + + PLATFORM_MEM_FREE(&state->arena, attackSpec, sizeof(AttackSpec)); + break; + } + // NOTE(doyle): We delete dead entities at the end of the update + // loop incase a later indexed entity deletes an earlier indexed + // entity, the entity will exist for an additional frame + case eventtype_entity_died: + { + DEBUG_LOG("Entity died: being deleted"); + if (!event.data) continue; + + Entity *entity = (CAST(Entity *) event.data); + audio_stopVorbis(&state->arena, audioManager, + entity->audioRenderer); + entity_clearData(&state->arena, world, entity); + numDeadEntities++; + break; + } + default: + { + break; + } + } + } + + /* Render all damage strings */ + for (i32 i = 0; i < ARRAY_COUNT(battleState.damageDisplay); i++) + { + if (battleState.damageDisplay[i].lifetime > 0.0f) + { + battleState.damageDisplay[i].lifetime -= dt; + + char *damageString = battleState.damageDisplay[i].damageStr; + v2 damagePos = battleState.damageDisplay[i].pos; + f32 lifetime = battleState.damageDisplay[i].lifetime; + + // TODO(doyle): Incorporate UI into entity list or it's own list + // with a rendering lifetime value + renderer_string(renderer, &state->arena, camera, font, + damageString, damagePos, V2(0, 0), 0, + V4(1, 1, 1, lifetime)); } } @@ -1251,6 +1296,13 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) // INIT IMGUI state->uiState.hotItem = 0; +#if 0 + UiItem damageString = {0}; + damageString.id = 6; + damageString.rect = {V2(500, 500), V2(font->maxSize.w * 30, font->maxSize.h)}; + damageString.type = uitype_string; +#endif + /* Draw ui */ Rect buttonRectA = {V2(300, 500), V2(100, 50)}; userInterface_button(&state->uiState, assetManager, renderer, state->input, diff --git a/src/include/Dengine/Common.h b/src/include/Dengine/Common.h index d9807b9..90a2f15 100644 --- a/src/include/Dengine/Common.h +++ b/src/include/Dengine/Common.h @@ -30,6 +30,9 @@ typedef double f64; i32 common_strlen(const char *const string); i32 common_strcmp(const char *a, const char *b); +char *common_memset(char *const ptr, const i32 value, const i32 numBytes); + +// Max buffer size should be 11 for 32 bit integers void common_itoa(i32 value, char *buf, i32 bufSize); #endif diff --git a/src/include/Dengine/UserInterface.h b/src/include/Dengine/UserInterface.h index 4a66fac..3544cff 100644 --- a/src/include/Dengine/UserInterface.h +++ b/src/include/Dengine/UserInterface.h @@ -11,17 +11,35 @@ typedef struct Font Font; typedef struct MemoryArena MemoryArena; typedef struct Renderer Renderer; +enum UiType +{ + uitype_button, + uitype_scrollbar, + uitype_textfield, + uitype_string, + uitype_count, +}; + +typedef struct UiItem +{ + i32 id; + Rect rect; + enum UiType type; +} UiItem; + typedef struct UiState { + UiItem uiList[128]; + i32 numItems; + i32 hotItem; i32 activeItem; + i32 lastWidget; i32 kbdItem; enum KeyCode keyEntered; enum KeyCode keyMod; enum KeyCode keyChar; - - i32 lastWidget; } UiState; i32 userInterface_button(UiState *const uiState,