Add basic entity death code for singular entity
This commit is contained in:
parent
3e2287e13a
commit
3aaad2fba3
@ -175,7 +175,7 @@ void debug_drawUi(GameState *state, f32 dt)
|
|||||||
strPos, 0, color);
|
strPos, 0, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i32 i = 0; i < world->maxEntities; i++)
|
for (i32 i = 0; i < world->freeEntityIndex; i++)
|
||||||
{
|
{
|
||||||
Entity *const entity = &world->entities[i];
|
Entity *const entity = &world->entities[i];
|
||||||
/* Render debug markers on entities */
|
/* Render debug markers on entities */
|
||||||
|
@ -58,6 +58,18 @@ INTERNAL Entity *addEntity(MemoryArena *arena, World *world, v2 pos, v2 size,
|
|||||||
return result;
|
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)
|
INTERNAL void rendererInit(GameState *state, v2 windowSize)
|
||||||
{
|
{
|
||||||
AssetManager *assetManager = &state->assetManager;
|
AssetManager *assetManager = &state->assetManager;
|
||||||
@ -105,6 +117,35 @@ INTERNAL void addAnim(AssetManager *assetManager, i32 animId, Entity *entity)
|
|||||||
entity->anim[animId].currDuration = anim->frameDuration;
|
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 <time.h>
|
||||||
|
#include <stdlib.h>
|
||||||
void worldTraveller_gameInit(GameState *state, v2 windowSize)
|
void worldTraveller_gameInit(GameState *state, v2 windowSize)
|
||||||
{
|
{
|
||||||
AssetManager *assetManager = &state->assetManager;
|
AssetManager *assetManager = &state->assetManager;
|
||||||
@ -302,26 +343,14 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize)
|
|||||||
npc->currAnimId = animlist_hero_wave;
|
npc->currAnimId = animlist_hero_wave;
|
||||||
|
|
||||||
/* Create a Mob */
|
/* Create a Mob */
|
||||||
pos = V2(renderer->size.w - (renderer->size.w / 3.0f),
|
pos = V2(renderer->size.w - (renderer->size.w / 3.0f),
|
||||||
CAST(f32) state->tileSize);
|
CAST(f32) state->tileSize);
|
||||||
size = hero->hitboxSize;
|
addGenericMob(arena, assetManager, world, pos);
|
||||||
type = entitytype_mob;
|
|
||||||
dir = direction_west;
|
|
||||||
tex = hero->tex;
|
|
||||||
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_battlePose, mob);
|
|
||||||
addAnim(assetManager, animlist_hero_tackle, mob);
|
|
||||||
hero->currAnimId = animlist_hero_idle;
|
|
||||||
|
|
||||||
#ifdef DENGINE_DEBUG
|
#ifdef DENGINE_DEBUG
|
||||||
DEBUG_LOG("World populated");
|
DEBUG_LOG("World populated");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
srand(CAST(u32)(time(NULL)));
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL inline void setActiveEntityAnim(Entity *entity,
|
INTERNAL inline void setActiveEntityAnim(Entity *entity,
|
||||||
@ -405,20 +434,20 @@ INTERNAL void parseInput(GameState *state, const f32 dt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO(doyle): Revisit key input with state checking for last ended down
|
// TODO(doyle): Revisit key input with state checking for last ended down
|
||||||
#if 0
|
|
||||||
if (state->keys[GLFW_KEY_SPACE] && !spaceBarWasDown)
|
if (state->keys[GLFW_KEY_SPACE] && !spaceBarWasDown)
|
||||||
{
|
{
|
||||||
if (!(hero->currAnimId == entityanimid_tackle &&
|
Renderer *renderer = &state->renderer;
|
||||||
hero->currAnimCyclesCompleted == 0))
|
f32 yPos = CAST(f32)(rand() % CAST(i32)renderer->size.h);
|
||||||
{
|
f32 xModifier = 5.0f - CAST(f32)(rand() % 3);
|
||||||
spaceBarWasDown = TRUE;
|
|
||||||
}
|
v2 pos = V2(renderer->size.w - (renderer->size.w / xModifier), yPos);
|
||||||
|
addGenericMob(&state->arena, &state->assetManager, world, pos);
|
||||||
|
spaceBarWasDown = TRUE;
|
||||||
}
|
}
|
||||||
else if (!state->keys[GLFW_KEY_SPACE])
|
else if (!state->keys[GLFW_KEY_SPACE])
|
||||||
{
|
{
|
||||||
spaceBarWasDown = FALSE;
|
spaceBarWasDown = FALSE;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(doyle): Clipping threshold for snapping velocity to 0
|
// NOTE(doyle): Clipping threshold for snapping velocity to 0
|
||||||
@ -462,7 +491,7 @@ INTERNAL void parseInput(GameState *state, const f32 dt)
|
|||||||
b32 heroCollided = FALSE;
|
b32 heroCollided = FALSE;
|
||||||
if (hero->collides == TRUE)
|
if (hero->collides == TRUE)
|
||||||
{
|
{
|
||||||
for (i32 i = 0; i < world->maxEntities; i++)
|
for (i32 i = 0; i < world->freeEntityIndex; i++)
|
||||||
{
|
{
|
||||||
if (i == world->heroIndex) continue;
|
if (i == world->heroIndex) continue;
|
||||||
Entity entity = world->entities[i];
|
Entity entity = world->entities[i];
|
||||||
@ -600,7 +629,14 @@ INTERNAL void endAttack(World *world, Entity *attacker)
|
|||||||
setActiveEntityAnim(attacker, animlist_hero_battlePose);
|
setActiveEntityAnim(attacker, animlist_hero_battlePose);
|
||||||
|
|
||||||
Entity *defender = &world->entities[attacker->stats->entityIdToAttack];
|
Entity *defender = &world->entities[attacker->stats->entityIdToAttack];
|
||||||
defender->stats->health--;
|
if (attacker->type == entitytype_hero)
|
||||||
|
{
|
||||||
|
defender->stats->health -= 50;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
defender->stats->health--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(doyle): Exposed because of debug .. rework debug system so it we don't
|
// TODO(doyle): Exposed because of debug .. rework debug system so it we don't
|
||||||
@ -727,8 +763,14 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity,
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case entitystate_attack:
|
case entitystate_attack:
|
||||||
|
break;
|
||||||
case entitystate_dead:
|
case entitystate_dead:
|
||||||
return;
|
updateWorldBattleEntities(world, entity, ENTITY_NOT_IN_BATTLE);
|
||||||
|
setActiveEntityAnim(entity, animlist_hero_wave);
|
||||||
|
entity->stats->actionTimer = entity->stats->actionRate;
|
||||||
|
entity->stats->queuedAttack = entityattack_invalid;
|
||||||
|
entity->stats->entityIdToAttack = ENTITY_NULL_ID;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
#ifdef DENGINE_DEBUG
|
#ifdef DENGINE_DEBUG
|
||||||
ASSERT(INVALID_CODE_PATH);
|
ASSERT(INVALID_CODE_PATH);
|
||||||
@ -743,6 +785,13 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
case entitystate_dead:
|
case entitystate_dead:
|
||||||
|
// TODO(doyle): Repeated logic with battle -> dead
|
||||||
|
updateWorldBattleEntities(world, entity, ENTITY_NOT_IN_BATTLE);
|
||||||
|
setActiveEntityAnim(entity, animlist_hero_wave);
|
||||||
|
entity->stats->actionTimer = entity->stats->actionRate;
|
||||||
|
entity->stats->queuedAttack = entityattack_invalid;
|
||||||
|
entity->stats->entityIdToAttack = ENTITY_NULL_ID;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
#ifdef DENGINE_DEBUG
|
#ifdef DENGINE_DEBUG
|
||||||
ASSERT(INVALID_CODE_PATH);
|
ASSERT(INVALID_CODE_PATH);
|
||||||
@ -770,7 +819,8 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity,
|
|||||||
entity->state = newState;
|
entity->state = newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void updateEntityAndRender(Renderer *renderer, World *world, f32 dt)
|
INTERNAL void updateEntityAndRender(MemoryArena *arena, Renderer *renderer,
|
||||||
|
World *world, f32 dt)
|
||||||
{
|
{
|
||||||
Entity *hero = &world->entities[world->heroIndex];
|
Entity *hero = &world->entities[world->heroIndex];
|
||||||
for (i32 i = 0; i < world->freeEntityIndex; i++)
|
for (i32 i = 0; i < world->freeEntityIndex; i++)
|
||||||
@ -780,6 +830,16 @@ INTERNAL void updateEntityAndRender(Renderer *renderer, World *world, f32 dt)
|
|||||||
{
|
{
|
||||||
case entitytype_mob:
|
case entitytype_mob:
|
||||||
{
|
{
|
||||||
|
if (entity->state == entitystate_dead)
|
||||||
|
{
|
||||||
|
// TODO(doyle): Accumulate all dead entities and delete at the
|
||||||
|
// end. Hence resort/organise entity array once, not every time
|
||||||
|
// an entity dies
|
||||||
|
i32 entityIndexInArray = i;
|
||||||
|
deleteEntity(arena, world, entityIndexInArray);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(doyle): Currently calculated in pixels, how about meaningful
|
// TODO(doyle): Currently calculated in pixels, how about meaningful
|
||||||
// game units?
|
// game units?
|
||||||
f32 battleThreshold = 500.0f;
|
f32 battleThreshold = 500.0f;
|
||||||
@ -796,42 +856,36 @@ INTERNAL void updateEntityAndRender(Renderer *renderer, World *world, f32 dt)
|
|||||||
// NOTE(doyle): Let entitytype_mob fall through to entitytype_hero here
|
// NOTE(doyle): Let entitytype_mob fall through to entitytype_hero here
|
||||||
case entitytype_hero:
|
case entitytype_hero:
|
||||||
{
|
{
|
||||||
if (entity->state == entitystate_battle ||
|
EntityStats *stats = entity->stats;
|
||||||
entity->state == entitystate_attack)
|
if (entity->state == entitystate_battle)
|
||||||
{
|
{
|
||||||
EntityStats *stats = entity->stats;
|
if (stats->actionTimer > 0)
|
||||||
if (stats->health > 0)
|
stats->actionTimer -= dt * stats->actionSpdMul;
|
||||||
|
|
||||||
|
if (stats->actionTimer < 0)
|
||||||
{
|
{
|
||||||
if (entity->state == entitystate_battle)
|
stats->actionTimer = 0;
|
||||||
{
|
if (stats->queuedAttack == entityattack_invalid)
|
||||||
if (stats->actionTimer > 0)
|
stats->queuedAttack = entityattack_tackle;
|
||||||
stats->actionTimer -= dt * stats->actionSpdMul;
|
|
||||||
|
|
||||||
if (stats->actionTimer < 0)
|
beginAttack(entity);
|
||||||
{
|
|
||||||
stats->actionTimer = 0;
|
|
||||||
if (stats->queuedAttack == entityattack_invalid)
|
|
||||||
stats->queuedAttack = entityattack_tackle;
|
|
||||||
|
|
||||||
beginAttack(entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
stats->busyDuration -= dt;
|
|
||||||
if (stats->busyDuration <= 0)
|
|
||||||
endAttack(world, entity);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
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) endAttack(world, attacker);
|
||||||
|
|
||||||
|
Entity *defender =
|
||||||
|
&world->entities[attacker->stats->entityIdToAttack];
|
||||||
|
if (defender->stats->health <= 0)
|
||||||
{
|
{
|
||||||
#ifdef DENGINE_DEBUG
|
#ifdef DENGINE_DEBUG
|
||||||
ASSERT(INVALID_CODE_PATH);
|
DEBUG_LOG("Entity has died");
|
||||||
#endif
|
#endif
|
||||||
// TODO(doyle): Generalise for all entities
|
entityStateSwitch(world, defender, entitystate_dead);
|
||||||
hero->stats->entityIdToAttack = ENTITY_NULL_ID;
|
|
||||||
hero->state = entitystate_idle;
|
|
||||||
entity->state = entitystate_dead;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -884,7 +938,7 @@ void worldTraveller_gameUpdateAndRender(GameState *state, const f32 dt)
|
|||||||
Font *font = &assetManager->font;
|
Font *font = &assetManager->font;
|
||||||
|
|
||||||
ASSERT(world->freeEntityIndex < world->maxEntities);
|
ASSERT(world->freeEntityIndex < world->maxEntities);
|
||||||
updateEntityAndRender(renderer, world, dt);
|
updateEntityAndRender(&state->arena, renderer, world, dt);
|
||||||
|
|
||||||
/* Draw ui */
|
/* Draw ui */
|
||||||
TexAtlas *heroAtlas = asset_getTextureAtlas(assetManager, texlist_hero);
|
TexAtlas *heroAtlas = asset_getTextureAtlas(assetManager, texlist_hero);
|
||||||
|
Loading…
Reference in New Issue
Block a user