From 8a3886a60e8cd5347f3d79cec9e361346947f6df Mon Sep 17 00:00:00 2001 From: Doyle Thai Date: Thu, 28 Jul 2016 14:33:58 +1000 Subject: [PATCH] Separate entity functions to own file --- Dengine.vcxproj | 1 + Dengine.vcxproj.filters | 3 + src/Entity.c | 161 ++++++++++++++++++++++++++ src/WorldTraveller.c | 218 ++++++----------------------------- src/include/Dengine/Entity.h | 17 ++- 5 files changed, 213 insertions(+), 187 deletions(-) create mode 100644 src/Entity.c diff --git a/Dengine.vcxproj b/Dengine.vcxproj index 2c138a2..3c80619 100644 --- a/Dengine.vcxproj +++ b/Dengine.vcxproj @@ -125,6 +125,7 @@ + diff --git a/Dengine.vcxproj.filters b/Dengine.vcxproj.filters index d14e0fc..60e25c8 100644 --- a/Dengine.vcxproj.filters +++ b/Dengine.vcxproj.filters @@ -48,6 +48,9 @@ Source Files + + Source Files + diff --git a/src/Entity.c b/src/Entity.c new file mode 100644 index 0000000..2dd9b94 --- /dev/null +++ b/src/Entity.c @@ -0,0 +1,161 @@ +#include "Dengine/AssetManager.h" +#include "Dengine/MemoryArena.h" +#include "Dengine/Platform.h" +#include "Dengine/Debug.h" + +#include "Dengine/Entity.h" + +#include "WorldTraveller/WorldTraveller.h" + +void entity_setActiveAnim(Entity *entity, enum AnimList animId) +{ +#ifdef DENGINE_DEBUG + ASSERT(animId < animlist_count); + ASSERT(entity->anim[animId].anim); +#endif + + /* Reset current anim data */ + EntityAnim_ *currAnim = &entity->anim[entity->currAnimId]; + currAnim->currDuration = currAnim->anim->frameDuration; + currAnim->currFrame = 0; + + /* Set entity active animation */ + entity->currAnimId = animId; +} + +void entity_updateAnim(Entity *entity, f32 dt) +{ + if (!entity->tex) return; + + // TODO(doyle): Recheck why we have this twice + EntityAnim_ *entityAnim = &entity->anim[entity->currAnimId]; + Animation anim = *entityAnim->anim; + i32 frameIndex = anim.frameIndex[entityAnim->currFrame]; + v4 texRect = anim.atlas->texRect[frameIndex]; + + entityAnim->currDuration -= dt; + if (entityAnim->currDuration <= 0.0f) + { + entityAnim->currFrame++; + entityAnim->currFrame = entityAnim->currFrame % anim.numFrames; + frameIndex = entityAnim->anim->frameIndex[entityAnim->currFrame]; + texRect = anim.atlas->texRect[frameIndex]; + entityAnim->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: + entity->renderSize = math_getRectSize(texRect); + default: + break; + } +} + +void entity_addAnim(AssetManager *assetManager, Entity *entity, i32 animId) +{ + Animation *anim = asset_getAnim(assetManager, animId); + entity->anim[animId].anim = anim; + entity->anim[animId].currFrame = 0; + entity->anim[animId].currDuration = anim->frameDuration; +} + +void entity_addGenericMob(MemoryArena *arena, AssetManager *assetManager, + World *world, v2 pos) +{ +#ifdef DENGINE_DEBUG + DEBUG_LOG("Mob entity spawned"); +#endif + + Entity *hero = &world->entities[world->heroIndex]; + + v2 size = V2(58.0f, 98.0f); + enum EntityType type = entitytype_mob; + enum Direction dir = direction_west; + Texture *tex = asset_getTexture(assetManager, texlist_hero); + b32 collides = TRUE; + Entity *mob = entity_add(arena, world, pos, size, type, dir, tex, collides); + + /* Populate mob animation references */ + entity_addAnim(assetManager, mob, animlist_hero_idle); + entity_addAnim(assetManager, mob, animlist_hero_walk); + entity_addAnim(assetManager, mob, animlist_hero_wave); + entity_addAnim(assetManager, mob, animlist_hero_battlePose); + entity_addAnim(assetManager, mob, animlist_hero_tackle); + mob->currAnimId = animlist_hero_idle; + +} + +Entity *entity_add(MemoryArena *arena, World *world, v2 pos, v2 size, + enum EntityType type, enum Direction direction, + Texture *tex, 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.hitboxSize = size; + entity.renderSize = size; + entity.type = type; + entity.direction = direction; + entity.tex = tex; + entity.collides = collides; + + switch(type) + { + case entitytype_hero: + entity.stats = PLATFORM_MEM_ALLOC(arena, 1, 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; + case entitytype_mob: + { + entity.stats = PLATFORM_MEM_ALLOC(arena, 1, 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_delete(MemoryArena *arena, World *world, i32 entityIndex) +{ + Entity *entity = &world->entities[entityIndex]; + PLATFORM_MEM_FREE(arena, entity->stats, sizeof(EntityStats)); + + // TODO(doyle): Inefficient shuffle down all elements + for (i32 i = entityIndex; i < world->freeEntityIndex-1; i++) + world->entities[i] = world->entities[i+1]; + + world->freeEntityIndex--; +} diff --git a/src/WorldTraveller.c b/src/WorldTraveller.c index a08a12b..e68a20c 100644 --- a/src/WorldTraveller.c +++ b/src/WorldTraveller.c @@ -1,8 +1,9 @@ #include "WorldTraveller/WorldTraveller.h" -#include "Dengine/Debug.h" -#include "Dengine/Platform.h" #include "Dengine/Audio.h" +#include "Dengine/Debug.h" +#include "Dengine/Entity.h" +#include "Dengine/Platform.h" enum State { @@ -11,82 +12,12 @@ enum State state_win, }; -INTERNAL Entity *getHeroEntity(World *world) +Entity *getHeroEntity(World *world) { Entity *result = &world->entities[world->heroIndex]; return result; } -INTERNAL Entity *addEntity(MemoryArena *arena, World *world, v2 pos, v2 size, - enum EntityType type, enum Direction direction, - Texture *tex, 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.hitboxSize = size; - entity.renderSize = size; - entity.type = type; - entity.direction = direction; - entity.tex = tex; - entity.collides = collides; - - switch(type) - { - case entitytype_hero: - entity.stats = PLATFORM_MEM_ALLOC(arena, 1, 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; - case entitytype_mob: - { - entity.stats = PLATFORM_MEM_ALLOC(arena, 1, 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; -} - -INTERNAL void deleteEntity(MemoryArena *arena, World *world, i32 entityIndex) -{ - Entity *entity = &world->entities[entityIndex]; - PLATFORM_MEM_FREE(arena, entity->stats, sizeof(EntityStats)); - - // TODO(doyle): Inefficient shuffle down all elements - for (i32 i = entityIndex; i < world->freeEntityIndex-1; i++) - world->entities[i] = world->entities[i+1]; - - world->freeEntityIndex--; -} - INTERNAL void rendererInit(GameState *state, v2 windowSize) { AssetManager *assetManager = &state->assetManager; @@ -126,40 +57,6 @@ INTERNAL void rendererInit(GameState *state, v2 windowSize) GL_CHECK_ERROR(); } -INTERNAL void addAnim(AssetManager *assetManager, i32 animId, Entity *entity) -{ - Animation *anim = asset_getAnim(assetManager, animId); - entity->anim[animId].anim = anim; - entity->anim[animId].currFrame = 0; - entity->anim[animId].currDuration = anim->frameDuration; -} - -INTERNAL void addGenericMob(MemoryArena *arena, AssetManager *assetManager, - World *world, v2 pos) -{ -#ifdef DENGINE_DEBUG - DEBUG_LOG("Mob entity spawned"); -#endif - - Entity *hero = &world->entities[world->heroIndex]; - - v2 size = V2(58.0f, 98.0f); - enum EntityType type = entitytype_mob; - enum Direction dir = direction_west; - Texture *tex = asset_getTexture(assetManager, texlist_hero); - b32 collides = TRUE; - Entity *mob = addEntity(arena, world, pos, size, type, dir, tex, collides); - - /* Populate mob animation references */ - addAnim(assetManager, animlist_hero_idle, mob); - addAnim(assetManager, animlist_hero_walk, mob); - addAnim(assetManager, animlist_hero_wave, mob); - addAnim(assetManager, animlist_hero_battlePose, mob); - addAnim(assetManager, animlist_hero_tackle, mob); - mob->currAnimId = animlist_hero_idle; - -} - // TODO(doyle): Remove and implement own random generator! #include #include @@ -345,10 +242,10 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize) enum Direction dir = direction_null; Texture *tex = asset_getTexture(assetManager, world->texType); b32 collides = FALSE; - Entity *tile = addEntity(arena, world, pos, size, type, dir, - tex, collides); + Entity *tile = entity_add(arena, world, pos, size, type, dir, + tex, collides); - addAnim(assetManager, animlist_terrain, tile); + entity_addAnim(assetManager, tile, animlist_terrain); tile->currAnimId = animlist_terrain; } } @@ -366,11 +263,11 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize) Texture *tex = NULL; b32 collides = FALSE; Entity *soundscape = - addEntity(arena, world, pos, size, type, dir, tex, collides); + entity_add(arena, world, pos, size, type, dir, tex, collides); world->soundscape = soundscape; - soundscape->audio = PLATFORM_MEM_ALLOC(arena, 1, AudioRenderer); - soundscape->audio->sourceIndex = AUDIO_SOURCE_UNASSIGNED; + soundscape->audioRenderer = PLATFORM_MEM_ALLOC(arena, 1, AudioRenderer); + soundscape->audioRenderer->sourceIndex = AUDIO_SOURCE_UNASSIGNED; /* Init hero entity */ world->heroIndex = world->freeEntityIndex; @@ -381,14 +278,14 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize) dir = direction_east; tex = asset_getTexture(assetManager, texlist_hero); collides = TRUE; - Entity *hero = addEntity(arena, world, pos, size, type, dir, tex, collides); + Entity *hero = entity_add(arena, world, pos, size, type, dir, tex, collides); /* Populate hero animation references */ - addAnim(assetManager, animlist_hero_idle, hero); - addAnim(assetManager, animlist_hero_walk, hero); - addAnim(assetManager, animlist_hero_wave, hero); - addAnim(assetManager, animlist_hero_battlePose, hero); - addAnim(assetManager, animlist_hero_tackle, hero); + entity_addAnim(assetManager, hero, animlist_hero_idle); + entity_addAnim(assetManager, hero, animlist_hero_walk); + entity_addAnim(assetManager, hero, animlist_hero_wave); + entity_addAnim(assetManager, hero, animlist_hero_battlePose); + entity_addAnim(assetManager, hero, animlist_hero_tackle); hero->currAnimId = animlist_hero_idle; /* Create a NPC */ @@ -398,16 +295,16 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize) dir = direction_null; tex = hero->tex; collides = FALSE; - Entity *npc = addEntity(arena, world, pos, size, type, dir, tex, collides); + Entity *npc = entity_add(arena, world, pos, size, type, dir, tex, collides); /* Populate npc animation references */ - addAnim(assetManager, animlist_hero_wave, npc); + entity_addAnim(assetManager, npc, animlist_hero_wave); npc->currAnimId = animlist_hero_wave; /* Create a Mob */ pos = V2(renderer->size.w - (renderer->size.w / 3.0f), CAST(f32) state->tileSize); - addGenericMob(arena, assetManager, world, pos); + entity_addGenericMob(arena, assetManager, world, pos); #ifdef DENGINE_DEBUG DEBUG_LOG("World populated"); #endif @@ -415,23 +312,6 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize) srand(CAST(u32)(time(NULL))); } -INTERNAL inline void setActiveEntityAnim(Entity *entity, - enum AnimList animId) -{ -#ifdef DENGINE_DEBUG - ASSERT(animId < animlist_count); - ASSERT(entity->anim[animId].anim); -#endif - - /* Reset current anim data */ - EntityAnim_ *currAnim = &entity->anim[entity->currAnimId]; - currAnim->currDuration = currAnim->anim->frameDuration; - currAnim->currFrame = 0; - - /* Set entity active animation */ - entity->currAnimId = animId; -} - INTERNAL inline v4 getEntityScreenRect(Entity entity) { v4 result = math_getRect(entity.pos, entity.hitboxSize); @@ -503,7 +383,8 @@ INTERNAL void parseInput(GameState *state, const f32 dt) f32 xModifier = 5.0f - CAST(f32)(rand() % 3); v2 pos = V2(renderer->size.w - (renderer->size.w / xModifier), yPos); - addGenericMob(&state->arena, &state->assetManager, world, pos); + entity_addGenericMob(&state->arena, &state->assetManager, world, + pos); spaceBarWasDown = TRUE; } else if (!state->keys[GLFW_KEY_SPACE]) @@ -522,12 +403,12 @@ INTERNAL void parseInput(GameState *state, const f32 dt) hero->dPos = V2(0.0f, 0.0f); if (hero->currAnimId == animlist_hero_walk) { - setActiveEntityAnim(hero, animlist_hero_idle); + entity_setActiveAnim(hero, animlist_hero_idle); } } else if (hero->currAnimId == animlist_hero_idle) { - setActiveEntityAnim(hero, animlist_hero_walk); + entity_setActiveAnim(hero, animlist_hero_walk); } f32 heroSpeed = 6.2f * METERS_TO_PIXEL; @@ -598,39 +479,6 @@ INTERNAL void parseInput(GameState *state, const f32 dt) } } -INTERNAL void updateEntityAnim(Entity *entity, f32 dt) -{ - if (!entity->tex) return; - - // TODO(doyle): Recheck why we have this twice - EntityAnim_ *entityAnim = &entity->anim[entity->currAnimId]; - Animation anim = *entityAnim->anim; - i32 frameIndex = anim.frameIndex[entityAnim->currFrame]; - v4 texRect = anim.atlas->texRect[frameIndex]; - - entityAnim->currDuration -= dt; - if (entityAnim->currDuration <= 0.0f) - { - entityAnim->currFrame++; - entityAnim->currFrame = entityAnim->currFrame % anim.numFrames; - frameIndex = entityAnim->anim->frameIndex[entityAnim->currFrame]; - texRect = anim.atlas->texRect[frameIndex]; - entityAnim->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: - entity->renderSize = math_getRectSize(texRect); - default: - break; - } -} - INTERNAL v4 createCameraBounds(World *world, v2 size) { v4 result = math_getRect(world->cameraPos, size); @@ -723,7 +571,7 @@ INTERNAL inline void updateWorldBattleEntities(World *world, Entity *entity, INTERNAL inline void resetEntityState(World *world, Entity *entity) { updateWorldBattleEntities(world, entity, ENTITY_NOT_IN_BATTLE); - setActiveEntityAnim(entity, animlist_hero_idle); + entity_setActiveAnim(entity, animlist_hero_idle); entity->stats->busyDuration = 0; entity->stats->actionTimer = entity->stats->actionRate; entity->stats->queuedAttack = entityattack_invalid; @@ -744,7 +592,7 @@ INTERNAL void beginAttack(World *world, Entity *attacker) f32 busyDuration = attackAnim.anim->frameDuration * CAST(f32) attackAnim.anim->numFrames; attacker->stats->busyDuration = busyDuration; - setActiveEntityAnim(attacker, animlist_hero_tackle); + entity_setActiveAnim(attacker, animlist_hero_tackle); if (attacker->direction == direction_east) attacker->dPos.x += (1.0f * METERS_TO_PIXEL); else @@ -859,7 +707,7 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity, // 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: - setActiveEntityAnim(entity, animlist_hero_idle); + entity_setActiveAnim(entity, animlist_hero_idle); entity->stats->busyDuration = 0; entity->stats->actionTimer = entity->stats->actionRate; entity->stats->queuedAttack = entityattack_invalid; @@ -896,7 +744,7 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity, { case entitystate_battle: endAttack(world, entity); - setActiveEntityAnim(entity, animlist_hero_battlePose); + entity_setActiveAnim(entity, animlist_hero_battlePose); entity->stats->actionTimer = entity->stats->actionRate; entity->stats->busyDuration = 0; break; @@ -956,9 +804,9 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) { Entity *const entity = &world->entities[i]; - if (entity->audio) + if (entity->audioRenderer) { - AudioRenderer *audioRenderer = entity->audio; + AudioRenderer *audioRenderer = entity->audioRenderer; if (world->numEntitiesInBattle > 0) { AudioVorbis *battleTheme = @@ -981,7 +829,7 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) } } - audio_updateAndPlay(&state->audioManager, entity->audio); + audio_updateAndPlay(&state->audioManager, entity->audioRenderer); } if (entity->state == entitystate_dead) @@ -1002,7 +850,7 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) // an entity dies #if 1 i32 entityIndexInArray = i; - deleteEntity(&state->arena, world, entityIndexInArray); + entity_delete(&state->arena, world, entityIndexInArray); // TODO(doyle): DeleteEntity moves elements down 1, so account for i i--; @@ -1113,7 +961,7 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) */ if (entity->tex) { - updateEntityAnim(entity, dt); + entity_updateAnim(entity, dt); /* Calculate region to render */ renderer_entity(renderer, cameraBounds, entity, V2(0, 0), 0, V4(1, 1, 1, 1)); @@ -1138,7 +986,7 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) { hero->state = entitystate_idle; world->entityIdInBattle[hero->id] = FALSE; - setActiveEntityAnim(hero, animlist_hero_idle); + entity_setActiveAnim(hero, animlist_hero_idle); } hero->stats->entityIdToAttack = -1; hero->stats->actionTimer = hero->stats->actionRate; diff --git a/src/include/Dengine/Entity.h b/src/include/Dengine/Entity.h index ed1ea5e..79f6c31 100644 --- a/src/include/Dengine/Entity.h +++ b/src/include/Dengine/Entity.h @@ -3,9 +3,12 @@ #include "Dengine/Common.h" #include "Dengine/Math.h" -#include "Dengine/Texture.h" +typedef struct AssetManager AssetManager; typedef struct AudioRenderer AudioRenderer; +typedef struct Texture Texture; +typedef struct Animation Animation; +typedef struct World World; enum Direction { @@ -91,7 +94,17 @@ typedef struct Entity enum AnimList currAnimId; EntityStats *stats; - AudioRenderer *audio; + AudioRenderer *audioRenderer; + i32 numAudioRenderers; } Entity; +void entity_setActiveAnim(Entity *entity, enum AnimList animId); +void entity_updateAnim(Entity *entity, f32 dt); +void entity_addAnim(AssetManager *assetManager, Entity *entity, i32 animId); +void entity_addGenericMob(MemoryArena *arena, AssetManager *assetManager, World *world, + v2 pos); +Entity *entity_add(MemoryArena *arena, World *world, v2 pos, v2 size, + enum EntityType type, enum Direction direction, Texture *tex, + b32 collides); +void entity_delete(MemoryArena *arena, World *world, i32 entityIndex); #endif