From 7cb13b3cf85ac681fa1f8fb733230c2c2cb2d7c0 Mon Sep 17 00:00:00 2001 From: Doyle Thai Date: Thu, 15 Sep 2016 03:20:13 +1000 Subject: [PATCH] Add additional entity struct data Attempting to add child weapon data to an entity has revealed the need for an entity origin to which children start transformations from. Worth exploring scene graphs in the future. --- src/AssetManager.c | 55 +++++++++----- src/Debug.c | 2 +- src/Entity.c | 18 ++++- src/Renderer.c | 21 ++--- src/WorldTraveller.c | 118 ++++++++++++++++------------- src/include/Dengine/AssetManager.h | 3 +- src/include/Dengine/Assets.h | 7 ++ src/include/Dengine/Entity.h | 11 ++- 8 files changed, 145 insertions(+), 90 deletions(-) diff --git a/src/AssetManager.c b/src/AssetManager.c index 5bb4442..6318b9b 100644 --- a/src/AssetManager.c +++ b/src/AssetManager.c @@ -82,16 +82,16 @@ INTERNAL HashTableEntry *const getEntryFromHash(HashTable *const table, * Texture Operations ********************************* */ -INTERNAL Rect *getFreeAtlasSubTexSlot(TexAtlas *const atlas, - MemoryArena *const arena, - const char *const key) +INTERNAL SubTexture *getFreeAtlasSubTexSlot(TexAtlas *const atlas, + MemoryArena *const arena, + const char *const key) { HashTableEntry *entry = getFreeHashSlot(&atlas->subTex, arena, key); if (entry) { - entry->data = PLATFORM_MEM_ALLOC(arena, 1, Rect); - Rect *result = CAST(Rect *)entry->data; + entry->data = PLATFORM_MEM_ALLOC(arena, 1, SubTexture); + SubTexture *result = CAST(SubTexture *)entry->data; return result; } else @@ -100,15 +100,15 @@ INTERNAL Rect *getFreeAtlasSubTexSlot(TexAtlas *const atlas, } } -const Rect asset_getAtlasSubTex(TexAtlas *const atlas, const char *const key) +const SubTexture asset_getAtlasSubTex(TexAtlas *const atlas, const char *const key) { HashTableEntry *entry = getEntryFromHash(&atlas->subTex, key); - Rect result = {0}; + SubTexture result = {0}; if (entry) { - result = *(CAST(Rect *) entry->data); + result = *(CAST(SubTexture *) entry->data); return result; } @@ -638,7 +638,7 @@ INTERNAL void parseXmlTreeToGame(AssetManager *assetManager, MemoryArena *arena, XmlAttribute *subTexAttrib = &atlasChildNode->attribute; char *key = NULL; - Rect subTex = {0}; + SubTexture subTex = {0}; while (subTexAttrib) { @@ -659,7 +659,7 @@ INTERNAL void parseXmlTreeToGame(AssetManager *assetManager, MemoryArena *arena, i32 valueLen = common_strlen(value); i32 intValue = common_atoi(value, valueLen); - subTex.pos.x = CAST(f32) intValue; + subTex.rect.pos.x = CAST(f32) intValue; } else if (common_strcmp(subTexAttrib->name, "y") == 0) @@ -668,7 +668,7 @@ INTERNAL void parseXmlTreeToGame(AssetManager *assetManager, MemoryArena *arena, i32 valueLen = common_strlen(value); i32 intValue = common_atoi(value, valueLen); - subTex.pos.y = CAST(f32) intValue; + subTex.rect.pos.y = CAST(f32) intValue; } else if (common_strcmp(subTexAttrib->name, "width") == 0) @@ -677,7 +677,7 @@ INTERNAL void parseXmlTreeToGame(AssetManager *assetManager, MemoryArena *arena, i32 valueLen = common_strlen(value); i32 intValue = common_atoi(value, valueLen); - subTex.size.w = CAST(f32) intValue; + subTex.rect.size.w = CAST(f32) intValue; } else if (common_strcmp(subTexAttrib->name, "height") == 0) @@ -686,7 +686,25 @@ INTERNAL void parseXmlTreeToGame(AssetManager *assetManager, MemoryArena *arena, i32 valueLen = common_strlen(value); i32 intValue = common_atoi(value, valueLen); - subTex.size.h = CAST(f32) intValue; + subTex.rect.size.h = CAST(f32) intValue; + } + else if (common_strcmp(subTexAttrib->name, + "hand_offset_x") == 0) + { + char *value = subTexAttrib->value; + i32 valueLen = common_strlen(value); + i32 intValue = common_atoi(value, valueLen); + + subTex.offset.x = CAST(f32) intValue; + } + else if (common_strcmp(subTexAttrib->name, + "hand_offset_y") == 0) + { + char *value = subTexAttrib->value; + i32 valueLen = common_strlen(value); + i32 intValue = common_atoi(value, valueLen); + + subTex.offset.y = CAST(f32) intValue; } else { @@ -701,13 +719,14 @@ INTERNAL void parseXmlTreeToGame(AssetManager *assetManager, MemoryArena *arena, // TODO(doyle): XML specifies 0,0 top left, we // prefer 0,0 bottom right, so offset by size since 0,0 // is top left and size creates a bounding box below it - subTex.pos.y = 1024 - subTex.pos.y; - subTex.pos.y -= subTex.size.h; + subTex.rect.pos.y = 1024 - subTex.rect.pos.y; + subTex.rect.pos.y -= subTex.rect.size.h; + subTex.offset.y = subTex.rect.size.h - subTex.offset.y; #ifdef DENGINE_DEBUG ASSERT(key); #endif - Rect *subTexInHash = + SubTexture *subTexInHash = getFreeAtlasSubTexSlot(atlas, arena, key); *subTexInHash = subTex; } @@ -1126,8 +1145,8 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena, // all ascii characters, charToEncode represents the character // 1:1 const char key[2] = {charToEncode, 0}; - Rect *subTex = getFreeAtlasSubTexSlot(fontAtlas, arena, key); - *subTex = CAST(Rect){origin, font->maxSize}; + SubTexture *subTex = getFreeAtlasSubTexSlot(fontAtlas, arena, key); + subTex->rect = CAST(Rect){origin, font->maxSize}; charToEncode++; } diff --git a/src/Debug.c b/src/Debug.c index 43e037d..75d5e3d 100644 --- a/src/Debug.c +++ b/src/Debug.c @@ -377,7 +377,7 @@ void debug_drawUi(GameState *state, f32 dt) if (debugString) { - v2 strPos = v2_add(entity->pos, entity->hitboxSize); + v2 strPos = v2_add(entity->pos, entity->hitbox); i32 indexOfLowerAInMetrics = 'a' - CAST(i32) font->codepointRange.x; strPos.y += font->charMetrics[indexOfLowerAInMetrics].offset.y; diff --git a/src/Entity.c b/src/Entity.c index aff2619..b5b9e80 100644 --- a/src/Entity.c +++ b/src/Entity.c @@ -3,6 +3,16 @@ #include "Dengine/Platform.h" #include "Dengine/WorldTraveller.h" +SubTexture entity_getActiveSubTexture(Entity *const entity) +{ + EntityAnim *entityAnim = &entity->animList[entity->currAnimId]; + Animation *anim = entityAnim->anim; + char *frameName = anim->frameList[entityAnim->currFrame]; + + SubTexture result = asset_getAtlasSubTex(anim->atlas, frameName); + return result; +} + void entity_setActiveAnim(EventQueue *eventQueue, Entity *const entity, const char *const animName) { @@ -71,9 +81,9 @@ void entity_updateAnim(EventQueue *eventQueue, Entity *const entity, case entitytype_weapon: case entitytype_projectile: char *frameName = anim->frameList[currEntityAnim->currFrame]; - Rect texRect = + SubTexture texRect = asset_getAtlasSubTex(anim->atlas, frameName); - entity->renderSize = texRect.size; + entity->size = v2_scale(texRect.rect.size, entity->scale); default: break; } @@ -114,8 +124,8 @@ Entity *const entity_add(MemoryArena *const arena, World *const world, Entity entity = {0}; entity.id = world->uniqueIdAccumulator++; entity.pos = pos; - entity.hitboxSize = size; - entity.renderSize = size; + entity.size = size; + entity.hitbox = size; entity.scale = scale; entity.type = type; entity.direction = direction; diff --git a/src/Renderer.c b/src/Renderer.c index 872480d..44f151f 100644 --- a/src/Renderer.c +++ b/src/Renderer.c @@ -210,13 +210,13 @@ void renderer_string(Renderer *const renderer, MemoryArena *arena, Rect camera, pos.x += charMetric.advance; /* Get texture out */ - Rect charTexRect = + SubTexture charTexRect = asset_getAtlasSubTex(font->atlas, &CAST(char)codepoint); v4 deprecatedTexRect = {0}; - deprecatedTexRect.vec2[0] = charTexRect.pos; + deprecatedTexRect.vec2[0] = charTexRect.rect.pos; deprecatedTexRect.vec2[1] = - v2_add(charTexRect.pos, charTexRect.size); + v2_add(charTexRect.rect.pos, charTexRect.rect.size); flipTexCoord(&deprecatedTexRect, FALSE, TRUE); @@ -244,7 +244,7 @@ void renderer_entity(Renderer *renderer, Rect camera, Entity *entity, // NOTE(doyle): Pos + Size since the origin of an entity is it's bottom left // corner. Add the two together so that the clipping point is the far right // side of the entity - v2 rightAlignedP = v2_add(entity->pos, entity->hitboxSize); + v2 rightAlignedP = v2_add(entity->pos, entity->hitbox); v2 leftAlignedP = entity->pos; if (math_pointInRect(camera, leftAlignedP) || math_pointInRect(camera, rightAlignedP)) @@ -252,14 +252,16 @@ void renderer_entity(Renderer *renderer, Rect camera, Entity *entity, EntityAnim *entityAnim = &entity->animList[entity->currAnimId]; Animation *anim = entityAnim->anim; char *frameName = anim->frameList[entityAnim->currFrame]; - Rect animRect = asset_getAtlasSubTex(anim->atlas, frameName); + SubTexture animRect = asset_getAtlasSubTex(anim->atlas, frameName); // TODO(doyle): Switch to rect v4 animTexRect = {0}; - animTexRect.vec2[0] = animRect.pos; - animTexRect.vec2[1] = v2_add(animRect.pos, animRect.size); + animTexRect.vec2[0] = animRect.rect.pos; + animTexRect.vec2[1] = v2_add(animRect.rect.pos, animRect.rect.size); - if (entity->direction == direction_east) + flipTexCoord(&animTexRect, entity->flipX, entity->flipY); + + if (entity->direction == direction_east) { flipTexCoord(&animTexRect, TRUE, FALSE); } @@ -270,9 +272,8 @@ void renderer_entity(Renderer *renderer, Rect camera, Entity *entity, updateBufferObject(renderer, &entityQuad, 1); v2 posInCameraSpace = v2_sub(entity->pos, camera.pos); - // TODO(doyle): Scale temporarily renderObject(renderer, posInCameraSpace, - v2_scale(entity->renderSize, entity->scale), pivotPoint, + entity->size, pivotPoint, entity->rotation + rotate, color, entity->tex); } } diff --git a/src/WorldTraveller.c b/src/WorldTraveller.c index 7466079..2718bb7 100644 --- a/src/WorldTraveller.c +++ b/src/WorldTraveller.c @@ -301,7 +301,10 @@ INTERNAL void assetInit(GameState *state) claudeAtlas, claudeRipperBlast, numRects, duration); - char *claudeRipperBlastVfx[9] = { + 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", @@ -601,19 +604,17 @@ INTERNAL void entityInit(GameState *state, v2 windowSize) dir = direction_east; tex = asset_getTex(assetManager, "ClaudeSprite.png"); collides = TRUE; + Entity *hero = entity_add(arena, world, pos, size, scale, type, dir, tex, collides); -#if 0 Entity *heroWeapon = - entity_add(arena, world, pos, V2(0, 0), entitytype_weapon, - hero->direction, hero->tex, FALSE); - heroWeapon->rotation = -90.0f; - heroWeapon->invisible = TRUE; + 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; -#endif hero->numAudioRenderers = 4; hero->audioRenderer = @@ -622,8 +623,8 @@ INTERNAL void entityInit(GameState *state, v2 windowSize) for (i32 i = 0; i < hero->numAudioRenderers; i++) hero->audioRenderer[i].sourceIndex = AUDIO_SOURCE_UNASSIGNED; - world->heroId = hero->id; - world->cameraFollowingId = hero->id; + world->heroId = hero->id; + world->cameraFollowingId = hero->id; /* Populate hero animation references */ entity_addAnim(assetManager, hero, "claudeIdle"); @@ -639,11 +640,11 @@ INTERNAL void entityInit(GameState *state, v2 windowSize) entity_addAnim(assetManager, hero, "claudeRipperBlast"); entity_addAnim(assetManager, hero, "claudeAirSlash"); - entity_setActiveAnim(eventQueue, hero, "claudeIdle"); + entity_setActiveAnim(eventQueue, hero, "claudeBattleIdle"); /* Create a NPC */ pos = V2(hero->pos.x * 3, CAST(f32) state->tileSize); - size = hero->hitboxSize; + size = hero->hitbox; type = entitytype_npc; dir = direction_null; tex = hero->tex; @@ -855,7 +856,7 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize) INTERNAL inline v4 getEntityScreenRect(Entity entity) { - v4 result = math_getRect(entity.pos, entity.hitboxSize); + v4 result = math_getRect(entity.pos, entity.hitbox); return result; } @@ -1162,12 +1163,6 @@ INTERNAL void beginAttack(AssetManager *assetManager, MemoryArena *arena, case entityattack_claudeAttack: { entity_setActiveAnim(eventQueue, attacker, "claudeAttack"); - if (attacker->stats->weapon) - { - attacker->stats->weapon->invisible = FALSE; - entity_setActiveAnim(eventQueue, attacker->stats->weapon, - "claudeAttackSlashLeft"); - } if (attacker->direction == direction_east) attacker->dPos.x += (1.0f * METERS_TO_PIXEL); else @@ -1178,12 +1173,6 @@ INTERNAL void beginAttack(AssetManager *assetManager, MemoryArena *arena, case entityattack_claudeAttackUp: { entity_setActiveAnim(eventQueue, attacker, "claudeAttackUp"); - if (attacker->stats->weapon) - { - attacker->stats->weapon->invisible = FALSE; - entity_setActiveAnim(eventQueue, attacker->stats->weapon, - "claudeAttackSlashLeft"); - } if (attacker->direction == direction_east) attacker->dPos.x += (1.0f * METERS_TO_PIXEL); else @@ -1194,12 +1183,6 @@ INTERNAL void beginAttack(AssetManager *assetManager, MemoryArena *arena, case entityattack_claudeAttackDown: { entity_setActiveAnim(eventQueue, attacker, "claudeAttackDown"); - if (attacker->stats->weapon) - { - attacker->stats->weapon->invisible = FALSE; - entity_setActiveAnim(eventQueue, attacker->stats->weapon, - "claudeAttackSlashLeft"); - } if (attacker->direction == direction_east) attacker->dPos.x += (1.0f * METERS_TO_PIXEL); else @@ -1330,12 +1313,6 @@ INTERNAL void endAttack(MemoryArena *arena, EventQueue *eventQueue, case entityattack_claudeAttackUp: case entityattack_claudeAttackDown: // TODO(doyle): Move animation offsets out and into animation type - - if (attacker->stats->weapon) - { - attacker->stats->weapon->invisible = TRUE; - } - if (attacker->direction == direction_east) attacker->dPos.x -= (1.0f * METERS_TO_PIXEL); else @@ -1515,7 +1492,7 @@ INTERNAL b32 checkCollision(Entity *a, Entity *b) b32 result = FALSE; if (a->collides && b->collides && a->collidesWith[b->type]) { - Rect aRect = {a->pos, a->hitboxSize}; + Rect aRect = {a->pos, a->hitbox}; v2 aTopLeftP = getPosRelativeToRect(aRect, V2(0, 0), rectbaseline_topLeft); @@ -1526,7 +1503,7 @@ INTERNAL b32 checkCollision(Entity *a, Entity *b) v2 aBottomRightP = getPosRelativeToRect(aRect, V2(0, 0), rectbaseline_bottomRight); - Rect bRect = {b->pos, b->hitboxSize}; + Rect bRect = {b->pos, b->hitbox}; if (math_pointInRect(bRect, aTopLeftP) || math_pointInRect(bRect, aTopRightP) || @@ -1730,7 +1707,7 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) 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->hitboxSize.x * 0.5f); + offsetFromEntityToCameraOrigin.x += (entity->hitbox.w * 0.5f); world->cameraPos = offsetFromEntityToCameraOrigin; } @@ -2017,11 +1994,38 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) if (stats->weapon) { - stats->weapon->pos = entity->pos; + 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(60.0f); + } + else + { + weapon->pos.x -= entitySubTexture.offset.x; + weapon->rotation = DEGREES_TO_RADIANS(-60.0f); + } } if (entity->state == entitystate_battle) { + if (stats->actionTimer > 0) stats->actionTimer -= dt * stats->actionSpdMul; @@ -2067,9 +2071,19 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) { entity_updateAnim(eventQueue, entity, dt); /* Calculate region to render */ - renderer_entity(renderer, camera, entity, - v2_scale(entity->renderSize, 0.5f), 0, - V4(1, 1, 1, 1)); + + if (entity->type == entitytype_weapon) + { + renderer_entity(renderer, camera, entity, + v2_scale(entity->size, 0.5f), 0, + V4(1, 1, 1, 1.0f)); + } + else + { + renderer_entity(renderer, camera, entity, + v2_scale(entity->size, 0.5f), 0, + V4(1, 1, 1, 1)); + } } } @@ -2372,18 +2386,19 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) /* Draw hero avatar */ TexAtlas *heroAtlas = asset_getTexAtlas(assetManager, "ClaudeSprite.png"); - Rect heroAvatarRect = + SubTexture heroAvatarRect = asset_getAtlasSubTex(heroAtlas, "ClaudeSprite_Avatar_01"); - v2 heroAvatarP = - V2(10.0f, (renderer->size.h * 0.5f) - (0.5f * heroAvatarRect.size.h)); + 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.pos; - heroAvatarTexRect.vec2[1] = v2_add(heroAvatarRect.pos, heroAvatarRect.size); + 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.size, V2(0, 0), 0, + renderer_staticRect(renderer, heroAvatarP, heroAvatarRect.rect.size, V2(0, 0), 0, heroRenderTex, V4(1, 1, 1, 1)); char heroAvatarStr[20]; @@ -2392,7 +2407,7 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) f32 strLenInPixels = CAST(f32)(font->maxSize.w * common_strlen(heroAvatarStr)); v2 strPos = - V2(heroAvatarP.x, heroAvatarP.y - (0.5f * heroAvatarRect.size.h)); + V2(heroAvatarP.x, heroAvatarP.y - (0.5f * heroAvatarRect.rect.size.h)); renderer_staticString(&state->renderer, &state->arena, font, heroAvatarStr, strPos, V2(0, 0), 0, V4(0, 0, 1, 1)); @@ -2410,9 +2425,8 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) { v2 difference = v2_sub(entity->pos, hero->pos); f32 angle = math_atan2f(difference.y, difference.x); - f32 angleDegrees = RADIANS_TO_DEGREES(angle); - v2 heroCenter = v2_add(hero->pos, v2_scale(hero->hitboxSize, 0.5f)); + 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); renderer_rect(&state->renderer, camera, heroCenter, diff --git a/src/include/Dengine/AssetManager.h b/src/include/Dengine/AssetManager.h index 9d74797..41dc01a 100644 --- a/src/include/Dengine/AssetManager.h +++ b/src/include/Dengine/AssetManager.h @@ -28,7 +28,8 @@ typedef struct AssetManager * Texture Operations ********************************* */ -const Rect asset_getAtlasSubTex(TexAtlas *const atlas, const char *const key); +const SubTexture asset_getAtlasSubTex(TexAtlas *const atlas, + const char *const key); Texture *asset_getTex(AssetManager *const assetManager, const char *const key); TexAtlas *asset_getFreeTexAtlasSlot(AssetManager *const assetManager, MemoryArena *arena, const char *const key, diff --git a/src/include/Dengine/Assets.h b/src/include/Dengine/Assets.h index ea1a3c6..67466f6 100644 --- a/src/include/Dengine/Assets.h +++ b/src/include/Dengine/Assets.h @@ -94,6 +94,13 @@ typedef struct AudioVorbis * Texture Assets ********************************* */ + +typedef struct SubTexture +{ + Rect rect; + v2 offset; +} SubTexture; + typedef struct TexAtlas { Texture *tex; diff --git a/src/include/Dengine/Entity.h b/src/include/Dengine/Entity.h index 8bb48fa..123e34d 100644 --- a/src/include/Dengine/Entity.h +++ b/src/include/Dengine/Entity.h @@ -3,12 +3,11 @@ #include "Dengine/Common.h" #include "Dengine/Math.h" +#include "Dengine/Assets.h" typedef struct AssetManager AssetManager; typedef struct AudioRenderer AudioRenderer; typedef struct MemoryArena MemoryArena; -typedef struct Texture Texture; -typedef struct Animation Animation; typedef struct World World; typedef struct EventQueue EventQueue; @@ -95,8 +94,9 @@ struct Entity v2 pos; // Position v2 dPos; // Velocity - v2 hitboxSize; - v2 renderSize; + v2 hitbox; + v2 size; + f32 scale; f32 rotation; @@ -107,6 +107,8 @@ struct Entity enum Direction direction; Texture *tex; + b32 flipX; + b32 flipY; // TODO(doyle): Two collision flags, we want certain entities to collide // with certain types of entities only (i.e. projectile from hero to enemy, @@ -126,6 +128,7 @@ struct Entity i32 numAudioRenderers; }; +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,