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.
This commit is contained in:
parent
e90b31de55
commit
c33b37b0ea
24
src/Common.c
24
src/Common.c
@ -21,6 +21,27 @@ i32 common_strcmp(const char *a, const char *b)
|
|||||||
return ((*a < *b) ? -1 : 1);
|
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)
|
void common_itoa(i32 value, char *buf, i32 bufSize)
|
||||||
{
|
{
|
||||||
if (!buf || bufSize == 0) return;
|
if (!buf || bufSize == 0) return;
|
||||||
@ -40,4 +61,7 @@ void common_itoa(i32 value, char *buf, i32 bufSize)
|
|||||||
buf[charIndex++] = rem + '0';
|
buf[charIndex++] = rem + '0';
|
||||||
val /= 10;
|
val /= 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE(doyle): The actual string length may differ from the bufSize
|
||||||
|
reverseString(buf, common_strlen(buf));
|
||||||
}
|
}
|
||||||
|
@ -78,34 +78,17 @@ INTERNAL void rendererInit(GameState *state, v2 windowSize)
|
|||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
GL_CHECK_ERROR();
|
GL_CHECK_ERROR();
|
||||||
|
|
||||||
|
#ifdef DENGINE_DEBUG
|
||||||
|
DEBUG_LOG("Renderer initialised");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(doyle): Remove and implement own random generator!
|
INTERNAL void assetInit(GameState *state)
|
||||||
#include <time.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
void worldTraveller_gameInit(GameState *state, v2 windowSize)
|
|
||||||
{
|
{
|
||||||
AssetManager *assetManager = &state->assetManager;
|
AssetManager *assetManager = &state->assetManager;
|
||||||
MemoryArena *arena = &state->arena;
|
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 */
|
/* Create empty 1x1 4bpp black texture */
|
||||||
u32 bitmap = (0xFF << 24) | (0xFF << 16) | (0xFF << 8) | (0xFF << 0);
|
u32 bitmap = (0xFF << 24) | (0xFF << 16) | (0xFF << 8) | (0xFF << 0);
|
||||||
Texture emptyTex = texture_gen(1, 1, 4, CAST(u8 *)(&bitmap));
|
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",
|
"data/shaders/sprite.frag.glsl",
|
||||||
shaderlist_sprite);
|
shaderlist_sprite);
|
||||||
|
|
||||||
result =
|
i32 result =
|
||||||
asset_loadTTFont(assetManager, arena, "C:/Windows/Fonts/Arialbd.ttf");
|
asset_loadTTFont(assetManager, arena, "C:/Windows/Fonts/Arialbd.ttf");
|
||||||
if (result) DEBUG_LOG("Font loading failed");
|
if (result) DEBUG_LOG("Font loading failed");
|
||||||
|
|
||||||
@ -217,16 +200,12 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize)
|
|||||||
#ifdef DENGINE_DEBUG
|
#ifdef DENGINE_DEBUG
|
||||||
DEBUG_LOG("Sound assets initialised");
|
DEBUG_LOG("Sound assets initialised");
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
state->state = state_active;
|
INTERNAL void entityInit(GameState *state, v2 windowSize)
|
||||||
state->currWorldIndex = 0;
|
{
|
||||||
state->tileSize = 64;
|
AssetManager *assetManager = &state->assetManager;
|
||||||
|
MemoryArena *arena = &state->arena;
|
||||||
/* Init renderer */
|
|
||||||
rendererInit(state, windowSize);
|
|
||||||
#ifdef DENGINE_DEBUG
|
|
||||||
DEBUG_LOG("Renderer initialised");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Init world */
|
/* Init world */
|
||||||
const i32 targetWorldWidth = 100 * METERS_TO_PIXEL;
|
const i32 targetWorldWidth = 100 * METERS_TO_PIXEL;
|
||||||
@ -235,8 +214,9 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize)
|
|||||||
v2 worldDimensionInTiles = V2i(targetWorldWidth / state->tileSize,
|
v2 worldDimensionInTiles = V2i(targetWorldWidth / state->tileSize,
|
||||||
targetWorldHeight / state->tileSize);
|
targetWorldHeight / state->tileSize);
|
||||||
#else
|
#else
|
||||||
v2 worldDimensionInTiles = V2i(CAST(i32) (windowSize.w / state->tileSize) * 2,
|
v2 worldDimensionInTiles =
|
||||||
CAST(i32) windowSize.h / state->tileSize);
|
V2i(CAST(i32)(windowSize.w / state->tileSize) * 2,
|
||||||
|
CAST(i32) windowSize.h / state->tileSize);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (i32 i = 0; i < ARRAY_COUNT(state->world); i++)
|
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),
|
pos = V2(renderer->size.w - (renderer->size.w / 3.0f),
|
||||||
CAST(f32) state->tileSize);
|
CAST(f32) state->tileSize);
|
||||||
entity_addGenericMob(arena, assetManager, world, pos);
|
entity_addGenericMob(arena, assetManager, world, pos);
|
||||||
|
|
||||||
#ifdef DENGINE_DEBUG
|
#ifdef DENGINE_DEBUG
|
||||||
DEBUG_LOG("World populated");
|
DEBUG_LOG("World populated");
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(doyle): Remove and implement own random generator!
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
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.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)));
|
srand(CAST(u32)(time(NULL)));
|
||||||
}
|
}
|
||||||
@ -985,6 +989,7 @@ INTERNAL void sortWorldEntityList(World *world, i32 numDeadEntities)
|
|||||||
listHasChanged = FALSE;
|
listHasChanged = FALSE;
|
||||||
for (i32 i = 0; i < numUnsortedEntities-1; i++)
|
for (i32 i = 0; i < numUnsortedEntities-1; i++)
|
||||||
{
|
{
|
||||||
|
// TODO(doyle): Better sort algorithm
|
||||||
Entity *entityA = &world->entities[i];
|
Entity *entityA = &world->entities[i];
|
||||||
Entity *entityB = &world->entities[i+1];
|
Entity *entityB = &world->entities[i+1];
|
||||||
if (entityA->type == entitytype_null ||
|
if (entityA->type == entitytype_null ||
|
||||||
@ -1002,6 +1007,20 @@ INTERNAL void sortWorldEntityList(World *world, i32 numDeadEntities)
|
|||||||
world->freeEntityIndex -= 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)
|
void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
|
||||||
{
|
{
|
||||||
if (dt >= 1.0f) dt = 1.0f;
|
if (dt >= 1.0f) dt = 1.0f;
|
||||||
@ -1172,53 +1191,79 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
|
|||||||
Event event = eventQueue.queue[i];
|
Event event = eventQueue.queue[i];
|
||||||
switch(event.type)
|
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);
|
battleState.damageDisplay[i].lifetime = 1.0f;
|
||||||
Entity *attacker = attackSpec->attacker;
|
battleState.damageDisplay[i].pos = defender->pos;
|
||||||
Entity *defender = attackSpec->defender;
|
common_itoa(
|
||||||
|
attackSpec->damage,
|
||||||
|
battleState.damageDisplay[i].damageStr,
|
||||||
|
ARRAY_COUNT(battleState.damageDisplay[i].damageStr));
|
||||||
|
|
||||||
audio_playVorbis(
|
break;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// INIT IMGUI
|
||||||
state->uiState.hotItem = 0;
|
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 */
|
/* Draw ui */
|
||||||
Rect buttonRectA = {V2(300, 500), V2(100, 50)};
|
Rect buttonRectA = {V2(300, 500), V2(100, 50)};
|
||||||
userInterface_button(&state->uiState, assetManager, renderer, state->input,
|
userInterface_button(&state->uiState, assetManager, renderer, state->input,
|
||||||
|
@ -30,6 +30,9 @@ typedef double f64;
|
|||||||
|
|
||||||
i32 common_strlen(const char *const string);
|
i32 common_strlen(const char *const string);
|
||||||
i32 common_strcmp(const char *a, const char *b);
|
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);
|
void common_itoa(i32 value, char *buf, i32 bufSize);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -11,17 +11,35 @@ typedef struct Font Font;
|
|||||||
typedef struct MemoryArena MemoryArena;
|
typedef struct MemoryArena MemoryArena;
|
||||||
typedef struct Renderer Renderer;
|
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
|
typedef struct UiState
|
||||||
{
|
{
|
||||||
|
UiItem uiList[128];
|
||||||
|
i32 numItems;
|
||||||
|
|
||||||
i32 hotItem;
|
i32 hotItem;
|
||||||
i32 activeItem;
|
i32 activeItem;
|
||||||
|
i32 lastWidget;
|
||||||
|
|
||||||
i32 kbdItem;
|
i32 kbdItem;
|
||||||
enum KeyCode keyEntered;
|
enum KeyCode keyEntered;
|
||||||
enum KeyCode keyMod;
|
enum KeyCode keyMod;
|
||||||
enum KeyCode keyChar;
|
enum KeyCode keyChar;
|
||||||
|
|
||||||
i32 lastWidget;
|
|
||||||
} UiState;
|
} UiState;
|
||||||
|
|
||||||
i32 userInterface_button(UiState *const uiState,
|
i32 userInterface_button(UiState *const uiState,
|
||||||
|
Loading…
Reference in New Issue
Block a user