diff --git a/Dengine.vcxproj b/Dengine.vcxproj
index 0b3c0cf..d471d3e 100644
--- a/Dengine.vcxproj
+++ b/Dengine.vcxproj
@@ -121,18 +121,17 @@
+
-
-
@@ -143,14 +142,15 @@
+
+
-
diff --git a/Dengine.vcxproj.filters b/Dengine.vcxproj.filters
index e50c137..e816c49 100644
--- a/Dengine.vcxproj.filters
+++ b/Dengine.vcxproj.filters
@@ -15,9 +15,6 @@
-
- Source Files
-
Source Files
@@ -42,9 +39,6 @@
Source Files
-
- Source Files
-
Source Files
@@ -57,6 +51,9 @@
Source Files
+
+ Source Files
+
@@ -86,9 +83,6 @@
Header Files
-
- Header Files
-
Header Files
@@ -116,5 +110,11 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
\ No newline at end of file
diff --git a/.clang-format b/src/.clang-format
similarity index 100%
rename from .clang-format
rename to src/.clang-format
diff --git a/src/Asteroid.c b/src/Asteroid.c
new file mode 100644
index 0000000..365cb50
--- /dev/null
+++ b/src/Asteroid.c
@@ -0,0 +1,241 @@
+#include "Dengine/Asteroid.h"
+#include "Dengine/Debug.h"
+
+void initAssetManager(GameState *state)
+{
+ AssetManager *assetManager = &state->assetManager;
+ MemoryArena_ *arena = &state->persistentArena;
+
+ i32 audioEntries = 32;
+ assetManager->audio.size = audioEntries;
+ assetManager->audio.entries =
+ memory_pushBytes(arena, audioEntries * sizeof(HashTableEntry));
+
+ i32 texAtlasEntries = 8;
+ assetManager->texAtlas.size = texAtlasEntries;
+ assetManager->texAtlas.entries =
+ memory_pushBytes(arena, texAtlasEntries * sizeof(HashTableEntry));
+
+ i32 texEntries = 32;
+ assetManager->textures.size = texEntries;
+ assetManager->textures.entries =
+ memory_pushBytes(arena, texEntries * sizeof(HashTableEntry));
+
+ i32 animEntries = 1024;
+ assetManager->anims.size = animEntries;
+ assetManager->anims.entries =
+ memory_pushBytes(arena, animEntries * sizeof(HashTableEntry));
+
+ /* Create empty 1x1 4bpp black texture */
+ u32 bitmap = (0xFF << 24) | (0xFF << 16) | (0xFF << 8) | (0xFF << 0);
+ Texture *tex = asset_getFreeTexSlot(assetManager, arena, "nullTex");
+ *tex = texture_gen(1, 1, 4, CAST(u8 *)(&bitmap));
+
+ /* Load shaders */
+ asset_loadShaderFiles(assetManager, arena, "data/shaders/sprite.vert.glsl",
+ "data/shaders/sprite.frag.glsl",
+ shaderlist_sprite);
+
+ i32 result =
+ asset_loadTTFont(assetManager, arena, "C:/Windows/Fonts/Arialbd.ttf");
+
+ if (result) {
+ ASSERT(TRUE);
+ }
+}
+
+void initRenderer(GameState *state, v2 windowSize) {
+ AssetManager *assetManager = &state->assetManager;
+ Renderer *renderer = &state->renderer;
+ renderer->size = windowSize;
+
+ // NOTE(doyle): Value to map a screen coordinate to NDC coordinate
+ renderer->vertexNdcFactor =
+ V2(1.0f / renderer->size.w, 1.0f / renderer->size.h);
+ renderer->shader = asset_getShader(assetManager, shaderlist_sprite);
+ shader_use(renderer->shader);
+
+ const mat4 projection =
+ mat4_ortho(0.0f, renderer->size.w, 0.0f, renderer->size.h, 0.0f, 1.0f);
+ shader_uniformSetMat4fv(renderer->shader, "projection", projection);
+ GL_CHECK_ERROR();
+
+ /* Create buffers */
+ glGenVertexArrays(1, &renderer->vao);
+ glGenBuffers(1, &renderer->vbo);
+ GL_CHECK_ERROR();
+
+ /* Bind buffers */
+ glBindBuffer(GL_ARRAY_BUFFER, renderer->vbo);
+ glBindVertexArray(renderer->vao);
+
+ /* Configure VAO */
+ u32 numVertexElements = 4;
+ u32 stride = sizeof(Vertex);
+ glVertexAttribPointer(0, numVertexElements, GL_FLOAT, GL_FALSE, stride,
+ (GLvoid *)0);
+ glEnableVertexAttribArray(0);
+
+ GL_CHECK_ERROR();
+
+ /* Unbind */
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ GL_CHECK_ERROR();
+
+ // TODO(doyle): Lazy allocate render group capacity
+ renderer->groupCapacity = 4096;
+ for (i32 i = 0; i < ARRAY_COUNT(renderer->groups); i++)
+ {
+ renderer->groups[i].vertexList = memory_pushBytes(
+ &state->persistentArena, renderer->groupCapacity * sizeof(Vertex));
+ }
+}
+
+enum ReadKeyType
+{
+ readkeytype_oneShot,
+ readkeytype_delayedRepeat,
+ readkeytype_repeat,
+ readkeytype_count,
+};
+
+#define KEY_DELAY_NONE 0.0f
+INTERNAL b32 getKeyStatus(KeyState *key, enum ReadKeyType readType,
+ f32 delayInterval, f32 dt)
+{
+
+ if (!key->endedDown) return FALSE;
+
+ switch(readType)
+ {
+ case readkeytype_oneShot:
+ {
+ if (key->newHalfTransitionCount > key->oldHalfTransitionCount)
+ return TRUE;
+ break;
+ }
+ case readkeytype_repeat:
+ case readkeytype_delayedRepeat:
+ {
+ if (key->newHalfTransitionCount > key->oldHalfTransitionCount)
+ {
+ if (readType == readkeytype_delayedRepeat)
+ {
+ // TODO(doyle): Let user set arbitrary delay after initial input
+ key->delayInterval = 2 * delayInterval;
+ }
+ else
+ {
+ key->delayInterval = delayInterval;
+ }
+ return TRUE;
+ }
+ else if (key->delayInterval <= 0.0f)
+ {
+ key->delayInterval = delayInterval;
+ return TRUE;
+ }
+ else
+ {
+ key->delayInterval -= dt;
+ }
+ break;
+ }
+ default:
+#ifdef DENGINE_DEBUG
+ DEBUG_LOG("getKeyStatus() error: Invalid ReadKeyType enum");
+ ASSERT(INVALID_CODE_PATH);
+#endif
+ break;
+ }
+
+ return FALSE;
+}
+
+
+void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
+ v2 windowSize, f32 dt)
+{
+ if (!state->init) {
+
+ memory_arenaInit(&state->persistentArena, memory->persistent,
+ memory->persistentSize);
+ memory_arenaInit(&state->transientArena, memory->transient,
+ memory->transientSize);
+
+ initAssetManager(state);
+ initRenderer(state, windowSize);
+
+ { // Init ship entity
+ Entity *ship = &state->entityList[state->entityIndex++];
+ ship->id = 0;
+ ship->pos = V2(100.0f, 100.0f);
+ ship->hitbox = V2(100.0f, 100.0f);
+ ship->size = V2(100.0f, 100.0f);
+ ship->scale = 1;
+ ship->type = entitytype_ship;
+ ship->direction = direction_null;
+ ship->tex = asset_getTex(&state->assetManager, "nullTex");
+ ship->collides = FALSE;
+ }
+
+ state->camera.pos = V2(0, 0);
+ state->camera.size = state->renderer.size;
+
+ state->init = TRUE;
+ }
+ {
+ KeyState *keys = state->input.keys;
+ for (enum KeyCode code = 0; code < keycode_count; code++)
+ {
+ KeyState *keyState = &keys[code];
+
+ u32 halfTransitionCount = keyState->newHalfTransitionCount -
+ keyState->oldHalfTransitionCount;
+
+ if (halfTransitionCount > 0)
+ {
+ b32 transitionCountIsOdd = ((halfTransitionCount & 1) == 1);
+
+ if (transitionCountIsOdd)
+ {
+ if (keyState->endedDown) keyState->endedDown = FALSE;
+ else keyState->endedDown = TRUE;
+ }
+
+ keyState->oldHalfTransitionCount =
+ keyState->newHalfTransitionCount;
+ }
+ }
+ }
+
+ for (i32 i = 0; i < state->entityIndex; i++)
+ {
+ Entity *entity = &state->entityList[i];
+ ASSERT(entity->type != entitytype_invalid);
+
+ if (entity->type == entitytype_ship) {
+
+ { // Parse input
+ if (getKeyStatus(&state->input.keys[keycode_up],
+ readkeytype_repeat, 0.0f, dt))
+ {
+ entity->pos.y += 10.0f;
+ }
+
+ if (getKeyStatus(&state->input.keys[keycode_down],
+ readkeytype_repeat, 0.0f, dt))
+ {
+ entity->pos.y -= 10.0f;
+ }
+ }
+
+ }
+
+ renderer_entity(&state->renderer, state->camera, entity, V2(0, 0), 0,
+ V4(1.0f, 1.0f, 1.0f, 1.0f));
+ }
+
+ renderer_renderGroups(&state->renderer);
+}
diff --git a/src/Debug.c b/src/Debug.c
index f1d8131..6294bec 100644
--- a/src/Debug.c
+++ b/src/Debug.c
@@ -1,10 +1,9 @@
#include "Dengine/Debug.h"
#include "Dengine/AssetManager.h"
-#include "Dengine/Entity.h"
#include "Dengine/MemoryArena.h"
#include "Dengine/Platform.h"
#include "Dengine/Renderer.h"
-#include "Dengine/WorldTraveller.h"
+#include "Dengine/Asteroid.h"
typedef struct DebugState
{
@@ -29,52 +28,6 @@ typedef struct DebugState
GLOBAL_VAR DebugState GLOBAL_debug;
-inline char *debug_entitystate_string(i32 val)
-{
- char *string;
- switch(val)
- {
- case entitystate_idle:
- string = "EntityState_Idle";
- break;
- case entitystate_battle:
- string = "EntityState_Battle";
- break;
- case entitystate_attack:
- string = "EntityState_Attack";
- break;
- case entitystate_dead:
- string = "EntityState_Dead";
- break;
- case entitystate_count:
- string = "EntityState_Count (Error!)";
- break;
- case entitystate_invalid:
- string = "EntityState_Invalid (Error!)";
- break;
- default:
- string = "EntityState Unknown (NOT DEFINED)";
- }
- return string;
-}
-
-inline char *debug_entityattack_string(i32 val)
-{
- char *string;
- switch(val)
- {
- case entityattack_count:
- string = "EntityAttack_Count (Error!)";
- break;
- case entityattack_invalid:
- string = "EntityAttack_Invalid";
- break;
- default:
- string = "EntityAttack Unknown (NOT DEFINED)";
- }
- return string;
-}
-
void debug_init(MemoryArena_ *arena, v2 windowSize, Font font)
{
GLOBAL_debug.font = font;
@@ -317,238 +270,5 @@ INTERNAL void renderConsole(Renderer *renderer, MemoryArena_ *arena)
void debug_drawUi(GameState *state, f32 dt)
{
- AssetManager *assetManager = &state->assetManager;
- Renderer *renderer = &state->renderer;
- World *const world = &state->world[state->currWorldIndex];
- Entity *hero = &world->entities[entity_getIndex(world, world->heroId)];
- MemoryArena_ *transientArena = &state->transientArena;
-
- // TODO(doyle): Dumb copy function from game so we don't expose api
- Rect camera = {world->cameraPos, renderer->size};
- // NOTE(doyle): Lock camera if it passes the bounds of the world
- if (camera.pos.x <= world->bounds.x)
- camera.pos.x = world->bounds.x;
-
- // TODO(doyle): Allow Y panning when we need it
- f32 cameraTopBoundInPixels = camera.pos.y + camera.size.h;
- if (cameraTopBoundInPixels >= world->bounds.w)
- camera.pos.y = (world->bounds.w - camera.size.h);
-
- f32 cameraRightBoundInPixels = camera.pos.x + camera.size.w;
- if (cameraRightBoundInPixels >= world->bounds.z)
- camera.pos.x = (world->bounds.z - camera.size.w);
-
- if (camera.pos.y <= world->bounds.y) camera.pos.y = world->bounds.y;
-
- Font *font = &GLOBAL_debug.font;
- if (world->numEntitiesInBattle > 0)
- {
- v4 color = V4(1.0f, 0, 0, 1);
- char *battleStr = "IN-BATTLE RANGE";
- f32 strLenInPixels =
- CAST(f32)(font->maxSize.w * common_strlen(battleStr));
- v2 strPos = V2((renderer->size.w * 0.5f) - (strLenInPixels * 0.5f),
- renderer->size.h - 300.0f);
- renderer_staticString(&state->renderer, transientArena, font, battleStr,
- strPos, V2(0, 0), 0, color);
- }
-
- for (i32 i = 0; i < world->freeEntityIndex; i++)
- {
- Entity *const entity = &world->entities[i];
- if (entity->state == entitystate_dead) continue;
-
- /* Render debug markers on entities */
- v4 color = V4(1, 1, 1, 1);
- char *debugString = NULL;
- switch (entity->type)
- {
- case entitytype_mob:
- color = V4(1, 0, 0, 1);
- debugString = "MOB";
- break;
-
- case entitytype_hero:
- color = V4(0, 0, 1.0f, 1);
- debugString = "HERO";
- break;
-
- case entitytype_npc:
- color = V4(0, 1.0f, 0, 1);
- debugString = "NPC";
- break;
-
- default:
- break;
- }
-
- if (debugString)
- {
- v2 strPos = v2_add(entity->pos, entity->hitbox);
- i32 indexOfLowerAInMetrics = 'a' - CAST(i32) font->codepointRange.x;
- strPos.y += font->charMetrics[indexOfLowerAInMetrics].offset.y;
-
- renderer_string(&state->renderer, transientArena, camera, font,
- debugString, strPos, V2(0, 0), 0, color);
-
- f32 stringLineGap = 1.1f * font->verticalSpacing;
- strPos.y -= GLOBAL_debug.stringLineGap;
-
- char entityPosStr[128];
- snprintf(entityPosStr, ARRAY_COUNT(entityPosStr), "%06.2f, %06.2f",
- entity->pos.x, entity->pos.y);
- renderer_string(&state->renderer, transientArena, camera, font,
- entityPosStr, strPos, V2(0, 0), 0, color);
-
- strPos.y -= GLOBAL_debug.stringLineGap;
- char entityIDStr[32];
- snprintf(entityIDStr, ARRAY_COUNT(entityIDStr), "ID: %4d/%d", entity->id,
- world->uniqueIdAccumulator-1);
- renderer_string(&state->renderer, transientArena, camera, font,
- entityIDStr, strPos, V2(0, 0), 0, color);
-
- if (entity->stats)
- {
- strPos.y -= GLOBAL_debug.stringLineGap;
- char entityHealth[32];
- snprintf(entityHealth, ARRAY_COUNT(entityHealth), "HP: %3.0f/%3.0f",
- entity->stats->health, entity->stats->maxHealth);
- renderer_string(&state->renderer, transientArena, camera,
- font, entityHealth, strPos, V2(0, 0), 0, color);
-
- strPos.y -= GLOBAL_debug.stringLineGap;
- char entityTimer[32];
- snprintf(entityTimer, ARRAY_COUNT(entityTimer), "ATB: %3.0f/%3.0f",
- entity->stats->actionTimer, entity->stats->actionRate);
- renderer_string(&state->renderer, transientArena, camera,
- font, entityTimer, strPos, V2(0, 0), 0, color);
-
- strPos.y -= GLOBAL_debug.stringLineGap;
- char entityIdTarget[32];
- snprintf(entityIdTarget, ARRAY_COUNT(entityIdTarget),
- "Targetting ID: %d", entity->stats->entityIdToAttack);
- renderer_string(&state->renderer, transientArena, camera,
- font, entityIdTarget, strPos, V2(0, 0), 0, color);
- }
-
- strPos.y -= GLOBAL_debug.stringLineGap;
- char *entityStateStr = debug_entitystate_string(entity->state);
- renderer_string(&state->renderer, transientArena, camera, font,
- entityStateStr, strPos, V2(0, 0), 0, color);
-
- if (entity->audioRenderer)
- {
- strPos.y -= GLOBAL_debug.stringLineGap;
- char entityAudioSourceIndex[32];
- snprintf(entityAudioSourceIndex,
- ARRAY_COUNT(entityAudioSourceIndex),
- "AudioSource Index: %d",
- entity->audioRenderer->sourceIndex);
- renderer_string(&state->renderer, transientArena, camera,
- font, entityAudioSourceIndex, strPos, V2(0, 0),
- 0, color);
- }
- }
- }
-
- /* Render debug info stack */
- DEBUG_PUSH_STRING("== Controls ==");
- DEBUG_PUSH_STRING(" [: Spawn a mob");
- DEBUG_PUSH_STRING(": Switch UI element");
- DEBUG_PUSH_STRING(": Close program");
- DEBUG_PUSH_STRING("");
-
- DEBUG_PUSH_STRING("== Config == ");
- DEBUG_PUSH_VAR("Toggle World Audio: %d", state->config.playWorldAudio,
- "i32");
- DEBUG_PUSH_VAR("Toggle Debug Display: %d", state->config.showDebugDisplay,
- "i32");
- DEBUG_PUSH_STRING("");
-
- DEBUG_PUSH_STRING("== Hero Properties == ");
- DEBUG_PUSH_VAR("Hero Pos: %06.2f, %06.2f", hero->pos, "v2");
- DEBUG_PUSH_VAR("Hero dPos: %06.2f, %06.2f", hero->dPos, "v2");
- DEBUG_PUSH_VAR("Hero Busy Duration: %05.3f", hero->stats->busyDuration, "f32");
- char *heroStateString = debug_entitystate_string(hero->state);
- DEBUG_PUSH_VAR("Hero State: %s", *heroStateString, "char");
- char *heroQueuedAttackStr =
- debug_entityattack_string(hero->stats->queuedAttack);
- DEBUG_PUSH_VAR("Hero QueuedAttack: %s", *heroQueuedAttackStr, "char");
- DEBUG_PUSH_STRING("");
-
- DEBUG_PUSH_STRING("== State Properties == ");
- DEBUG_PUSH_VAR("FreeEntityIndex: %d", world->freeEntityIndex, "i32");
- DEBUG_PUSH_VAR("GLDrawArray Calls: %d",
- GLOBAL_debug.callCount[debugcount_drawArrays], "i32");
- DEBUG_PUSH_VAR("PlatformMemAlloc Calls: %d",
- GLOBAL_debug.callCount[debugcount_platformMemAlloc], "i32");
- DEBUG_PUSH_VAR("PlatformMemFree Calls: %d",
- GLOBAL_debug.callCount[debugcount_platformMemFree], "i32");
-
- i32 vertexesUsed = GLOBAL_debug.callCount[debugcount_numVertex];
- i32 vertexesAvail =
- (ARRAY_COUNT(state->renderer.groups) * state->renderer.groupCapacity);
- i32 vertexesLeft = vertexesAvail - vertexesUsed;
- v2 vertexData = V2i(vertexesUsed, vertexesAvail);
- DEBUG_PUSH_VAR("Vertexes Rendered: %1.0f/%1.0f", vertexData, "v2");
- DEBUG_PUSH_VAR("Vertexes Left: %d", vertexesLeft, "i32");
-
- i32 groupsUsed = GLOBAL_debug.callCount[debugcount_renderGroups];
- i32 groupsAvail = ARRAY_COUNT(state->renderer.groups);
- v2 groupData = V2i(groupsUsed, groupsAvail);
- DEBUG_PUSH_VAR("Render Groups Used: %1.0f/%1.0f", groupData, "v2");
-
- DEBUG_PUSH_VAR("Mouse Pos: %06.2f, %06.2f", state->input.mouseP, "v2");
-
- /*
- *****************
- * MEMORY DISPLAY
- *****************
- */
- i32 debug_bAllocated = transientArena->used;
- i32 debug_kbAllocated = debug_bAllocated / 1024;
- i32 debug_mbAllocated = debug_kbAllocated / 1024;
- DEBUG_PUSH_VAR("TransientArena Used: %db", debug_bAllocated, "i32");
- DEBUG_PUSH_VAR("TransientArena Used: %dkb", debug_kbAllocated, "i32");
- DEBUG_PUSH_VAR("TransientArena Used: %dmb", debug_mbAllocated, "i32");
- DEBUG_PUSH_STRING("");
-
- debug_bAllocated = state->arena_.used;
- debug_kbAllocated = debug_bAllocated / 1024;
- debug_mbAllocated = debug_kbAllocated / 1024;
- DEBUG_PUSH_VAR("PersistentArena Used: %db", debug_bAllocated, "i32");
- DEBUG_PUSH_VAR("PersistentArena Used: %dkb", debug_kbAllocated, "i32");
- DEBUG_PUSH_VAR("PersistentArena Used: %dmb", debug_mbAllocated, "i32");
- DEBUG_PUSH_STRING("");
-
- AudioManager *audioManager = &state->audioManager;
- DEBUG_PUSH_STRING("== Audio System ==");
- for (i32 i = 0; i < ARRAY_COUNT(audioManager->sourceList); i++)
- {
- if (audioManager->sourceList[i].isFree) continue;
- v3 tmp = V3i(i, audioManager->sourceList[i].id,
- audioManager->sourceList[i].isFree);
- DEBUG_PUSH_VAR("Source ID[%02.0f].id[%02.0f].isFree: %1.0f", tmp, "v3");
- }
- DEBUG_PUSH_STRING("");
-
- DEBUG_PUSH_STRING("== EntityIDs in Battle List == ");
- DEBUG_PUSH_VAR("NumEntitiesInBattle: %d", world->numEntitiesInBattle,
- "i32");
- if (world->numEntitiesInBattle > 0)
- {
- for (i32 i = 0; i < world->maxEntities; i++)
- {
- if (world->entityIdInBattle[i])
- DEBUG_PUSH_VAR("Entity ID: %d", i, "i32");
- }
- }
- else
- {
- DEBUG_PUSH_STRING("-none-");
- }
-
- updateAndRenderDebugStack(&state->renderer, transientArena, dt);
- renderConsole(&state->renderer, transientArena);
debug_clearCounter();
}
diff --git a/src/Entity.c b/src/Entity.c
index ea9deeb..1803841 100644
--- a/src/Entity.c
+++ b/src/Entity.c
@@ -1,12 +1,10 @@
#include "Dengine/Entity.h"
#include "Dengine/AssetManager.h"
#include "Dengine/Debug.h"
-#include "Dengine/MemoryArena.h"
-#include "Dengine/WorldTraveller.h"
SubTexture entity_getActiveSubTexture(Entity *const entity)
{
- EntityAnim *entityAnim = &entity->animList[entity->currAnimId];
+ EntityAnim *entityAnim = &entity->animList[entity->animListIndex];
Animation *anim = entityAnim->anim;
char *frameName = anim->frameList[entityAnim->currFrame];
@@ -14,11 +12,10 @@ SubTexture entity_getActiveSubTexture(Entity *const entity)
return result;
}
-void entity_setActiveAnim(EventQueue *eventQueue, Entity *const entity,
- const char *const animName)
+void entity_setActiveAnim(Entity *const entity, const char *const animName)
{
/* Reset current anim data */
- EntityAnim *currEntityAnim = &entity->animList[entity->currAnimId];
+ EntityAnim *currEntityAnim = &entity->animList[entity->animListIndex];
currEntityAnim->currDuration = currEntityAnim->anim->frameDuration;
currEntityAnim->currFrame = 0;
currEntityAnim->timesCompleted = 0;
@@ -32,14 +29,11 @@ void entity_setActiveAnim(EventQueue *eventQueue, Entity *const entity,
// TODO(doyle): Linear search, but not a problem if list is small
if (common_strcmp(anim->key, animName) == 0)
{
- entity->currAnimId = i;
+ entity->animListIndex = i;
EntityAnim *newEntityAnim = &entity->animList[i];
newEntityAnim->currDuration =
newEntityAnim->anim->frameDuration;
newEntityAnim->currFrame = 0;
-
- worldTraveller_registerEvent(eventQueue, eventtype_start_anim,
- newEntityAnim);
return;
}
}
@@ -48,13 +42,12 @@ void entity_setActiveAnim(EventQueue *eventQueue, Entity *const entity,
DEBUG_LOG("Entity does not have access to desired anim");
}
-void entity_updateAnim(EventQueue *eventQueue, Entity *const entity,
- const f32 dt)
+void entity_updateAnim(Entity *const entity, const f32 dt)
{
if (!entity->tex)
return;
- EntityAnim *currEntityAnim = &entity->animList[entity->currAnimId];
+ EntityAnim *currEntityAnim = &entity->animList[entity->animListIndex];
Animation *anim = currEntityAnim->anim;
currEntityAnim->currDuration -= dt;
@@ -64,30 +57,15 @@ void entity_updateAnim(EventQueue *eventQueue, Entity *const entity,
currEntityAnim->currFrame = currEntityAnim->currFrame % anim->numFrames;
if (currEntityAnim->currFrame == 0)
{
- worldTraveller_registerEvent(eventQueue, eventtype_end_anim,
- currEntityAnim);
currEntityAnim->timesCompleted++;
}
currEntityAnim->currDuration = anim->frameDuration;
}
- // NOTE(doyle): If humanoid entity, let animation dictate render size which
- // may exceed the hitbox size of the entity
- switch (entity->type)
- {
- case entitytype_hero:
- case entitytype_mob:
- case entitytype_npc:
- case entitytype_weapon:
- case entitytype_projectile:
- char *frameName = anim->frameList[currEntityAnim->currFrame];
- SubTexture texRect =
- asset_getAtlasSubTex(anim->atlas, frameName);
- entity->size = v2_scale(texRect.rect.size, entity->scale);
- default:
- break;
- }
+ char *frameName = anim->frameList[currEntityAnim->currFrame];
+ SubTexture texRect = asset_getAtlasSubTex(anim->atlas, frameName);
+ entity->size = v2_scale(texRect.rect.size, entity->scale);
}
void entity_addAnim(AssetManager *const assetManager, Entity *const entity,
@@ -108,127 +86,3 @@ void entity_addAnim(AssetManager *const assetManager, Entity *const entity,
DEBUG_LOG("No more free entity animation slots");
}
-
-Entity *const entity_add(MemoryArena_ *const arena, World *const world,
- const v2 pos, const v2 size, const f32 scale,
- const enum EntityType type,
- const enum Direction direction, Texture *const tex,
- const b32 collides)
-{
-
-#ifdef DENGINE_DEBUG
- ASSERT(world);
- ASSERT(world->freeEntityIndex < world->maxEntities);
- ASSERT(type < entitytype_count);
-#endif
-
- Entity entity = {0};
- entity.id = world->uniqueIdAccumulator++;
- entity.pos = pos;
- entity.size = size;
- entity.hitbox = size;
- entity.scale = scale;
- entity.type = type;
- entity.direction = direction;
- entity.tex = tex;
- entity.collides = collides;
-
- switch (type)
- {
- case entitytype_hero:
- entity.stats = MEMORY_PUSH_STRUCT(arena, EntityStats);
- entity.stats->maxHealth = 100;
- entity.stats->health = entity.stats->maxHealth;
- entity.stats->actionRate = 100;
- entity.stats->actionTimer = entity.stats->actionRate;
- entity.stats->actionSpdMul = 100;
- entity.stats->entityIdToAttack = -1;
- entity.stats->queuedAttack = entityattack_invalid;
- entity.state = entitystate_idle;
- entity.collidesWith[entitytype_mob] = TRUE;
- break;
- case entitytype_mob:
- {
- entity.stats = MEMORY_PUSH_STRUCT(arena, EntityStats);
- entity.stats->maxHealth = 100;
- entity.stats->health = entity.stats->maxHealth;
- entity.stats->actionRate = 80;
- entity.stats->actionTimer = entity.stats->actionRate;
- entity.stats->actionSpdMul = 100;
- entity.stats->entityIdToAttack = -1;
- entity.stats->queuedAttack = entityattack_invalid;
- entity.state = entitystate_idle;
- entity.collidesWith[entitytype_hero] = TRUE;
- break;
- }
- case entitytype_projectile:
- case entitytype_attackObject:
- entity.stats = MEMORY_PUSH_STRUCT(arena, EntityStats);
- entity.stats->maxHealth = 100;
- entity.stats->health = entity.stats->maxHealth;
- entity.stats->actionRate = 100;
- entity.stats->actionTimer = entity.stats->actionRate;
- entity.stats->actionSpdMul = 100;
- entity.stats->entityIdToAttack = -1;
- entity.stats->queuedAttack = entityattack_invalid;
- entity.state = entitystate_idle;
- break;
-
- default:
- break;
- }
-
- world->entities[world->freeEntityIndex++] = entity;
- Entity *result = &world->entities[world->freeEntityIndex - 1];
-
- return result;
-}
-
-void entity_clearData(MemoryArena_ *const arena, World *const world,
- Entity *const entity)
-{
- // TODO(doyle): Mem free// memory leak!!
-
- /*
- if (entity->stats)
- PLATFORM_MEM_FREE(arena, entity->stats, sizeof(EntityStats));
-
- if (entity->audioRenderer)
- PLATFORM_MEM_FREE(arena, entity->audioRenderer,
- sizeof(AudioRenderer) * entity->numAudioRenderers);
- */
-
- entity->type = entitytype_null;
-}
-
-i32 entity_getIndex(World *const world, const i32 entityId)
-{
- i32 first = 0;
- i32 last = world->freeEntityIndex - 1;
-
- while (first <= last)
- {
- i32 middle = (first + last) / 2;
-
- if (world->entities[middle].id > entityId)
- last = middle - 1;
- else if (world->entities[middle].id < entityId)
- first = middle + 1;
- else
- return middle;
- }
-
-#ifdef DENGINE_DEBUG
- ASSERT(INVALID_CODE_PATH);
-#endif
- return -1;
-}
-
-Entity *entity_get(World *const world, const i32 entityId)
-{
- Entity *result = NULL;
- i32 worldIndex = entity_getIndex(world, entityId);
- if (worldIndex != -1) result = &world->entities[worldIndex];
-
- return result;
-}
diff --git a/src/Platform.c b/src/Platform.c
index 26d7e26..c874b78 100644
--- a/src/Platform.c
+++ b/src/Platform.c
@@ -6,7 +6,7 @@
#include "Dengine/Debug.h"
#include "Dengine/MemoryArena.h"
-void platform_memoryFree(MemoryArena_ *arena, void *data, i32 numBytes)
+void platform_memoryFree(MemoryArena_ *arena, void *data, size_t numBytes)
{
if (data) free(data);
@@ -16,7 +16,7 @@ void platform_memoryFree(MemoryArena_ *arena, void *data, i32 numBytes)
#endif
}
-void *platform_memoryAlloc(MemoryArena_ *arena, i32 numBytes)
+void *platform_memoryAlloc(MemoryArena_ *arena, size_t numBytes)
{
void *result = calloc(1, numBytes);
diff --git a/src/Renderer.c b/src/Renderer.c
index 90abc50..df39a4e 100644
--- a/src/Renderer.c
+++ b/src/Renderer.c
@@ -381,23 +381,31 @@ void renderer_entity(Renderer *renderer, Rect camera, Entity *entity,
if (math_pointInRect(camera, leftAlignedP) ||
math_pointInRect(camera, rightAlignedP))
{
- EntityAnim *entityAnim = &entity->animList[entity->currAnimId];
- Animation *anim = entityAnim->anim;
- char *frameName = anim->frameList[entityAnim->currFrame];
- SubTexture animRect = asset_getAtlasSubTex(anim->atlas, frameName);
+ EntityAnim *entityAnim = &entity->animList[entity->animListIndex];
- v4 animTexRect = {0};
- animTexRect.vec2[0] = animRect.rect.pos;
- animTexRect.vec2[1] = v2_add(animRect.rect.pos, animRect.rect.size);
+ v4 texRect = {0};
+ if (entityAnim->anim)
+ {
+ Animation *anim = entityAnim->anim;
+ char *frameName = anim->frameList[entityAnim->currFrame];
+ SubTexture subTex = asset_getAtlasSubTex(anim->atlas, frameName);
- flipTexCoord(&animTexRect, entity->flipX, entity->flipY);
+ texRect.vec2[0] = subTex.rect.pos;
+ texRect.vec2[1] = v2_add(subTex.rect.pos, subTex.rect.size);
+ flipTexCoord(&texRect, entity->flipX, entity->flipY);
+ }
+ else
+ {
+ texRect = V4(0.0f, 0.0f, (f32)entity->tex->width,
+ (f32)entity->tex->height);
+ }
if (entity->direction == direction_east)
{
- flipTexCoord(&animTexRect, TRUE, FALSE);
+ flipTexCoord(&texRect, TRUE, FALSE);
}
- RenderTex renderTex = {entity->tex, animTexRect};
+ RenderTex renderTex = {entity->tex, texRect};
renderer_rect(renderer, camera, entity->pos, entity->size, pivotPoint,
entity->rotation + rotate, renderTex, color);
}
diff --git a/src/WorldTraveller.c b/src/WorldTraveller.c
deleted file mode 100644
index 7b80b0e..0000000
--- a/src/WorldTraveller.c
+++ /dev/null
@@ -1,2477 +0,0 @@
-#include "Dengine/WorldTraveller.h"
-#include "Dengine/Audio.h"
-#include "Dengine/Debug.h"
-#include "Dengine/Entity.h"
-#include "Dengine/Platform.h"
-#include "Dengine/String.h"
-#include "Dengine/UserInterface.h"
-
-enum State
-{
- state_active,
- state_menu,
- state_win,
-};
-
-INTERNAL Entity *getHeroEntity(World *world)
-{
- Entity *result = &world->entities[entity_getIndex(world, world->heroId)];
- return result;
-}
-
-INTERNAL void addGenericMob(EventQueue *eventQueue, MemoryArena_ *arena,
- AssetManager *assetManager, World *world, v2 pos)
-{
-#ifdef DENGINE_DEBUG
- DEBUG_LOG("Mob entity spawned");
-#endif
-
- Entity *hero = &world->entities[entity_getIndex(world, world->heroId)];
-
- v2 size = V2(58.0f, 98.0f);
- f32 scale = 2;
- enum EntityType type = entitytype_mob;
- enum Direction dir = direction_west;
- Texture *tex = asset_getTex(assetManager, "ClaudeSprite.png");
- b32 collides = TRUE;
- Entity *mob =
- entity_add(arena, world, pos, size, scale, type, dir, tex, collides);
-
- mob->numAudioRenderers = 4;
- mob->audioRenderer =
- memory_pushBytes(arena, mob->numAudioRenderers * sizeof(AudioRenderer));
-
- for (i32 i = 0; i < mob->numAudioRenderers; i++)
- mob->audioRenderer[i].sourceIndex = AUDIO_SOURCE_UNASSIGNED;
-
- /* Populate mob animation references */
- entity_addAnim(assetManager, mob, "claudeIdle");
- entity_addAnim(assetManager, mob, "claudeRun");
- entity_addAnim(assetManager, mob, "claudeBattleIdle");
-
- entity_addAnim(assetManager, mob, "claudeAttack");
- entity_addAnim(assetManager, mob, "claudeAttackUp");
- entity_addAnim(assetManager, mob, "claudeAttackDown");
-
- entity_addAnim(assetManager, mob, "claudeAirSlash");
- entity_addAnim(assetManager, mob, "claudeDragonHowl");
- entity_addAnim(assetManager, mob, "claudeEnergySword");
- entity_addAnim(assetManager, mob, "claudeRipperBlast");
-
- entity_setActiveAnim(eventQueue, mob, "claudeIdle");
-}
-
-INTERNAL void rendererInit(GameState *state, v2 windowSize)
-{
- AssetManager *assetManager = &state->assetManager;
- Renderer *renderer = &state->renderer;
- renderer->size = windowSize;
- // NOTE(doyle): Value to map a screen coordinate to NDC coordinate
- renderer->vertexNdcFactor =
- V2(1.0f / renderer->size.w, 1.0f / renderer->size.h);
- renderer->shader = asset_getShader(assetManager, shaderlist_sprite);
- shader_use(renderer->shader);
-
- const mat4 projection =
- mat4_ortho(0.0f, renderer->size.w, 0.0f, renderer->size.h, 0.0f, 1.0f);
- shader_uniformSetMat4fv(renderer->shader, "projection", projection);
- GL_CHECK_ERROR();
-
- /* Create buffers */
- glGenVertexArrays(1, &renderer->vao);
- glGenBuffers(1, &renderer->vbo);
- GL_CHECK_ERROR();
-
- /* Bind buffers */
- glBindBuffer(GL_ARRAY_BUFFER, renderer->vbo);
- glBindVertexArray(renderer->vao);
-
- /* Configure VAO */
- u32 numVertexElements = 4;
- u32 stride = sizeof(Vertex);
- glVertexAttribPointer(0, numVertexElements, GL_FLOAT, GL_FALSE,
- stride, (GLvoid *)0);
- glEnableVertexAttribArray(0);
-
- GL_CHECK_ERROR();
-
- /* Unbind */
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindVertexArray(0);
- GL_CHECK_ERROR();
-
- // TODO(doyle): Lazy allocate render group capacity
- renderer->groupCapacity = 4096;
- for (i32 i = 0; i < ARRAY_COUNT(renderer->groups); i++)
- {
- renderer->groups[i].vertexList = memory_pushBytes(
- &state->arena_, renderer->groupCapacity * sizeof(Vertex));
- }
-
-#ifdef DENGINE_DEBUG
- DEBUG_LOG("Renderer initialised");
-#endif
-}
-
-INTERNAL void assetInit(GameState *state)
-{
- AssetManager *assetManager = &state->assetManager;
- MemoryArena_ *arena = &state->arena_;
-
- i32 audioEntries = 32;
- assetManager->audio.size = audioEntries;
- assetManager->audio.entries =
- memory_pushBytes(arena, audioEntries * sizeof(HashTableEntry));
-
- i32 texAtlasEntries = 8;
- assetManager->texAtlas.size = texAtlasEntries;
- assetManager->texAtlas.entries =
- memory_pushBytes(arena, texAtlasEntries * sizeof(HashTableEntry));
-
- i32 texEntries = 32;
- assetManager->textures.size = texEntries;
- assetManager->textures.entries =
- memory_pushBytes(arena, texEntries * sizeof(HashTableEntry));
-
- i32 animEntries = 1024;
- assetManager->anims.size = animEntries;
- assetManager->anims.entries =
- memory_pushBytes(arena, animEntries * sizeof(HashTableEntry));
-
- /* Create empty 1x1 4bpp black texture */
- u32 bitmap = (0xFF << 24) | (0xFF << 16) | (0xFF << 8) | (0xFF << 0);
- Texture *tex = asset_getFreeTexSlot(assetManager, arena, "nullTex");
- *tex = texture_gen(1, 1, 4, CAST(u8 *)(&bitmap));
-
- /*
- *********************************
- * Load terrain texture atlas data
- *********************************
- */
- PlatformFileRead terrainXml = {0};
- i32 result = platform_readFileToBuffer(
- arena, "data/textures/WorldTraveller/terrain.xml", &terrainXml);
- if (result)
- {
- DEBUG_LOG("Failed to read sprite sheet xml");
- }
- else
- {
- result = asset_loadXmlFile(assetManager, arena, &terrainXml);
-
- if (!result)
- {
- TexAtlas *terrainAtlas =
- asset_getTexAtlas(assetManager, "terrain.png");
-
- i32 numSubTextures = 1;
- f32 duration = 1.0f;
- char *grassTerrain[1] = {"grass.png"};
- asset_addAnimation(assetManager, arena, "terrainGrass",
- terrainAtlas, grassTerrain, numSubTextures,
- duration);
- }
- else
- {
-#ifdef DENGINE_DEBUG
- DEBUG_LOG("Failed to load terrain sprite xml data");
-#endif
- }
-
- platform_closeFileRead(arena, &terrainXml);
- }
-
- /*
- *********************************
- * Load Claude texture atlas data
- *********************************
- */
- PlatformFileRead claudeXml = {0};
- result = platform_readFileToBuffer(
- arena, "data/textures/WorldTraveller/ClaudeSprite.xml", &claudeXml);
-
- if (result)
- {
- DEBUG_LOG("Failed to read sprite sheet xml");
- }
- else
- {
- result = asset_loadXmlFile(assetManager, arena, &claudeXml);
-
- if (!result)
- {
- TexAtlas *claudeAtlas =
- asset_getTexAtlas(assetManager, "ClaudeSprite.png");
-
- char *claudeIdle[1] = {"ClaudeSprite_Walk_Left_01"};
- f32 duration = 1.0f;
- i32 numRects = ARRAY_COUNT(claudeIdle);
- asset_addAnimation(assetManager, arena, "claudeIdle", claudeAtlas,
- claudeIdle, numRects, duration);
-
- // Run animation
- char *claudeRun[6] = {
- "ClaudeSprite_Run_Left_01", "ClaudeSprite_Run_Left_02",
- "ClaudeSprite_Run_Left_03", "ClaudeSprite_Run_Left_04",
- "ClaudeSprite_Run_Left_05", "ClaudeSprite_Run_Left_06"};
- duration = 0.1f;
- numRects = ARRAY_COUNT(claudeRun);
- asset_addAnimation(assetManager, arena, "claudeRun", claudeAtlas,
- claudeRun, numRects, duration);
-
- // Battle Idle animation
- char *claudeBattleIdle[3] = {"ClaudeSprite_BattleIdle_Left_01",
- "ClaudeSprite_BattleIdle_Left_02",
- "ClaudeSprite_BattleIdle_Left_03"};
- numRects = ARRAY_COUNT(claudeBattleIdle);
- duration = 0.2f;
- asset_addAnimation(assetManager, arena, "claudeBattleIdle",
- claudeAtlas, claudeBattleIdle, numRects,
- duration);
-
- // Attack Left animation
- char *claudeAttack[6] = {
- "ClaudeSprite_Attack_Left_01", "ClaudeSprite_Attack_Left_02",
- "ClaudeSprite_Attack_Left_03", "ClaudeSprite_Attack_Left_04",
- "ClaudeSprite_Attack_Left_05", "ClaudeSprite_Attack_Left_06"};
- numRects = ARRAY_COUNT(claudeAttack);
- duration = 0.1f;
- asset_addAnimation(assetManager, arena, "claudeAttack", claudeAtlas,
- claudeAttack, numRects, duration);
-
- char *claudeAttackDown[7] = {
- "ClaudeSprite_Attack_Down_01",
- "ClaudeSprite_Attack_Down_02",
- "ClaudeSprite_Attack_Down_03",
- "ClaudeSprite_Attack_Down_04",
- "ClaudeSprite_Attack_Down_05",
- "ClaudeSprite_Attack_Down_06",
- "ClaudeSprite_Attack_Down_07",
- };
-
- numRects = ARRAY_COUNT(claudeAttackDown);
- duration = 0.1f;
- asset_addAnimation(assetManager, arena, "claudeAttackDown",
- claudeAtlas, claudeAttackDown, numRects,
- duration);
-
- char *claudeAttackUp[3] = {
- "ClaudeSprite_Attack_Up_01",
- "ClaudeSprite_Attack_Up_02",
- "ClaudeSprite_Attack_Up_03",
- };
-
- numRects = ARRAY_COUNT(claudeAttackUp);
- duration = 0.2f;
- asset_addAnimation(assetManager, arena, "claudeAttackUp",
- claudeAtlas, claudeAttackUp, numRects,
- duration);
-
- char *claudeDragonHowl[3] = {
- "ClaudeSprite_Attack_DragonHowl_01",
- "ClaudeSprite_Attack_DragonHowl_02",
- "ClaudeSprite_Attack_DragonHowl_03",
- };
-
- numRects = ARRAY_COUNT(claudeDragonHowl);
- duration = 0.2f;
- asset_addAnimation(assetManager, arena, "claudeDragonHowl",
- claudeAtlas, claudeDragonHowl, numRects,
- duration);
-
- char *claudeDragonHowlVfx[7] = {
- "ClaudeSprite_Attack_DragonHowl_Vfx_01",
- "ClaudeSprite_Attack_DragonHowl_Vfx_02",
- "ClaudeSprite_Attack_DragonHowl_Vfx_03",
- "ClaudeSprite_Attack_DragonHowl_Vfx_04",
- "ClaudeSprite_Attack_DragonHowl_Vfx_05",
- "ClaudeSprite_Attack_DragonHowl_Vfx_06",
- "ClaudeSprite_Attack_DragonHowl_Vfx_07",
- };
-
- numRects = ARRAY_COUNT(claudeDragonHowlVfx);
- duration = 0.1f;
- asset_addAnimation(assetManager, arena, "claudeDragonHowlVfx",
- claudeAtlas, claudeDragonHowlVfx, numRects,
- duration);
-
- char *claudeRipperBlast[6] = {
- "ClaudeSprite_Attack_RipperBlast_01",
- "ClaudeSprite_Attack_RipperBlast_02",
- "ClaudeSprite_Attack_RipperBlast_03",
- "ClaudeSprite_Attack_RipperBlast_04",
- "ClaudeSprite_Attack_RipperBlast_05",
- "ClaudeSprite_Attack_RipperBlast_06",
- };
-
- numRects = ARRAY_COUNT(claudeRipperBlast);
- duration = 0.1f;
- asset_addAnimation(assetManager, arena, "claudeRipperBlast",
- claudeAtlas, claudeRipperBlast, numRects,
- duration);
-
- char *claudeRipperBlastVfx[12] = {
- "ClaudeSprite_Attack_RipperBlast_Vfx_01",
- "ClaudeSprite_Attack_RipperBlast_Vfx_02",
- "ClaudeSprite_Attack_RipperBlast_Vfx_03",
- "ClaudeSprite_Attack_RipperBlast_Vfx_04",
- "ClaudeSprite_Attack_RipperBlast_Vfx_05",
- "ClaudeSprite_Attack_RipperBlast_Vfx_06",
- "ClaudeSprite_Attack_RipperBlast_Vfx_07",
- "ClaudeSprite_Attack_RipperBlast_Vfx_08",
- "ClaudeSprite_Attack_RipperBlast_Vfx_09",
- "ClaudeSprite_Attack_RipperBlast_Vfx_10",
- "ClaudeSprite_Attack_RipperBlast_Vfx_11",
- "ClaudeSprite_Attack_RipperBlast_Vfx_12",
- };
-
- numRects = ARRAY_COUNT(claudeRipperBlastVfx);
- duration = 0.1f;
- asset_addAnimation(assetManager, arena, "claudeRipperBlastVfx",
- claudeAtlas, claudeRipperBlastVfx, numRects,
- duration);
-
- // Victory animation
- char *claudeVictory[8] = {"ClaudeSprite_Battle_Victory_01",
- "ClaudeSprite_Battle_Victory_02",
- "ClaudeSprite_Battle_Victory_03",
- "ClaudeSprite_Battle_Victory_04",
- "ClaudeSprite_Battle_Victory_05",
- "ClaudeSprite_Battle_Victory_06",
- "ClaudeSprite_Battle_Victory_07",
- "ClaudeSprite_Battle_Victory_08"};
- numRects = ARRAY_COUNT(claudeVictory);
- duration = 0.1f;
- asset_addAnimation(assetManager, arena, "claudeVictory",
- claudeAtlas, claudeVictory, numRects, duration);
-
- char *claudeEnergySword[6] = {"ClaudeSprite_Attack_EnergySword_01",
- "ClaudeSprite_Attack_EnergySword_02",
- "ClaudeSprite_Attack_EnergySword_03",
- "ClaudeSprite_Attack_EnergySword_04",
- "ClaudeSprite_Attack_EnergySword_05",
- "ClaudeSprite_Attack_EnergySword_06"};
- numRects = ARRAY_COUNT(claudeEnergySword);
- duration = 0.1f;
- asset_addAnimation(assetManager, arena, "claudeEnergySword",
- claudeAtlas, claudeEnergySword, numRects,
- duration);
-
- char *claudeAirSlash[7] = {"ClaudeSprite_Attack_AirSlash_01",
- "ClaudeSprite_Attack_AirSlash_02",
- "ClaudeSprite_Attack_AirSlash_03",
- "ClaudeSprite_Attack_AirSlash_04",
- "ClaudeSprite_Attack_AirSlash_05",
- "ClaudeSprite_Attack_AirSlash_06",
- "ClaudeSprite_Attack_AirSlash_07"};
- numRects = ARRAY_COUNT(claudeAirSlash);
- duration = 0.075f;
- asset_addAnimation(assetManager, arena, "claudeAirSlash",
- claudeAtlas, claudeAirSlash, numRects,
- duration);
-
- char *claudeAirSlashVfx[7] = {"ClaudeSprite_Attack_AirSlash_Vfx_01",
- "ClaudeSprite_Attack_AirSlash_Vfx_02",
- "ClaudeSprite_Attack_AirSlash_Vfx_03",
- "ClaudeSprite_Attack_AirSlash_Vfx_04",
- "ClaudeSprite_Attack_AirSlash_Vfx_05",
- "ClaudeSprite_Attack_AirSlash_Vfx_06",
- "ClaudeSprite_Attack_AirSlash_Vfx_07"};
- numRects = ARRAY_COUNT(claudeAirSlashVfx);
- duration = 0.075f;
- asset_addAnimation(assetManager, arena, "claudeAirSlashVfx",
- claudeAtlas, claudeAirSlashVfx, numRects,
- duration);
-
- char *claudeSword[1] = {
- "ClaudeSprite_Sword_01",
- };
-
- numRects = ARRAY_COUNT(claudeSword);
- duration = 0.4f;
- asset_addAnimation(assetManager, arena, "claudeSword",
- claudeAtlas, claudeSword, numRects,
- duration);
-
- char *claudeAttackSlashLeft[4] = {
- "ClaudeSprite_Attack_Slash_Left_01",
- "ClaudeSprite_Attack_Slash_Left_02",
- "ClaudeSprite_Attack_Slash_Left_03",
- "ClaudeSprite_Attack_Slash_Left_04",
- };
-
- numRects = ARRAY_COUNT(claudeAttackSlashLeft);
- duration = 0.1f;
- asset_addAnimation(assetManager, arena, "claudeAttackSlashLeft",
- claudeAtlas, claudeAttackSlashLeft, numRects,
- duration);
-
- }
- else
- {
-#ifdef DENGINE_DEBUG
- DEBUG_LOG("Failed to load claude sprite xml data");
-#endif
- }
-
- platform_closeFileRead(arena, &claudeXml);
- }
-
-
-#ifdef DENGINE_DEBUG
- DEBUG_LOG("Animations created");
-#endif
-
- /* Load shaders */
- asset_loadShaderFiles(assetManager, arena, "data/shaders/sprite.vert.glsl",
- "data/shaders/sprite.frag.glsl",
- shaderlist_sprite);
-
- result =
- asset_loadTTFont(assetManager, arena, "C:/Windows/Fonts/Arialbd.ttf");
-
-#ifdef DENGINE_DEBUG
- if (result) DEBUG_LOG("Font loading failed");
- GL_CHECK_ERROR();
- DEBUG_LOG("Assets loaded");
-#endif
-
- /* Load sound */
-
- i32 before = arena->used;
-
- char *sfxListPath = "data/audio/sfx/sfx.txt";
- PlatformFileRead sfxList = {0};
- result = platform_readFileToBuffer(arena, sfxListPath, &sfxList);
-
- char *sfxAudioNames[256];
- i32 sfxAudioIndex = 0;
- if (!result)
- {
- char string[256] = {0};
- i32 stringIndex = 0;
- for (i32 i = 0; i < sfxList.size; i++)
- {
- char c = (CAST(char *)sfxList.buffer)[i];
- switch(c)
- {
- case 0x0a:
- {
- i32 actualStrLen = common_strlen(string) + 1;
- sfxAudioNames[sfxAudioIndex] =
- memory_pushBytes(arena, actualStrLen * sizeof(char));
- common_strncpy(sfxAudioNames[sfxAudioIndex++], string,
- actualStrLen);
-
- common_memset(string, 0, ARRAY_COUNT(string));
- stringIndex = 0;
- break;
- }
- default:
- {
- if (c >= ' ' && c <= '~')
- {
- string[stringIndex++] = c;
- }
- break;
- }
- }
- }
- }
-
- char *sfxDir = "data/audio/sfx/";
- char *sfxExtension = ".ogg";
- i32 sfxDirLen = common_strlen(sfxDir);
- i32 sfxExtensionLen = common_strlen(sfxExtension);
-
- for (i32 i = 0; i < sfxAudioIndex; i++)
- {
- char *sfxName = sfxAudioNames[i];
- i32 sfxNameLen = common_strlen(sfxName);
-
- i32 sfxFullPathLen = sfxDirLen + sfxExtensionLen + sfxNameLen + 1;
- char *sfxFullPath =
- memory_pushBytes(arena, sfxFullPathLen * sizeof(char));
-
- common_strncat(sfxFullPath, sfxDir, sfxDirLen);
- common_strncat(sfxFullPath, sfxName, sfxNameLen);
- common_strncat(sfxFullPath, sfxExtension, sfxExtensionLen);
-
- i32 result = asset_loadVorbis(assetManager, arena, sfxFullPath, sfxName);
- if (result) DEBUG_LOG("Failed to load sfx file");
-
- // TODO(doyle): Need better string type to account for null terminating
- // character, having to remember to +1 on allocation AND freeing since
- // strlen only counts until null char is going to leave memory leaks
- // everywhere
- // TODO(doyle): Free mem
- // PLATFORM_MEM_FREE(arena, sfxName, sfxNameLen * sizeof(char) + 1);
- // PLATFORM_MEM_FREE(arena, sfxFullPath, sfxFullPathLen * sizeof(char));
- }
-
- // TODO(doyle): Free mem
- // platform_closeFileRead(arena, &sfxList);
-
- char *audioPath =
- "data/audio/Motoi Sakuraba - Stab the sword of justice.ogg";
- asset_loadVorbis(assetManager, arena, audioPath, "audio_battle");
- audioPath = "data/audio/Motoi Sakuraba - Field of Exper.ogg";
- asset_loadVorbis(assetManager, arena, audioPath, "audio_overworld");
- audioPath = "data/audio/nuindependent_hit22.ogg";
- asset_loadVorbis(assetManager, arena, audioPath, "audio_tackle");
-
-#ifdef DENGINE_DEBUG
- DEBUG_LOG("Sound assets 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;
- const i32 targetWorldHeight = 10 * METERS_TO_PIXEL;
-#if 0
- 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);
-#endif
-
- EventQueue *eventQueue = &state->eventQueue;
- for (i32 i = 0; i < ARRAY_COUNT(state->world); i++)
- {
- World *const world = &state->world[i];
- world->maxEntities = 16384;
- world->entities =
- memory_pushBytes(arena, world->maxEntities * sizeof(Entity));
- world->entityIdInBattle =
- memory_pushBytes(arena, world->maxEntities * sizeof(i32));
- world->numEntitiesInBattle = 0;
- world->bounds =
- math_getRect(V2(0, 0), v2_scale(worldDimensionInTiles,
- CAST(f32) state->tileSize));
- world->uniqueIdAccumulator = 0;
-
-#if 1
- TexAtlas *const atlas = asset_getTexAtlas(assetManager, "terrain.png");
-
- for (i32 y = 0; y < 1; y++)
- {
- for (i32 x = 0; x < worldDimensionInTiles.x; x++)
- {
-#ifdef DENGINE_DEBUG
- ASSERT(worldDimensionInTiles.x * worldDimensionInTiles.y <
- world->maxEntities);
-#endif
- v2 pos = V2(CAST(f32) x * state->tileSize,
- CAST(f32) y * state->tileSize);
- v2 size =
- V2(CAST(f32) state->tileSize, CAST(f32) state->tileSize);
- f32 scale = 1.0f;
- enum EntityType type = entitytype_tile;
- enum Direction dir = direction_null;
- Texture *tex = asset_getTex(assetManager, "terrain.png");
- b32 collides = FALSE;
- Entity *tile = entity_add(arena, world, pos, size, scale, type,
- dir, tex, collides);
-
- entity_addAnim(assetManager, tile, "terrainGrass");
- entity_setActiveAnim(eventQueue, tile, "terrainGrass");
- }
- }
-#endif
- }
-
- World *const world = &state->world[state->currWorldIndex];
- world->cameraPos = V2(0.0f, 0.0f);
-
- /* Add world soundscape */
- Renderer *renderer = &state->renderer;
- v2 size = V2(10.0f, 10.0f);
- v2 pos = V2(0, 0);
- f32 scale = 1.0f;
- enum EntityType type = entitytype_soundscape;
- enum Direction dir = direction_null;
- Texture *tex = NULL;
- b32 collides = FALSE;
- Entity *soundscape =
- entity_add(arena, world, pos, size, scale, type, dir, tex, collides);
-
- world->soundscape = soundscape;
- soundscape->numAudioRenderers = 1;
- soundscape->audioRenderer = memory_pushBytes(
- arena, soundscape->numAudioRenderers * sizeof(AudioRenderer));
- for (i32 i = 0; i < soundscape->numAudioRenderers; i++)
- soundscape->audioRenderer[i].sourceIndex = AUDIO_SOURCE_UNASSIGNED;
-
- /* Init hero entity */
- size = V2(58.0f, 98.0f);
- pos = V2(size.x, CAST(f32) state->tileSize);
- scale = 2.0f;
- type = entitytype_hero;
- dir = direction_east;
- tex = asset_getTex(assetManager, "ClaudeSprite.png");
- collides = TRUE;
-
- Entity *hero =
- entity_add(arena, world, pos, size, scale, type, dir, tex, collides);
-
- Entity *heroWeapon =
- entity_add(arena, world, pos, V2(20, 20), scale, entitytype_weapon,
- dir, tex, FALSE);
- heroWeapon->flipX = TRUE;
- entity_addAnim(assetManager, heroWeapon, "claudeSword");
-
- hero->stats->weapon = heroWeapon;
-
- hero->numAudioRenderers = 4;
- hero->audioRenderer = memory_pushBytes(arena, hero->numAudioRenderers *
- sizeof(AudioRenderer));
-
- for (i32 i = 0; i < hero->numAudioRenderers; i++)
- hero->audioRenderer[i].sourceIndex = AUDIO_SOURCE_UNASSIGNED;
-
- world->heroId = hero->id;
- world->cameraFollowingId = hero->id;
-
- /* Populate hero animation references */
- entity_addAnim(assetManager, hero, "claudeIdle");
- entity_addAnim(assetManager, hero, "claudeRun");
- entity_addAnim(assetManager, hero, "claudeBattleIdle");
-
- entity_addAnim(assetManager, hero, "claudeAttack");
- entity_addAnim(assetManager, hero, "claudeAttackUp");
- entity_addAnim(assetManager, hero, "claudeAttackDown");
-
- entity_addAnim(assetManager, hero, "claudeDragonHowl");
- entity_addAnim(assetManager, hero, "claudeEnergySword");
- entity_addAnim(assetManager, hero, "claudeRipperBlast");
- entity_addAnim(assetManager, hero, "claudeAirSlash");
-
- entity_setActiveAnim(eventQueue, hero, "claudeIdle");
-
- /* Create a NPC */
- pos = V2(hero->pos.x * 3, CAST(f32) state->tileSize);
- size = hero->hitbox;
- type = entitytype_npc;
- dir = direction_null;
- tex = hero->tex;
- collides = FALSE;
- Entity *npc =
- entity_add(arena, world, pos, size, scale, type, dir, tex, collides);
-
- /* Populate npc animation references */
- entity_addAnim(assetManager, npc, "claudeVictory");
- entity_setActiveAnim(eventQueue, npc, "claudeVictory");
-
- /* Create a Mob */
- pos = V2(renderer->size.w - (renderer->size.w / 3.0f),
- CAST(f32) state->tileSize);
- addGenericMob(eventQueue, arena, assetManager, world, pos);
-
-#ifdef DENGINE_DEBUG
- DEBUG_LOG("World populated");
-#endif
-}
-
-INTERNAL v2 getPosRelativeToRect(Rect rect, v2 offset,
- enum RectBaseline baseline)
-{
-#ifdef DENGINE_DEBUG
- ASSERT(baseline < rectbaseline_count);
-#endif
- v2 result = {0};
-
- v2 posToOffsetFrom = rect.pos;
- switch (baseline)
- {
- case rectbaseline_top:
- posToOffsetFrom.y += (rect.size.h);
- posToOffsetFrom.x += (rect.size.w * 0.5f);
- break;
- case rectbaseline_topLeft:
- posToOffsetFrom.y += (rect.size.h);
- break;
- case rectbaseline_topRight:
- posToOffsetFrom.y += (rect.size.h);
- posToOffsetFrom.x += (rect.size.w);
- break;
- case rectbaseline_bottom:
- posToOffsetFrom.x += (rect.size.w * 0.5f);
- break;
- case rectbaseline_bottomRight:
- posToOffsetFrom.x += (rect.size.w);
- break;
- case rectbaseline_left:
- posToOffsetFrom.y += (rect.size.h * 0.5f);
- break;
- case rectbaseline_right:
- posToOffsetFrom.x += (rect.size.w);
- posToOffsetFrom.y += (rect.size.h * 0.5f);
- break;
-
- case rectbaseline_bottomLeft:
- break;
- default:
-#ifdef DENGINE_DEBUG
- DEBUG_LOG(
- "getPosRelativeToRect() warning: baseline enum not recognised");
-#endif
- break;
- }
-
- result = v2_add(posToOffsetFrom, offset);
- return result;
-}
-
-INTERNAL void unitTest(MemoryArena_ *arena)
-{
- ASSERT(common_atoi("-2", common_strlen("-2")) == -2);
- ASSERT(common_atoi("100", common_strlen("100")) == 100);
- ASSERT(common_atoi("1", common_strlen("1")) == 1);
- ASSERT(common_atoi("954 32", common_strlen("954 32")) == 954);
-
- ASSERT(common_atoi("", 0) == -1);
- ASSERT(common_atoi(" 32", common_strlen(" 32")) == -1);
- ASSERT(common_atoi("+32", common_strlen("+32")) == 32);
- ASSERT(common_atoi("+ 32", common_strlen("+ 32")) == 0);
- asset_unitTest(arena);
-
- i32 memBefore = arena->used;
- String *hello = string_make(arena, "hello, ");
- String *world = string_make(arena, "world");
- ASSERT(string_len(hello) == 7);
- ASSERT(string_len(world) == 5);
-
- hello = string_append(arena, hello, world, string_len(world));
- ASSERT(string_len(hello) == 12);
- string_free(arena, hello);
- string_free(arena, world);
-
- hello = string_make(arena, "");
- world = string_make(arena, "");
- hello = string_append(arena, hello, world, string_len(world));
- ASSERT(string_len(hello) == 0);
- ASSERT(string_len(world) == 0);
-
- string_free(arena, hello);
- string_free(arena, world);
-
- i32 memAfter = arena->used;
-}
-
-// TODO(doyle): Remove and implement own random generator!
-#include
-#include
-void worldTraveller_gameInit(GameState *state, v2 windowSize, Memory *memory)
-{
- state->memory = memory;
- memory_arenaInit(&state->arena_, memory->persistent,
- memory->persistentSize);
-
- memory_arenaInit(&state->transientArena, memory->transient,
- memory->transientSize);
-
-#ifdef DENGINE_DEBUG
- unitTest(&state->arena_);
-#endif
-
- 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 = 70;
-
- state->uiState.uniqueId = 1;
- state->uiState.keyEntered = keycode_null;
- state->uiState.keyMod = keycode_null;
- state->uiState.keyChar = keycode_null;
-
- common_strncpy(state->uiState.statWindow.title, "Stat Menu",
- common_strlen("Stat Menu"));
- state->uiState.statWindow.id = 99;
- state->uiState.statWindow.rect.pos = V2(300, 400);
- state->uiState.statWindow.rect.size = V2(300, 400);
- state->uiState.statWindow.prevFrameWindowHeld = FALSE;
- state->uiState.statWindow.windowHeld = FALSE;
-
-
- WindowState *debugWindow = &state->uiState.debugWindow;
- common_strncpy(debugWindow->title, "Debug Menu",
- common_strlen("Debug Menu"));
- debugWindow->id = 98;
- debugWindow->numChildUiItems = 0;
- debugWindow->rect.size = V2(400, 200);
- debugWindow->rect.pos = V2(windowSize.w - debugWindow->rect.size.w - 10,
- windowSize.h - debugWindow->rect.size.h - 10);
- debugWindow->prevFrameWindowHeld = FALSE;
- debugWindow->windowHeld = FALSE;
-
- UiItem *audioBtn =
- (debugWindow->childUiItems) + debugWindow->numChildUiItems++;
- common_strncpy(audioBtn->label, "Toggle Music",
- common_strlen("Toggle Music"));
- audioBtn->id = userInterface_generateId(&state->uiState);
- audioBtn->rect.size = V2(100, 50);
- audioBtn->rect.pos = getPosRelativeToRect(debugWindow->rect, V2(10, -65.0f),
- rectbaseline_topLeft);
- audioBtn->type = uitype_button;
-
- UiItem *debugBtn =
- (debugWindow->childUiItems) + debugWindow->numChildUiItems++;
- common_strncpy(debugBtn->label, "Toggle Debug",
- common_strlen("Toggle Debug"));
- debugBtn->id = userInterface_generateId(&state->uiState);
- debugBtn->rect.size = V2(100, 50);
- debugBtn->rect.pos = getPosRelativeToRect(audioBtn->rect, V2(25, 0),
- rectbaseline_bottomRight);
- debugBtn->type = uitype_button;
-
- UiItem *scrollbar =
- (debugWindow->childUiItems) + debugWindow->numChildUiItems++;
- scrollbar->id = userInterface_generateId(&state->uiState);
-
- scrollbar->rect.size = V2(16, debugWindow->rect.size.h);
- scrollbar->rect.pos =
- getPosRelativeToRect(debugWindow->rect, V2(-scrollbar->rect.size.w, 0),
- rectbaseline_bottomRight);
- scrollbar->value = 0;
- scrollbar->maxValue = 160;
- scrollbar->type = uitype_scrollbar;
-
- UiItem *textField =
- (debugWindow->childUiItems) + debugWindow->numChildUiItems++;
- textField->id = userInterface_generateId(&state->uiState);
- textField->rect.size = V2(200, 20);
- textField->rect.pos = getPosRelativeToRect(
- audioBtn->rect, V2(0, -textField->rect.size.h - 10),
- rectbaseline_bottomLeft);
-
- common_strncpy(textField->string, "Hello world",
- common_strlen("Hello world"));
- textField->type = uitype_textField;
-
- state->config.playWorldAudio = FALSE;
- state->config.showDebugDisplay = TRUE;
-
- assetInit(state);
- rendererInit(state, windowSize);
- entityInit(state, windowSize);
-
- srand(CAST(u32)(time(NULL)));
-}
-
-INTERNAL inline v4 getEntityScreenRect(Entity entity)
-{
- v4 result = math_getRect(entity.pos, entity.hitbox);
- return result;
-}
-
-enum ReadKeyType
-{
- readkeytype_oneShot,
- readkeytype_delayedRepeat,
- readkeytype_repeat,
- readkeytype_count,
-};
-
-#define KEY_DELAY_NONE 0.0f
-
-INTERNAL b32 getKeyStatus(KeyState *key, enum ReadKeyType readType,
- f32 delayInterval, f32 dt)
-{
-
- if (!key->endedDown) return FALSE;
-
- switch(readType)
- {
- case readkeytype_oneShot:
- {
- if (key->newHalfTransitionCount > key->oldHalfTransitionCount)
- return TRUE;
- break;
- }
- case readkeytype_repeat:
- case readkeytype_delayedRepeat:
- {
- if (key->newHalfTransitionCount > key->oldHalfTransitionCount)
- {
- if (readType == readkeytype_delayedRepeat)
- {
- // TODO(doyle): Let user set arbitrary delay after initial input
- key->delayInterval = 2 * delayInterval;
- }
- else
- {
- key->delayInterval = delayInterval;
- }
- return TRUE;
- }
- else if (key->delayInterval <= 0.0f)
- {
- key->delayInterval = delayInterval;
- return TRUE;
- }
- else
- {
- key->delayInterval -= dt;
- }
- break;
- }
- default:
-#ifdef DENGINE_DEBUG
- DEBUG_LOG("getKeyStatus() error: Invalid ReadKeyType enum");
- ASSERT(INVALID_CODE_PATH);
-#endif
- break;
- }
-
- return FALSE;
-}
-
-INTERNAL Rect createWorldBoundedCamera(World *world, v2 size)
-{
- Rect camera = {world->cameraPos, size};
- // NOTE(doyle): Lock camera if it passes the bounds of the world
- if (camera.pos.x <= world->bounds.x)
- camera.pos.x = world->bounds.x;
-
- // TODO(doyle): Allow Y panning when we need it
- f32 cameraTopBoundInPixels = camera.pos.y + camera.size.h;
- if (cameraTopBoundInPixels >= world->bounds.w)
- camera.pos.y = (world->bounds.w - camera.size.h);
-
- f32 cameraRightBoundInPixels = camera.pos.x + camera.size.w;
- if (cameraRightBoundInPixels >= world->bounds.z)
- camera.pos.x = (world->bounds.z - camera.size.w);
-
- if (camera.pos.y <= world->bounds.y) camera.pos.y = world->bounds.y;
- return camera;
-}
-
-#define ENTITY_IN_BATTLE TRUE
-#define ENTITY_NOT_IN_BATTLE FALSE
-#define ENTITY_NULL_ID -1
-INTERNAL i32 findBestEntityToAttack(World *world, Entity attacker)
-{
-#ifdef DENGINE_DEBUG
- ASSERT(world);
- ASSERT(attacker.type == entitytype_hero || attacker.type == entitytype_mob);
-#endif
- i32 result = 0;
-
- // TODO(doyle): If attacker is mob- retrieve hero entity id directly, change
- // when we have party members!
- if (attacker.type == entitytype_mob)
- {
- Entity hero = world->entities[entity_getIndex(world, world->heroId)];
-
- if (hero.state == entitystate_dead) result = ENTITY_NULL_ID;
- else result = hero.id;
-
- return result;
- }
-
- /* Attacker is hero */
- Entity hero = attacker;
- for (i32 i = world->maxEntities; i >= 0; i--)
- {
- Entity targetEntity = world->entities[i];
- if (hero.id == targetEntity.id) continue;
- if (world->entityIdInBattle[targetEntity.id] == ENTITY_IN_BATTLE)
- {
- result = targetEntity.id;
- return result;
- }
- }
-
- // NOTE(doyle): Not all "battling" entities have been enumerated yet in the
- // update loop, guard against when using function
- return ENTITY_NULL_ID;
-}
-
-INTERNAL inline void updateWorldBattleEntities(World *world, Entity *entity,
- b32 isInBattle)
-{
-#ifdef DENGINE_DEBUG
- ASSERT(isInBattle == ENTITY_IN_BATTLE ||
- isInBattle == ENTITY_NOT_IN_BATTLE);
- ASSERT(world && entity);
-#endif
- world->entityIdInBattle[entity->id] = isInBattle;
-
- if (isInBattle)
- {
- world->numEntitiesInBattle++;
- }
- else
- {
- world->numEntitiesInBattle--;
- }
-
-#ifdef DENGINE_DEBUG
- ASSERT(world->numEntitiesInBattle >= 0);
-#endif
-}
-
-// TODO(doyle): Function too vague
-INTERNAL inline void resetEntityState(EventQueue *eventQueue, World *world,
- Entity *entity)
-{
- updateWorldBattleEntities(world, entity, ENTITY_NOT_IN_BATTLE);
- entity_setActiveAnim(eventQueue, entity, "claudeIdle");
- entity->stats->busyDuration = 0;
- entity->stats->actionTimer = entity->stats->actionRate;
- entity->stats->queuedAttack = entityattack_invalid;
- entity->stats->entityIdToAttack = ENTITY_NULL_ID;
-}
-
-void worldTraveller_registerEvent(EventQueue *eventQueue, enum EventType type, void *data)
-{
-#ifdef DENGINE_DEBUG
- ASSERT(eventQueue && type < eventtype_count);
- ASSERT(eventQueue->numEvents+1 < ARRAY_COUNT(eventQueue->queue));
-#endif
- i32 currIndex = eventQueue->numEvents++;
- eventQueue->queue[currIndex].type = type;
- eventQueue->queue[currIndex].data = data;
-}
-
-INTERNAL void entityStateSwitch(EventQueue *eventQueue, World *world,
- Entity *entity, enum EntityState newState)
-{
-#ifdef DENGINE_DEBUG
- ASSERT(world && entity)
- ASSERT(entity->type == entitytype_mob || entity->type == entitytype_hero)
-#endif
- if (entity->state == newState) return;
-
- switch(entity->state)
- {
- case entitystate_idle:
- switch (newState)
- {
- case entitystate_battle:
- updateWorldBattleEntities(world, entity, ENTITY_IN_BATTLE);
- entity->stats->entityIdToAttack =
- findBestEntityToAttack(world, *entity);
- break;
-
- // TODO(doyle): Corner case- if move out of range and entity has
- // switched to idle mode, we reach the attacker entity and they continue
- // attacking it since there's no check before attack if entity is idle
- // or not (i.e. has moved out of frame last frame).
- case entitystate_dead:
- worldTraveller_registerEvent(eventQueue, eventtype_entity_died,
- CAST(void *) entity);
- entity_setActiveAnim(eventQueue, entity, "claudeIdle");
- entity->stats->busyDuration = 0;
- entity->stats->actionTimer = entity->stats->actionRate;
- entity->stats->queuedAttack = entityattack_invalid;
- entity->stats->entityIdToAttack = ENTITY_NULL_ID;
- break;
-
- case entitystate_attack:
- default:
-#ifdef DENGINE_DEBUG
- ASSERT(INVALID_CODE_PATH);
-#endif
- break;
- }
- break;
- case entitystate_battle:
- switch (newState)
- {
- case entitystate_attack:
- {
- break;
- }
- case entitystate_idle:
- resetEntityState(eventQueue, world, entity);
- break;
- case entitystate_dead:
- worldTraveller_registerEvent(eventQueue, eventtype_entity_died,
- CAST(void *) entity);
- resetEntityState(eventQueue, world, entity);
- break;
- default:
-#ifdef DENGINE_DEBUG
- ASSERT(INVALID_CODE_PATH);
-#endif
- break;
- }
- break;
- case entitystate_attack:
- switch (newState)
- {
- case entitystate_battle:
- entity_setActiveAnim(eventQueue, entity, "claudeBattleIdle");
- entity->stats->actionTimer = entity->stats->actionRate;
- entity->stats->busyDuration = 0;
- break;
- // NOTE(doyle): Entity has been forced out of an attack (out of range)
- case entitystate_idle:
- resetEntityState(eventQueue, world, entity);
- break;
- case entitystate_dead:
- worldTraveller_registerEvent(eventQueue, eventtype_entity_died,
- CAST(void *) entity);
- resetEntityState(eventQueue, world, entity);
- break;
- default:
-#ifdef DENGINE_DEBUG
- ASSERT(INVALID_CODE_PATH);
-#endif
- break;
- }
- break;
- case entitystate_dead:
- switch (newState)
- {
- case entitystate_idle:
- case entitystate_battle:
- case entitystate_attack:
- default:
-#ifdef DENGINE_DEBUG
- ASSERT(INVALID_CODE_PATH);
-#endif
- break;
- }
- break;
- default:
-#ifdef DENGINE_DEBUG
- ASSERT(INVALID_CODE_PATH);
-#endif
- break;
- }
-
- entity->state = newState;
-}
-
-typedef struct AttackSpec
-{
- Entity *attacker;
- Entity *defender;
- i32 damage;
-} AttackSpec;
-
-INTERNAL void beginAttack(AssetManager *assetManager, MemoryArena_ *arena,
- EventQueue *eventQueue, World *world,
- Entity *attacker)
-{
-#ifdef DENGINE_DEBUG
- ASSERT(attacker->stats->entityIdToAttack != ENTITY_NULL_ID);
- ASSERT(attacker->state == entitystate_battle);
-#endif
-
- entityStateSwitch(eventQueue, world, attacker, entitystate_attack);
- switch (attacker->stats->queuedAttack)
- {
- case entityattack_claudeAttack:
- {
- entity_setActiveAnim(eventQueue, attacker, "claudeAttack");
- if (attacker->direction == direction_east)
- attacker->dPos.x += (1.0f * METERS_TO_PIXEL);
- else
- attacker->dPos.x -= (1.0f * METERS_TO_PIXEL);
- break;
- }
-
- case entityattack_claudeAttackUp:
- {
- entity_setActiveAnim(eventQueue, attacker, "claudeAttackUp");
- if (attacker->direction == direction_east)
- attacker->dPos.x += (1.0f * METERS_TO_PIXEL);
- else
- attacker->dPos.x -= (1.0f * METERS_TO_PIXEL);
- break;
- }
-
- case entityattack_claudeAttackDown:
- {
- entity_setActiveAnim(eventQueue, attacker, "claudeAttackDown");
- if (attacker->direction == direction_east)
- attacker->dPos.x += (1.0f * METERS_TO_PIXEL);
- else
- attacker->dPos.x -= (1.0f * METERS_TO_PIXEL);
- break;
- }
-
- case entityattack_claudeDragonHowl:
- {
- entity_setActiveAnim(eventQueue, attacker, "claudeDragonHowl");
- f32 scale = 1.5f;
- v2 size = V2(40, 40);
- Entity *projectile = entity_add(
- arena, world, attacker->pos, size, scale,
- entitytype_projectile, attacker->direction, attacker->tex, TRUE);
-
- projectile->collidesWith[entitytype_hero] = TRUE;
- projectile->collidesWith[entitytype_mob] = TRUE;
- projectile->collidesWith[attacker->type] = FALSE;
-
- projectile->stats->entityIdToAttack = attacker->stats->entityIdToAttack;
- entity_addAnim(assetManager, projectile, "claudeDragonHowlVfx");
- entity_setActiveAnim(eventQueue, projectile, "claudeDragonHowlVfx");
- break;
- }
-
- case entityattack_claudeEnergySword:
- {
- entity_setActiveAnim(eventQueue, attacker, "claudeEnergySword");
- break;
- }
-
- case entityattack_claudeRipperBlast:
- {
- entity_setActiveAnim(eventQueue, attacker, "claudeRipperBlast");
- f32 scale = 5.0f;
- v2 size = V2(20, 20);
-
- Entity *target = entity_get(world, attacker->stats->entityIdToAttack);
- v2 targetPos = v2_add(attacker->pos, V2(100, 0));
- if (target)
- {
- targetPos = target->pos;
- }
-
- Entity *projectile = entity_add(
- arena, world, targetPos, size, scale,
- entitytype_attackObject, attacker->direction, attacker->tex, TRUE);
-
- projectile->collidesWith[entitytype_hero] = TRUE;
- projectile->collidesWith[entitytype_mob] = TRUE;
- projectile->collidesWith[attacker->type] = FALSE;
-
- projectile->stats->entityIdToAttack = attacker->stats->entityIdToAttack;
- entity_addAnim(assetManager, projectile, "claudeRipperBlastVfx");
- entity_setActiveAnim(eventQueue, projectile, "claudeRipperBlastVfx");
- break;
- }
-
- case entityattack_claudeAirSlash:
- {
- entity_setActiveAnim(eventQueue, attacker, "claudeAirSlash");
- f32 scale = 1.5f;
- v2 size = V2(20, 20);
- Entity *projectile = entity_add(
- arena, world, attacker->pos, size, scale,
- entitytype_projectile, attacker->direction, attacker->tex, TRUE);
-
- projectile->collidesWith[entitytype_hero] = TRUE;
- projectile->collidesWith[entitytype_mob] = TRUE;
- projectile->collidesWith[attacker->type] = FALSE;
-
- projectile->stats->entityIdToAttack = attacker->stats->entityIdToAttack;
- entity_addAnim(assetManager, projectile, "claudeAirSlashVfx");
- entity_setActiveAnim(eventQueue, projectile, "claudeAirSlashVfx");
-
- v2 initialOffset = V2(size.x * 0.5f, 0);
- f32 deltaScale = 0.3f;
- projectile->numChilds = 3;
- for (i32 i = 0; i < projectile->numChilds; i++)
- {
- v2 childOffset = v2_scale(initialOffset, CAST(f32) i + 1);
- scale -= deltaScale;
-
- Entity *child =
- entity_add(arena, world, v2_sub(projectile->pos, childOffset),
- V2(20, 20), scale, entitytype_projectile,
- projectile->direction, projectile->tex, FALSE);
-
- child->collidesWith[entitytype_hero] = FALSE;
- child->collidesWith[entitytype_mob] = TRUE;
-
- child->stats->entityIdToAttack =
- projectile->stats->entityIdToAttack;
- entity_addAnim(assetManager, child, "claudeAirSlashVfx");
- entity_setActiveAnim(eventQueue, child, "claudeAirSlashVfx");
- projectile->childIds[i] = child->id;
- }
- break;
- }
-
- default:
-#ifdef DENGINE_DEBUG
- ASSERT(INVALID_CODE_PATH);
-#endif
- break;
- }
-
- EntityAnim attackAnim = attacker->animList[attacker->currAnimId];
- f32 busyDuration =
- attackAnim.anim->frameDuration * CAST(f32) attackAnim.anim->numFrames;
- attacker->stats->busyDuration = busyDuration;
-}
-
-// TODO(doyle): MemArena here is temporary until we incorporate AttackSpec to
-// battle in general!
-INTERNAL void endAttack(MemoryArena_ *arena, EventQueue *eventQueue,
- World *world, Entity *attacker)
-{
-#ifdef DENGINE_DEBUG
- ASSERT(attacker->stats->entityIdToAttack != ENTITY_NULL_ID);
-#endif
-
- entityStateSwitch(eventQueue, world, attacker, entitystate_battle);
- switch (attacker->stats->queuedAttack)
- {
- case entityattack_claudeAttack:
- case entityattack_claudeAttackUp:
- case entityattack_claudeAttackDown:
- // TODO(doyle): Move animation offsets out and into animation type
- if (attacker->direction == direction_east)
- attacker->dPos.x -= (1.0f * METERS_TO_PIXEL);
- else
- attacker->dPos.x += (1.0f * METERS_TO_PIXEL);
-
- break;
-
- case entityattack_claudeAirSlash:
- case entityattack_claudeRipperBlast:
- case entityattack_claudeDragonHowl:
- break;
-
- case entityattack_claudeEnergySword:
- attacker->stats->health += 80;
- AttackSpec *attackSpec = MEMORY_PUSH_STRUCT(arena, AttackSpec);
- attackSpec->attacker = attacker;
- attackSpec->defender = attacker;
- attackSpec->damage = 30;
- worldTraveller_registerEvent(eventQueue, eventtype_end_attack,
- attackSpec);
- return;
-
- default:
-#ifdef DENGINE_DEBUG
- ASSERT(INVALID_CODE_PATH);
-#endif
- break;
- }
-
- /* Compute attack damage */
- Entity *defender = NULL;
-
- // TODO(doyle): Implement faster lookup for entity id in entity table
- b32 noMoreValidTargets = FALSE;
- do
- {
- /* Get target entity to attack */
- i32 entityIdToAttack = attacker->stats->entityIdToAttack;
- i32 entityIndex = entity_getIndex(world, entityIdToAttack);
-
- if (entityIndex != -1)
- {
- defender = &world->entities[entityIndex];
-#ifdef DENGINE_DEBUG
- ASSERT(defender->type == entitytype_mob ||
- defender->type == entitytype_hero);
-#endif
- }
- else
- {
- i32 entityIdToAttack = findBestEntityToAttack(world, *attacker);
- if (entityIdToAttack == ENTITY_NULL_ID)
- {
- noMoreValidTargets = TRUE;
- }
- else
- {
- attacker->stats->entityIdToAttack =
- findBestEntityToAttack(world, *attacker);
- }
- }
- } while (!defender && noMoreValidTargets == TRUE);
-
- if (!noMoreValidTargets)
- {
- i32 damage = 25;
-
- AttackSpec *attackSpec = MEMORY_PUSH_STRUCT(arena, AttackSpec);
- attackSpec->attacker = attacker;
- attackSpec->defender = defender;
- attackSpec->damage = damage;
-
- worldTraveller_registerEvent(eventQueue, eventtype_end_attack,
- attackSpec);
- // TODO(doyle): Use attacker stats in battle equations
- if (attacker->type == entitytype_hero)
- {
- defender->stats->health -= damage;
- }
- else if (attacker->type == entitytype_mob)
- {
- defender->stats->health -= damage * 0.25f;
- }
-
- if (defender->stats->health <= 0.0f) defender->stats->health = 10.0f;
-
- if (defender->stats->health <= 0)
- {
- entityStateSwitch(eventQueue, world, defender, entitystate_dead);
- entityStateSwitch(eventQueue, world, attacker, entitystate_idle);
- }
- }
-}
-
-INTERNAL void sortWorldEntityList(World *world)
-{
- b32 listHasChanged = TRUE;
- i32 numUnsortedEntities = world->freeEntityIndex;
- while (listHasChanged)
- {
- 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 ||
- (entityB->type != entitytype_null && entityA->id > entityB->id))
- {
- Entity tempEntity = world->entities[i];
- world->entities[i] = world->entities[i + 1];
- world->entities[i + 1] = tempEntity;
- listHasChanged = TRUE;
- }
- }
- numUnsortedEntities--;
- }
-}
-
-INTERNAL enum EntityAttack selectBestAttack(Entity *entity)
-{
- if (entity->stats->health <= 50.0f && entity->type == entitytype_hero)
- {
- return entityattack_claudeEnergySword;
- }
- else
- {
- enum EntityAttack attack = entityattack_claudeAttack;
- i32 choice = rand() % 7;
- switch(choice)
- {
- case 0: attack = entityattack_claudeAttack; break;
- case 1: attack = entityattack_claudeAttackUp; break;
- case 2: attack = entityattack_claudeAttackDown; break;
- case 3: attack = entityattack_claudeDragonHowl; break;
- case 4: attack = entityattack_claudeEnergySword; break;
- case 5: attack = entityattack_claudeRipperBlast; break;
- case 6: attack = entityattack_claudeAirSlash; break;
- default: break;
- }
-
- return attack;
- }
-}
-
-INTERNAL i32 entityGetFreeAudioRendererIndex(Entity *entity)
-{
- i32 result = -1;
- for (i32 i = 0; i < entity->numAudioRenderers; i++)
- {
- if (entity->audioRenderer[i].state == audiostate_stopped)
- {
- result = i;
- break;
- }
- }
-
- return result;
-}
-
-typedef struct DamageDisplay
-{
- char damageStr[12];
- v2 pos;
- f32 lifetime;
-} DamageDisplay;
-
-typedef struct BattleState
-{
- DamageDisplay damageDisplay[128];
-} BattleState;
-
-GLOBAL_VAR BattleState battleState = {0};
-
-INTERNAL b32 checkCollision(Entity *a, Entity *b)
-{
- b32 result = FALSE;
- if (a->collides && b->collides && a->collidesWith[b->type])
- {
- Rect aRect = {a->pos, a->hitbox};
-
- v2 aTopLeftP =
- getPosRelativeToRect(aRect, V2(0, 0), rectbaseline_topLeft);
- v2 aTopRightP =
- getPosRelativeToRect(aRect, V2(0, 0), rectbaseline_topRight);
- v2 aBottomLeftP =
- getPosRelativeToRect(aRect, V2(0, 0), rectbaseline_bottomLeft);
- v2 aBottomRightP =
- getPosRelativeToRect(aRect, V2(0, 0), rectbaseline_bottomRight);
-
- Rect bRect = {b->pos, b->hitbox};
-
- if (math_pointInRect(bRect, aTopLeftP) ||
- math_pointInRect(bRect, aTopRightP) ||
- math_pointInRect(bRect, aBottomLeftP) ||
- math_pointInRect(bRect, aBottomRightP))
- {
- result = TRUE;
- return result;
- }
- }
-
- return result;
-}
-
-INTERNAL b32 moveEntityAndReturnCollision(World *world, Entity *entity,
- v2 ddPos, f32 speedInMs, f32 dt)
-{
- /*
- **************************
- * Calculate Hero Speed
- **************************
- */
- // NOTE(doyle): Clipping threshold for snapping velocity to 0
- f32 epsilon = 15.0f;
- v2 epsilonDpos = v2_sub(V2(epsilon, epsilon),
- V2(ABS(entity->dPos.x), ABS(entity->dPos.y)));
-
- if (epsilonDpos.x >= 0.0f && epsilonDpos.y >= 0.0f)
- entity->dPos = V2(0.0f, 0.0f);
-
- f32 speedInPixels = speedInMs * METERS_TO_PIXEL;
-
- ddPos = v2_scale(ddPos, speedInPixels);
- // TODO(doyle): Counteracting force on player's acceleration is
- // arbitrary
- ddPos = v2_sub(ddPos, v2_scale(entity->dPos, 5.5f));
-
- /*
- NOTE(doyle): Calculate new position from acceleration with old
- velocity
- new Position = (a/2) * (t^2) + (v*t) + p,
- acceleration = (a/2) * (t^2)
- old velocity = (v*t)
- */
- v2 ddPosNew = v2_scale(v2_scale(ddPos, 0.5f), SQUARED(dt));
- v2 dPos = v2_scale(entity->dPos, dt);
-
- v2 oldP = entity->pos;
- v2 newP = v2_add(v2_add(ddPosNew, dPos), entity->pos);
- entity->pos = newP;
-
- /*
- **************************
- * Collision Detection
- **************************
- */
- // TODO(doyle): Only check collision for entities within small
- // bounding box of the hero
- b32 entityCollided = FALSE;
- if (entity->collides)
- {
- for (i32 i = 0; i < world->maxEntities; i++)
- {
- Entity *collider = &world->entities[i];
- if (collider->state == entitystate_dead) continue;
- if (collider->id == entity->id) continue;
-
- entityCollided = checkCollision(entity, collider);
- if (entityCollided) break;
- }
- }
-
- if (entityCollided)
- {
- entity->dPos = V2(0.0f, 0.0f);
- entity->pos = oldP;
- }
- else
- {
- // f'(t) = curr velocity = a*t + v, where v is old velocity
- entity->dPos = v2_add(entity->dPos, v2_scale(ddPos, dt));
- entity->pos = newP;
- }
-
- return entityCollided;
-}
-
-void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
-{
- // TODO(doyle): use proper dt limiting techniques
- if (dt >= 1.0f) dt = 1.0f;
- GL_CHECK_ERROR();
-
- memory_arenaInit(&state->transientArena, state->memory->transient,
- state->memory->transientSize);
-
- AssetManager *assetManager = &state->assetManager;
- Renderer *renderer = &state->renderer;
- World *const world = &state->world[state->currWorldIndex];
- Font *font = &assetManager->font;
- MemoryArena_ *arena = &state->arena_;
- MemoryArena_ *transientArena = &state->transientArena;
- EventQueue *eventQueue = &state->eventQueue;
-
- /*
- **********************
- * Parse Input Keys
- **********************
- */
- {
- /*
- **********************
- * Parse Alphabet Keys
- **********************
- */
- KeyState *keys = state->input.keys;
- for (enum KeyCode code = 0; code < keycode_count; code++)
- {
- b32 parseKey = FALSE;
-
- KeyState *key = &keys[code];
- if (key->newHalfTransitionCount > key->oldHalfTransitionCount)
- {
- i32 numTransitions =
- key->newHalfTransitionCount - key->oldHalfTransitionCount;
-
- if (!IS_EVEN(numTransitions))
- key->endedDown = (key->endedDown) ? FALSE : TRUE;
- }
-
- if (code >= keycode_a && code <= keycode_z) parseKey = TRUE;
- if (code >= keycode_A && code <= keycode_Z) parseKey = TRUE;
- if (code >= keycode_0 && code <= keycode_9) parseKey = TRUE;
-
- if (!parseKey) continue;
-
- if (getKeyStatus(key, readkeytype_repeat, 0.15f, dt))
- {
- // TODO(doyle): Multi press within frame overrides ui parsing
- state->uiState.keyChar = code;
- }
- }
-
- /*
- **************************
- * Parse Game Control Keys
- **************************
- */
- if (getKeyStatus(&keys[keycode_enter], readkeytype_oneShot,
- KEY_DELAY_NONE, dt))
- {
- state->uiState.keyEntered = keycode_enter;
- }
-
- if (getKeyStatus(&keys[keycode_tab], readkeytype_delayedRepeat, 0.25f,
- dt))
- {
- state->uiState.keyEntered = keycode_tab;
- }
-
- if (getKeyStatus(&keys[keycode_space], readkeytype_delayedRepeat, 0.25f,
- dt))
- {
- state->uiState.keyChar = keycode_space;
- }
-
- if (getKeyStatus(&keys[keycode_backspace], readkeytype_delayedRepeat,
- 0.1f, dt))
- {
- state->uiState.keyEntered = keycode_backspace;
- }
-
- if (getKeyStatus(&keys[keycode_left_square_bracket],
- readkeytype_delayedRepeat, 0.0f, dt))
- {
-
- Renderer *renderer = &state->renderer;
- f32 yPos = CAST(f32)(rand() % CAST(i32) renderer->size.h);
- f32 xModifier = 5.0f - CAST(f32)(rand() % 3);
-
- v2 pos =
- V2(renderer->size.w - (renderer->size.w / xModifier), yPos);
- addGenericMob(eventQueue, &state->arena_, &state->assetManager, world, pos);
- }
- }
-
- /*
- ******************************
- * Update entities and render
- ******************************
- */
- Rect camera = createWorldBoundedCamera(world, renderer->size);
- AudioManager *audioManager = &state->audioManager;
-
- ASSERT(world->freeEntityIndex < world->maxEntities);
- for (i32 i = 0; i < world->freeEntityIndex; i++)
- {
- Entity *const entity = &world->entities[i];
-
- /* Reposition camera if entity is targeted id */
- if (world->cameraFollowingId == entity->id)
- {
- // NOTE(doyle): Set the camera such that the hero is centered
- v2 offsetFromEntityToCameraOrigin =
- V2((entity->pos.x - (0.5f * state->renderer.size.w)), (0.0f));
-
- // NOTE(doyle): Account for the hero's origin being the bottom left
- offsetFromEntityToCameraOrigin.x += (entity->hitbox.w * 0.5f);
- world->cameraPos = offsetFromEntityToCameraOrigin;
- }
-
- if (entity->state == entitystate_dead) continue;
- if (entity->invisible == TRUE) continue;
-
- if (entity->type == entitytype_soundscape)
- {
- AudioRenderer *audioRenderer = &entity->audioRenderer[0];
- if (!state->config.playWorldAudio)
- {
- // TODO(doyle): Use is playing flag, not just streaming flag
- if (audioRenderer->state == audiostate_playing)
- {
- audio_pauseVorbis(&state->audioManager, audioRenderer);
- }
- }
- else
- {
- if (world->numEntitiesInBattle > 0)
- {
- AudioVorbis *battleTheme =
- asset_getVorbis(assetManager, "audio_battle");
- if (audioRenderer->audio)
- {
- if (common_strcmp(audioRenderer->audio->key,
- "audio_battle") != 0)
- {
- audio_streamPlayVorbis(arena, &state->audioManager,
- audioRenderer, battleTheme,
- AUDIO_REPEAT_INFINITE);
- }
- }
- else
- {
- audio_streamPlayVorbis(arena, &state->audioManager,
- audioRenderer, battleTheme,
- AUDIO_REPEAT_INFINITE);
- }
- }
- else
- {
- AudioVorbis *overworldTheme =
- asset_getVorbis(assetManager, "audio_overworld");
- if (audioRenderer->audio)
- {
- if (common_strcmp(audioRenderer->audio->key,
- "audio_overworld") != 0)
- {
- audio_streamPlayVorbis(
- arena, &state->audioManager, audioRenderer,
- overworldTheme, AUDIO_REPEAT_INFINITE);
- }
- }
- else
- {
- audio_streamPlayVorbis(arena, &state->audioManager,
- audioRenderer, overworldTheme,
- AUDIO_REPEAT_INFINITE);
- }
- }
-
- if (audioRenderer->state == audiostate_paused)
- {
- audio_resumeVorbis(&state->audioManager, audioRenderer);
- }
- }
- }
-
- /*
- *****************************************************
- * Calculate Mob In Battle Range
- *****************************************************
- */
- if (entity->type == entitytype_mob)
- {
- // TODO(doyle): Currently calculated in pixels, how about meaningful
- // game units?
- f32 battleThreshold = 500.0f;
- Entity *hero = getHeroEntity(world);
- f32 distance = v2_magnitude(hero->pos, entity->pos);
-
- enum EntityState newState = entitystate_invalid;
- if (distance <= battleThreshold)
- {
- // NOTE(doyle): If in range but in battle, no state change
- if (entity->state == entitystate_battle ||
- entity->state == entitystate_attack)
- {
- newState = entity->state;
- }
- else
- {
- newState = entitystate_battle;
- }
- }
- else
- {
- newState = entitystate_idle;
- }
-
- i32 numEntitiesInBattleBefore = world->numEntitiesInBattle;
- entityStateSwitch(eventQueue, world, entity, newState);
-
- if (numEntitiesInBattleBefore == 0 &&
- world->numEntitiesInBattle > 0)
- {
- i32 freeAudioIndex = entityGetFreeAudioRendererIndex(hero);
- if (freeAudioIndex != -1)
- {
- char *battleTaunt[11] = {
- "Battle_come_on",
- "Battle_heh",
- "Battle_heres_the_enemy",
- "Battle_hey",
- "Battle_oh_its_just_them",
- "Battle_shouldnt_you_run_away",
- "Battle_things_will_work_out_somehow",
- "Battle_things_will_work_out",
- "Battle_were_gonna_win",
- "Battle_we_can_win_this",
- "Battle_you_think_you_can_win_over_the_hero_of_light"};
-
- i32 battleTauntSfxIndex = rand() % ARRAY_COUNT(battleTaunt);
- audio_playVorbis(
- arena, audioManager,
- &hero->audioRenderer[freeAudioIndex],
- asset_getVorbis(assetManager,
- battleTaunt[battleTauntSfxIndex]),
- 1);
- }
- }
- }
- else if (entity->type == entitytype_hero)
- {
- /*
- **************************
- * Calculate Hero Movement
- **************************
- */
-
- /*
- Equations of Motion
- f(t) = position m
- f'(t) = velocity m/s
- f"(t) = acceleration m/s^2
-
- The user supplies an acceleration, a, and by integrating
- f"(t) = a, where a is a constant, acceleration
- f'(t) = a*t + v, where v is a constant, old velocity
- f (t) = (a/2)*t^2 + v*t + p, where p is a constant, old position
- */
-
- Entity *hero = entity;
- KeyState *keys = state->input.keys;
-
- v2 ddPos = V2(0, 0);
- if (hero->stats->busyDuration <= 0)
- {
- if (getKeyStatus(&keys[keycode_right], readkeytype_repeat,
- KEY_DELAY_NONE, dt))
- {
- ddPos.x = 1.0f;
- hero->direction = direction_east;
- }
-
- if (getKeyStatus(&keys[keycode_left], readkeytype_repeat,
- KEY_DELAY_NONE, dt))
- {
- ddPos.x = -1.0f;
- hero->direction = direction_west;
- }
-
- if (getKeyStatus(&keys[keycode_up], readkeytype_repeat,
- KEY_DELAY_NONE, dt))
- {
- ddPos.y = 1.0f;
- }
-
- if (getKeyStatus(&keys[keycode_down], readkeytype_repeat,
- KEY_DELAY_NONE, dt))
- {
- ddPos.y = -1.0f;
- }
-
- if (ddPos.x != 0.0f && ddPos.y != 0.0f)
- {
- // NOTE(doyle): Cheese it and pre-compute the vector for
- // diagonal using pythagoras theorem on a unit triangle 1^2
- // + 1^2 = c^2
- ddPos = v2_scale(ddPos, 0.70710678118f);
- }
- }
-
- f32 heroSpeed = 6.2f;
- if (getKeyStatus(&state->input.keys[keycode_leftShift],
- readkeytype_repeat, KEY_DELAY_NONE, dt))
- {
- // TODO: Context sensitive command separation
- state->uiState.keyMod = keycode_leftShift;
- heroSpeed *= 10.0f;
- }
- else
- {
- state->uiState.keyMod = keycode_null;
- }
-
- moveEntityAndReturnCollision(world, hero, ddPos, heroSpeed, dt);
-
- char *currAnimName = hero->animList[hero->currAnimId].anim->key;
- if (ABS(entity->dPos.x) > 0.0f || ABS(entity->dPos.y) > 0.0f)
- {
- if (common_strcmp(currAnimName, "claudeIdle") == 0)
- {
- entity_setActiveAnim(eventQueue, hero, "claudeRun");
- }
- }
- else
- {
- if (common_strcmp(currAnimName, "claudeRun") == 0)
- {
- entity_setActiveAnim(eventQueue, hero, "claudeIdle");
- }
- }
-
- }
- else if (entity->type == entitytype_projectile)
- {
- Entity *projectile = entity;
- i32 targetIndex =
- entity_getIndex(world, projectile->stats->entityIdToAttack);
- Entity *target = &world->entities[targetIndex];
-
- v2 ddPos = V2(0, 0);
- f32 projectileSpeed = 10.0f;
-
- v2 difference = v2_sub(target->pos, projectile->pos);
- f32 longSide = (ABS(difference.x) > ABS(difference.y))
- ? ABS(difference.x)
- : ABS(difference.y);
-
- ddPos.x = (difference.x / longSide);
- ddPos.y = (difference.y / longSide);
-
- if (ddPos.x != 0.0f && ddPos.y != 0.0f)
- {
- // NOTE(doyle): Cheese it and pre-compute the vector for
- // diagonal using pythagoras theorem on a unit triangle 1^2
- // + 1^2 = c^2
- ddPos = v2_scale(ddPos, 0.70710678118f);
- }
-
- b32 collided = moveEntityAndReturnCollision(
- world, projectile, ddPos, projectileSpeed, dt);
-
- if (collided)
- {
- // TODO(doyle): Unify concept of dead entity for mobs and
- // projectiles
- projectile->state = entitystate_dead;
- // TODO(doyle): register endattack event
- worldTraveller_registerEvent(eventQueue, eventtype_entity_died,
- projectile);
- }
- }
- else if (entity->type == entitytype_attackObject)
- {
- if (entity->animList[entity->currAnimId].timesCompleted == 1)
- {
- entity->state = entitystate_dead;
- worldTraveller_registerEvent(eventQueue, eventtype_entity_died,
- entity);
- }
- }
-
- /*
- **************************************************
- * Conduct Battle For Mobs In Range
- **************************************************
- */
- if (entity->type == entitytype_mob || entity->type == entitytype_hero)
- {
- EntityStats *stats = entity->stats;
-
- if (stats->weapon)
- {
- Entity *weapon = stats->weapon;
- weapon->pos = entity->pos;
-
- // TODO(doyle): Add concept of entity origin and make all
- // transform start from that origin point
- if (entity->direction == direction_east)
- {
- weapon->pos.x += entity->size.w;
- weapon->pos.x -= weapon->size.w;
- }
- weapon->direction = entity->direction;
-
- SubTexture entitySubTexture =
- entity_getActiveSubTexture(entity);
- weapon->pos.y += entitySubTexture.offset.y;
-
- if (weapon->direction == direction_west)
- {
- weapon->pos.x += entitySubTexture.offset.x;
- // TODO(doyle): Typedef rotation to degrees for type safety
- weapon->rotation = DEGREES_TO_RADIANS(30.0f);
- }
- else
- {
- LOCAL_PERSIST f32 rotation = -30.0f;
- rotation -= 1.5f;
- weapon->pos.x -= entitySubTexture.offset.x;
- weapon->rotation = DEGREES_TO_RADIANS(rotation);
- }
- }
-
- if (entity->state == entitystate_battle)
- {
-
- if (stats->actionTimer > 0)
- stats->actionTimer -= dt * stats->actionSpdMul;
-
- if (stats->actionTimer <= 0)
- {
- stats->actionTimer = 0;
- if (stats->queuedAttack == entityattack_invalid)
- {
- enum EntityAttack attack = selectBestAttack(entity);
- stats->queuedAttack = attack;
- }
-
- /* Launch up attack animation */
- beginAttack(assetManager, &state->arena_, eventQueue, world,
- entity);
- }
- }
- else if (entity->state == entitystate_attack)
- {
- // TODO(doyle): Untested if the attacker and the defender same
- Entity *attacker = entity;
- stats->busyDuration -= dt;
- if (stats->busyDuration <= 0)
- {
- /* Apply attack damage */
- endAttack(transientArena, eventQueue, world, entity);
- }
- }
- }
-
- /*
- ****************
- * Update Entity
- ****************
- */
- for (i32 i = 0; i < entity->numAudioRenderers; i++)
- {
- audio_updateAndPlay(&state->arena_, &state->audioManager,
- &entity->audioRenderer[i]);
- }
-
- if (entity->tex)
- {
- entity_updateAnim(eventQueue, entity, dt);
- /* Calculate region to render */
- renderer_entity(renderer, camera, entity,
- v2_scale(entity->size, 0.5f), 0, V4(1, 1, 1, 1.0f));
- }
- }
-
- /*
- *****************************************
- * Process Events From Entity Update Loop
- *****************************************
- */
- i32 numDeadEntities = 0;
- for (i32 i = 0; i < eventQueue->numEvents; i++)
- {
- Event event = eventQueue->queue[i];
-
- eventQueue->queue[i].type = eventtype_null;
- eventQueue->queue[i].data = NULL;
-
- switch(event.type)
- {
- case eventtype_end_attack:
- {
- if (!event.data) continue;
-
- AttackSpec *attackSpec = (CAST(AttackSpec *) event.data);
- Entity *attacker = attackSpec->attacker;
- Entity *defender = attackSpec->defender;
-
- if (attacker->stats->queuedAttack == entityattack_claudeAttack ||
- attacker->stats->queuedAttack == entityattack_claudeAttackUp ||
- attacker->stats->queuedAttack == entityattack_claudeAttackDown)
- {
- i32 freeAudioIndex = entityGetFreeAudioRendererIndex(attacker);
- if (freeAudioIndex != -1)
- {
- char *attackSfx[11] = {
- "Attack_1", "Attack_2", "Attack_3",
- "Attack_4", "Attack_5", "Attack_6",
- "Attack_7", "Attack_hit_it", "Attack_take_that",
- "Attack_hya", "Attack_burn"};
-
- i32 attackSfxIndex = rand() % ARRAY_COUNT(attackSfx);
- audio_playVorbis(arena, audioManager,
- &attacker->audioRenderer[freeAudioIndex],
- asset_getVorbis(assetManager,
- attackSfx[attackSfxIndex]),
- 1);
- }
-
- freeAudioIndex = entityGetFreeAudioRendererIndex(defender);
- if (freeAudioIndex != -1)
- {
- char *hurtSfx[10] = {"Hurt_1", "Hurt_2",
- "Hurt_3", "Hurt_hows_this",
- "Hurt_battlecry", "Hurt_ow",
- "Hurt_uh_oh", "Hurt_ugh",
- "Hurt_woah", "Hurt_yearning"};
-
- i32 hurtSfxIndex = rand() % ARRAY_COUNT(hurtSfx);
-
- audio_playVorbis(
- arena, audioManager,
- &defender->audioRenderer[freeAudioIndex],
- asset_getVorbis(assetManager, hurtSfx[hurtSfxIndex]),
- 1);
- }
- }
- else if (attacker->stats->queuedAttack ==
- entityattack_claudeEnergySword)
- {
- i32 freeAudioIndex = entityGetFreeAudioRendererIndex(attacker);
- if (freeAudioIndex != -1)
- {
- audio_playVorbis(
- arena, audioManager,
- &attacker->audioRenderer[freeAudioIndex],
- asset_getVorbis(assetManager, "Attack_energy_sword"),
- 1);
- }
- }
- else if (attacker->stats->queuedAttack ==
- entityattack_claudeAirSlash)
- {
- i32 freeAudioIndex = entityGetFreeAudioRendererIndex(attacker);
- if (freeAudioIndex != -1)
- {
- audio_playVorbis(
- arena, audioManager,
- &attacker->audioRenderer[freeAudioIndex],
- asset_getVorbis(assetManager, "Attack_air_slash"),
- 1);
- }
- }
- else if (attacker->stats->queuedAttack ==
- entityattack_claudeDragonHowl)
- {
- i32 freeAudioIndex = entityGetFreeAudioRendererIndex(attacker);
- if (freeAudioIndex != -1)
- {
- audio_playVorbis(
- arena, audioManager,
- &attacker->audioRenderer[freeAudioIndex],
- asset_getVorbis(assetManager, "Attack_Dragon_howl"),
- 1);
- }
- }
- else if (attacker->stats->queuedAttack ==
- entityattack_claudeRipperBlast)
- {
- i32 freeAudioIndex = entityGetFreeAudioRendererIndex(attacker);
- if (freeAudioIndex != -1)
- {
- audio_playVorbis(
- arena, audioManager,
- &attacker->audioRenderer[freeAudioIndex],
- asset_getVorbis(assetManager, "Attack_tear_into_pieces"),
- 1);
- }
- }
- else
- {
- //ASSERT(INVALID_CODE_PATH);
- }
-
- attacker->stats->queuedAttack = entityattack_invalid;
-
- /* Get first free string position and store the damage str data */
- for (i32 i = 0; i < ARRAY_COUNT(battleState.damageDisplay); i++)
- {
- if (battleState.damageDisplay[i].lifetime <= 0.0f)
- {
- common_memset(
- battleState.damageDisplay[i].damageStr, 0,
- ARRAY_COUNT(battleState.damageDisplay[i].damageStr));
-
- 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));
-
- break;
- }
- }
- 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:
- {
-#ifdef DEGINE_DEBUG
- DEBUG_LOG("Entity died: being deleted");
-#endif
- if (!event.data) continue;
-
- Entity *entity = (CAST(Entity *) event.data);
- for (i32 i = 0; i < entity->numAudioRenderers; i++)
- {
- audio_stopVorbis(&state->arena_, audioManager,
- &entity->audioRenderer[i]);
- }
- entity_clearData(&state->arena_, world, entity);
- numDeadEntities++;
-
- for (i32 i = 0; i < entity->numChilds; i++)
- {
- Entity *child = entity_get(world, entity->childIds[i]);
- if (child)
- {
- for (i32 i = 0; i < child->numAudioRenderers; i++)
- {
- audio_stopVorbis(&state->arena_, audioManager,
- &child->audioRenderer[i]);
- }
- entity_clearData(&state->arena_, world, child);
- numDeadEntities++;
- }
- else
- {
- DEBUG_LOG("Entity child expected but not found");
- }
- }
- break;
- }
- default:
- {
- break;
- }
- }
- }
- eventQueue->numEvents = 0;
-
- /*
- ****************************
- * Update World From Results
- ****************************
- */
- // TODO(doyle): Dead hero not accounted for here
- Entity *hero = getHeroEntity(world);
- if (world->numEntitiesInBattle > 0)
- {
- // NOTE(doyle): If battle entities is 1 then only the hero left
- if (hero->state == entitystate_battle &&
- world->numEntitiesInBattle == 1)
- {
- entityStateSwitch(eventQueue, world, hero, entitystate_idle);
- }
- else if (hero->state != entitystate_attack)
- {
- entityStateSwitch(eventQueue, world, hero, entitystate_battle);
- }
- }
- else
- {
- if (hero->state == entitystate_battle)
- {
- hero->state = entitystate_idle;
- world->entityIdInBattle[hero->id] = FALSE;
- entity_setActiveAnim(eventQueue, hero, "claudeIdle");
- }
- hero->stats->entityIdToAttack = -1;
- hero->stats->actionTimer = hero->stats->actionRate;
- hero->stats->busyDuration = 0;
- }
-
- sortWorldEntityList(world);
- world->freeEntityIndex -= numDeadEntities;
-
- /*
- ********************
- * UI Rendering Code
- ********************
- */
- /* 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, transientArena, camera, font,
- damageString, damagePos, V2(0, 0), 0,
- V4(1, 1, 1, lifetime));
- }
- }
-
- // INIT IMGUI
- state->uiState.hotItem = 0;
-
- /* Draw ui */
- if (state->uiState.keyChar == keycode_i)
- {
- state->config.showStatMenu =
- (state->config.showStatMenu == TRUE) ? FALSE : TRUE;
- }
-
- if (state->config.showStatMenu)
- {
- WindowState *statWindow = &state->uiState.statWindow;
- userInterface_window(&state->uiState, transientArena, assetManager,
- renderer, font, state->input, statWindow);
- }
-
- /* Draw debug window */
- WindowState *debugWindow = &state->uiState.debugWindow;
- i32 activeId =
- userInterface_window(&state->uiState, transientArena, assetManager,
- renderer, font, state->input, debugWindow);
-
- // TODO(doyle): Name lookup to user interface id
- if (activeId == 1)
- {
- state->config.playWorldAudio =
- (state->config.playWorldAudio == TRUE) ? FALSE : TRUE;
- }
- else if (activeId == 2)
- {
- state->config.showDebugDisplay =
- (state->config.showDebugDisplay == TRUE) ? FALSE : TRUE;
- }
-
- // RESET IMGUI
- if (!state->input.keys[keycode_mouseLeft].endedDown)
- state->uiState.activeItem = 0;
- else if (state->uiState.activeItem == 0)
- state->uiState.activeItem = -1;
-
- if (state->uiState.keyEntered == keycode_tab) state->uiState.kbdItem = 0;
- state->uiState.keyEntered = keycode_null;
- state->uiState.keyChar = keycode_null;
-
- /* Draw hero avatar */
- TexAtlas *heroAtlas =
- asset_getTexAtlas(assetManager, "ClaudeSprite.png");
- SubTexture heroAvatarRect =
- asset_getAtlasSubTex(heroAtlas, "ClaudeSprite_Avatar_01");
- v2 heroAvatarP = V2(10.0f, (renderer->size.h * 0.5f) -
- (0.5f * heroAvatarRect.rect.size.h));
-
- // TODO(doyle): Use rect in rendering not V4
- v4 heroAvatarTexRect = {0};
- heroAvatarTexRect.vec2[0] = heroAvatarRect.rect.pos;
- heroAvatarTexRect.vec2[1] =
- v2_add(heroAvatarRect.rect.pos, heroAvatarRect.rect.size);
-
- RenderTex heroRenderTex = {hero->tex, heroAvatarTexRect};
- renderer_staticRect(renderer, heroAvatarP, heroAvatarRect.rect.size, V2(0, 0), 0,
- heroRenderTex, V4(1, 1, 1, 1));
-
- char heroAvatarStr[20];
- snprintf(heroAvatarStr, ARRAY_COUNT(heroAvatarStr), "HP: %3.0f/%3.0f",
- hero->stats->health, hero->stats->maxHealth);
- f32 strLenInPixels =
- CAST(f32)(font->maxSize.w * common_strlen(heroAvatarStr));
- v2 strPos =
- V2(heroAvatarP.x, heroAvatarP.y - (0.5f * heroAvatarRect.rect.size.h));
- renderer_staticString(&state->renderer, transientArena, font, heroAvatarStr,
- strPos, V2(0, 0), 0, V4(0, 0, 1, 1));
-
- renderer_staticString(&state->renderer, transientArena, font, heroAvatarStr,
- strPos, V2(0, 0), 0, V4(0, 0, 1, 1));
-
- for (i32 i = 0; i < world->maxEntities; i++)
- {
- Entity *entity = &world->entities[i];
- if (entity->id == hero->id)
- continue;
-
- if (entity->state == entitystate_attack ||
- entity->state == entitystate_battle)
- {
- v2 difference = v2_sub(entity->pos, hero->pos);
- f32 angle = math_atan2f(difference.y, difference.x);
-
- v2 heroCenter = v2_add(hero->pos, v2_scale(hero->hitbox, 0.5f));
- RenderTex renderTex = renderer_createNullRenderTex(assetManager);
- f32 distance = v2_magnitude(hero->pos, entity->pos);
- v2 size = V2(distance, 2.0f);
- renderer_rect(&state->renderer, camera, heroCenter,
- size, V2(0, 0), angle, renderTex,
- V4(1, 0, 0, 1.0f));
- }
- }
-
- for (i32 i = 0; i < keycode_count; i++)
- {
- state->input.keys[i].oldHalfTransitionCount =
- state->input.keys[i].newHalfTransitionCount;
- }
-
- /*
- ********************
- * DEBUG CODE
- ********************
- */
-#ifdef DENGINE_DEBUG
- for (i32 i = 0; i < world->freeEntityIndex-1; i++)
- {
- ASSERT(world->entities[i].type != entitytype_null);
- ASSERT(world->entities[i].id < world->entities[i+1].id);
- }
-#endif
-
-#ifdef DENGINE_DEBUG
- if (state->config.showDebugDisplay)
- {
- debug_drawUi(state, dt);
- }
-#endif
-
- renderer_renderGroups(renderer);
-}
diff --git a/src/build.bat b/src/build.bat
index 6cd7464..7215d53 100644
--- a/src/build.bat
+++ b/src/build.bat
@@ -1,4 +1,13 @@
@echo OFF
+
+REM Build tags file
+ctags -R
+
+REM Check if build tool is on path
+REM >nul, 2>nul will remove the output text from the where command
+where cl.exe >nul 2>nul
+if %errorlevel%==1 call msvc86.bat
+
REM Drop compilation files into build folder
IF NOT EXIST ..\bin mkdir ..\bin
pushd ..\bin
diff --git a/src/dengine.c b/src/dengine.c
index a276c8f..8a10878 100644
--- a/src/dengine.c
+++ b/src/dengine.c
@@ -3,7 +3,8 @@
#include "Dengine/Debug.h"
#include "Dengine/Math.h"
#include "Dengine/OpenGL.h"
-#include "Dengine/WorldTraveller.h"
+#include "Dengine/MemoryArena.h"
+#include "Dengine/Asteroid.h"
INTERNAL inline void processKey(KeyState *state, int action)
{
@@ -142,6 +143,7 @@ i32 main(void)
i32 frameBufferWidth, frameBufferHeight;
glfwGetFramebufferSize(window, &frameBufferWidth, &frameBufferHeight);
glViewport(0, 0, frameBufferWidth, frameBufferHeight);
+ v2 windowSize = V2i(frameBufferWidth, frameBufferHeight);
glfwSetKeyCallback(window, keyCallback);
glfwSetCursorPosCallback(window, mouseCallback);
@@ -161,9 +163,8 @@ i32 main(void)
*******************
*/
Memory memory = {0};
-
- size_t persistentSize = MEGABYTES(128);
- size_t transientSize = MEGABYTES(128);
+ MemoryIndex persistentSize = MEGABYTES(128);
+ MemoryIndex transientSize = MEGABYTES(128);
memory.persistentSize = persistentSize;
memory.persistent = PLATFORM_MEM_ALLOC_(NULL, persistentSize, u8);
@@ -171,15 +172,8 @@ i32 main(void)
memory.transientSize = transientSize;
memory.transient = PLATFORM_MEM_ALLOC_(NULL, transientSize, u8);
- GameState worldTraveller = {0};
- worldTraveller_gameInit(&worldTraveller,
- V2i(frameBufferWidth, frameBufferHeight), &memory);
-#ifdef DENGINE_DEBUG
- debug_init(&worldTraveller.arena_, V2i(windowWidth, windowHeight),
- worldTraveller.assetManager.font);
-#endif
-
- glfwSetWindowUserPointer(window, CAST(void *)(&worldTraveller));
+ GameState gameState = {0};
+ glfwSetWindowUserPointer(window, CAST(void *)(&gameState));
/*
*******************
@@ -206,10 +200,11 @@ i32 main(void)
glfwPollEvents();
/* Rendering commands here*/
- glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- worldTraveller_gameUpdateAndRender(&worldTraveller, secondsElapsed);
+ asteroid_gameUpdateAndRender(&gameState, &memory, windowSize,
+ secondsElapsed);
GL_CHECK_ERROR();
/* Swap the buffers */
@@ -235,14 +230,10 @@ i32 main(void)
f32 msPerFrame = secondsElapsed * 1000.0f;
f32 framesPerSecond = 1.0f / secondsElapsed;
- i32 entityCount =
- worldTraveller.world[worldTraveller.currWorldIndex]
- .freeEntityIndex;
-
char textBuffer[256];
snprintf(textBuffer, ARRAY_COUNT(textBuffer),
"Dengine | %f ms/f | %f fps | Entity Count: %d",
- msPerFrame, framesPerSecond, entityCount);
+ msPerFrame, framesPerSecond, 0);
glfwSetWindowTitle(window, textBuffer);
titleUpdateFrequencyInSeconds = 0.5f;
diff --git a/src/include/Dengine/Assets.h b/src/include/Dengine/Assets.h
index 67466f6..f07635b 100644
--- a/src/include/Dengine/Assets.h
+++ b/src/include/Dengine/Assets.h
@@ -94,7 +94,6 @@ typedef struct AudioVorbis
* Texture Assets
*********************************
*/
-
typedef struct SubTexture
{
Rect rect;
diff --git a/src/include/Dengine/Asteroid.h b/src/include/Dengine/Asteroid.h
new file mode 100644
index 0000000..54a9523
--- /dev/null
+++ b/src/include/Dengine/Asteroid.h
@@ -0,0 +1,31 @@
+#ifndef ASTEROID_H
+#define ASTEROID_H
+
+#include "Dengine/AssetManager.h"
+#include "Dengine/Common.h"
+#include "Dengine/Entity.h"
+#include "Dengine/MemoryArena.h"
+#include "Dengine/Platform.h"
+#include "Dengine/Renderer.h"
+
+typedef struct GameState {
+ b32 init;
+
+ Entity entityList[1024];
+ i32 entityIndex;
+
+ Rect camera;
+
+ AssetManager assetManager;
+ KeyInput input;
+
+ MemoryArena_ transientArena;
+ MemoryArena_ persistentArena;
+
+ Renderer renderer;
+} GameState;
+
+void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
+ v2 windowSize, f32 dt);
+
+#endif
diff --git a/src/include/Dengine/Common.h b/src/include/Dengine/Common.h
index 5281a5c..bd525f0 100644
--- a/src/include/Dengine/Common.h
+++ b/src/include/Dengine/Common.h
@@ -14,6 +14,8 @@ typedef i32 b32;
typedef float f32;
typedef double f64;
+typedef size_t MemoryIndex;
+
#define TRUE 1
#define FALSE 0
diff --git a/src/include/Dengine/Entity.h b/src/include/Dengine/Entity.h
index 842d488..c90f30b 100644
--- a/src/include/Dengine/Entity.h
+++ b/src/include/Dengine/Entity.h
@@ -1,17 +1,10 @@
-#ifndef DENGINE_ENTITY_H
-#define DENGINE_ENTITY_H
+#ifndef ENTITY_H
+#define ENTITY_H
-#include "Dengine/Common.h"
-#include "Dengine/Math.h"
#include "Dengine/Assets.h"
+#include "Dengine/Common.h"
-typedef struct AssetManager AssetManager;
typedef struct AudioRenderer AudioRenderer;
-typedef struct MemoryArena MemoryArena_;
-typedef struct World World;
-typedef struct EventQueue EventQueue;
-
-typedef struct Entity Entity;
enum Direction
{
@@ -19,63 +12,17 @@ enum Direction
direction_west,
direction_south,
direction_east,
- direction_num,
direction_null,
+ direction_num,
};
enum EntityType
{
- entitytype_null,
- entitytype_hero,
- entitytype_weapon,
- entitytype_projectile,
- entitytype_attackObject,
- entitytype_npc,
- entitytype_mob,
- entitytype_tile,
- entitytype_soundscape,
+ entitytype_invalid,
+ entitytype_ship,
entitytype_count,
};
-enum EntityState
-{
- entitystate_idle,
- entitystate_battle,
- entitystate_attack,
- entitystate_dead,
- entitystate_count,
- entitystate_invalid,
-};
-
-enum EntityAttack
-{
- entityattack_claudeAttack,
- entityattack_claudeAttackUp,
- entityattack_claudeAttackDown,
- entityattack_claudeDragonHowl,
- entityattack_claudeEnergySword,
- entityattack_claudeRipperBlast,
- entityattack_claudeAirSlash,
- entityattack_count,
- entityattack_invalid,
-};
-
-typedef struct EntityStats
-{
- f32 maxHealth;
- f32 health;
-
- f32 actionRate;
- f32 actionTimer;
- f32 actionSpdMul;
-
- f32 busyDuration;
- i32 entityIdToAttack;
- enum EntityAttack queuedAttack;
-
- Entity *weapon;
-} EntityStats;
-
typedef struct EntityAnim
{
Animation *anim;
@@ -85,7 +32,7 @@ typedef struct EntityAnim
u32 timesCompleted;
} EntityAnim;
-struct Entity
+typedef struct Entity
{
i32 id;
@@ -102,7 +49,6 @@ struct Entity
b32 invisible;
- enum EntityState state;
enum EntityType type;
enum Direction direction;
@@ -116,32 +62,13 @@ struct Entity
// allow for early-exit in collision check if the entity doesn't collide at
// all
b32 collides;
- enum EntityType collidesWith[entitytype_count];
EntityAnim animList[16];
- i32 currAnimId;
-
- EntityStats *stats;
+ i32 animListIndex;
// TODO(doyle): Audio mixing instead of multiple renderers
AudioRenderer *audioRenderer;
i32 numAudioRenderers;
-};
+} Entity;
-SubTexture entity_getActiveSubTexture(Entity *const entity);
-void entity_setActiveAnim(EventQueue *eventQueue, Entity *const entity,
- const char *const animName);
-void entity_updateAnim(EventQueue *eventQueue, Entity *const entity,
- const f32 dt);
-void entity_addAnim(AssetManager *const assetManager, Entity *const entity,
- const char *const animName);
-Entity *const entity_add(MemoryArena_ *const arena, World *const world,
- const v2 pos, const v2 size, const f32 scale,
- const enum EntityType type,
- const enum Direction direction, Texture *const tex,
- const b32 collides);
-void entity_clearData(MemoryArena_ *const arena, World *const world,
- Entity *const entity);
-Entity *entity_get(World *const world, const i32 entityId);
-i32 entity_getIndex(World *const world, const i32 entityId);
#endif
diff --git a/src/include/Dengine/MemoryArena.h b/src/include/Dengine/MemoryArena.h
index 17f60cd..2e16a38 100644
--- a/src/include/Dengine/MemoryArena.h
+++ b/src/include/Dengine/MemoryArena.h
@@ -5,25 +5,25 @@
typedef struct MemoryArena
{
- size_t size;
- size_t used;
+ MemoryIndex size;
+ MemoryIndex used;
u8 *base;
} MemoryArena_;
typedef struct Memory
{
void *persistent;
- size_t persistentSize;
+ MemoryIndex persistentSize;
void *transient;
- size_t transientSize;
+ MemoryIndex transientSize;
b32 init;
} Memory;
#define MEMORY_PUSH_STRUCT(arena, type) (type *)memory_pushBytes(arena, sizeof(type))
#define MEMORY_PUSH_ARRAY(arena, count, type) (type *)memory_pushBytes(arena, (count)*sizeof(type))
-inline void *memory_pushBytes(MemoryArena_ *arena, size_t size)
+inline void *memory_pushBytes(MemoryArena_ *arena, MemoryIndex size)
{
ASSERT((arena->used + size) <= arena->size);
void *result = arena->base + arena->used;
@@ -32,6 +32,6 @@ inline void *memory_pushBytes(MemoryArena_ *arena, size_t size)
return result;
}
-void memory_arenaInit(MemoryArena_ *arena, void *base, size_t size);
+void memory_arenaInit(MemoryArena_ *arena, void *base, MemoryIndex size);
#endif
diff --git a/src/include/Dengine/Platform.h b/src/include/Dengine/Platform.h
index 01e2eb6..159cff2 100644
--- a/src/include/Dengine/Platform.h
+++ b/src/include/Dengine/Platform.h
@@ -140,14 +140,16 @@ typedef struct PlatformFileRead
} PlatformFileRead;
// TODO(doyle): Create own custom memory allocator
-#define PLATFORM_MEM_FREE_(arena, ptr, bytes) platform_memoryFree(arena, CAST(void *) ptr, bytes)
+#define PLATFORM_MEM_FREE_(arena, ptr, bytes) \
+ platform_memoryFree(arena, CAST(void *) ptr, bytes)
// TODO(doyle): numBytes in mem free is temporary until we create custom
// allocator since we haven't put in a system to track memory usage per
// allocation
-void platform_memoryFree(MemoryArena_ *arena, void *data, i32 numBytes);
+void platform_memoryFree(MemoryArena_ *arena, void *data, MemoryIndex numBytes);
-#define PLATFORM_MEM_ALLOC_(arena, num, type) CAST(type *) platform_memoryAlloc(arena, num * sizeof(type))
-void *platform_memoryAlloc(MemoryArena_ *arena, i32 numBytes);
+#define PLATFORM_MEM_ALLOC_(arena, num, type) \
+ CAST(type *) platform_memoryAlloc(arena, num * sizeof(type))
+void *platform_memoryAlloc(MemoryArena_ *arena, MemoryIndex numBytes);
void platform_closeFileRead(MemoryArena_ *arena, PlatformFileRead *file);
i32 platform_readFileToBuffer(MemoryArena_ *arena, const char *const filePath,
diff --git a/src/include/Dengine/Renderer.h b/src/include/Dengine/Renderer.h
index aad3dee..fa6f2df 100644
--- a/src/include/Dengine/Renderer.h
+++ b/src/include/Dengine/Renderer.h
@@ -6,8 +6,8 @@
/* Forward Declaration */
typedef struct AssetManager AssetManager;
-typedef struct Entity Entity;
typedef struct Font Font;
+typedef struct Entity Entity;
typedef struct MemoryArena MemoryArena_;
typedef struct Shader Shader;
typedef struct Texture Texture;
diff --git a/src/include/Dengine/WorldTraveller.h b/src/include/Dengine/WorldTraveller.h
deleted file mode 100644
index 7f38bfc..0000000
--- a/src/include/Dengine/WorldTraveller.h
+++ /dev/null
@@ -1,109 +0,0 @@
-#ifndef WORLDTRAVELLER_GAME_H
-#define WORLDTRAVELLER_GAME_H
-
-#include "Dengine/AssetManager.h"
-#include "Dengine/Audio.h"
-#include "Dengine/Common.h"
-#include "Dengine/Math.h"
-#include "Dengine/MemoryArena.h"
-#include "Dengine/Platform.h"
-#include "Dengine/Renderer.h"
-#include "Dengine/UserInterface.h"
-
-#define NUM_KEYS 1024
-#define METERS_TO_PIXEL 240
-
-/* Forward declaration */
-typedef struct Entity Entity;
-
-enum EventType
-{
- eventtype_null = 0,
- eventtype_start_attack,
- eventtype_end_attack,
- eventtype_start_anim,
- eventtype_end_anim,
- eventtype_entity_died,
- eventtype_count,
-};
-
-typedef struct Event
-{
- enum EventType type;
- void *data;
-} Event;
-
-typedef struct EventQueue
-{
- Event queue[1024];
- i32 numEvents;
-} EventQueue;
-
-enum RectBaseline
-{
- rectbaseline_top,
- rectbaseline_topLeft,
- rectbaseline_topRight,
- rectbaseline_bottom,
- rectbaseline_bottomRight,
- rectbaseline_bottomLeft,
- rectbaseline_left,
- rectbaseline_right,
- rectbaseline_center,
- rectbaseline_count,
-
-};
-
-typedef struct Config
-{
- b32 playWorldAudio;
- b32 showStatMenu;
- b32 showDebugDisplay;
-} Config;
-
-typedef struct World
-{
- Entity *entities;
- i32 maxEntities;
- b32 *entityIdInBattle;
- i32 numEntitiesInBattle;
-
- i32 cameraFollowingId;
- v2 cameraPos; // In pixels
- v4 bounds; // In pixels
-
- i32 heroId;
- i32 freeEntityIndex;
- u32 uniqueIdAccumulator;
-
- Entity *soundscape;
-} World;
-
-typedef struct GameState
-{
- Memory *memory;
- MemoryArena_ arena_;
- MemoryArena_ transientArena;
-
- enum State state;
- KeyInput input;
- v2 mouse;
-
- Renderer renderer;
-
- World world[4];
- i32 currWorldIndex;
- i32 tileSize;
-
- AssetManager assetManager;
- AudioManager audioManager;
- Config config;
- UiState uiState;
- EventQueue eventQueue;
-} GameState;
-
-void worldTraveller_gameInit(GameState *state, v2 windowSize, Memory *memory);
-void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt);
-void worldTraveller_registerEvent(EventQueue *eventQueue, enum EventType type,
- void *data);
-#endif