fpona: Add tile coordinates

This commit is contained in:
doyle 2023-09-16 19:06:16 +10:00
parent e7641fa9a9
commit eb8fa0604e
2 changed files with 115 additions and 46 deletions

2
External/tely vendored

@ -1 +1 @@
Subproject commit 9b91e7e1b9bb3a6eb103aeb5de457c4a56fee331 Subproject commit 1b331f9ab37baa31b345d5be8d71a8c4c7946f87

View File

@ -192,6 +192,21 @@ void TELY_DLL_Init(void *user_data)
enemy->flags |= TELY_EntityFlag_MoveByMouse; enemy->flags |= TELY_EntityFlag_MoveByMouse;
} }
// NOTE: Wall
{
TELY_GameEntity *entity = TELY_Game_MakeEntityPointerF(game, "V. Wall");
entity->local_pos = Dqn_V2_InitNx2(100.f, 300.f);
entity->local_hit_box_size = Dqn_V2_InitNx2(100.f, 300.f);
entity->flags |= TELY_EntityFlag_Clickable;
entity->flags |= TELY_EntityFlag_MoveByKeyboard;
entity->flags |= TELY_EntityFlag_MoveByMouse;
TELY_GameShape *wall = Dqn_FArray_Make(&entity->shapes, Dqn_ZeroMem_Yes);
wall->type = TELY_GameShapeType_Rect;
wall->p2 = entity->local_hit_box_size;
wall->colour = TELY_COLOUR_GREEN_DARK_KHAKI_V4;
}
uint16_t font_size = 18; uint16_t font_size = 18;
game->camera.scale = Dqn_V2_InitNx1(1); game->camera.scale = Dqn_V2_InitNx1(1);
pona->inter_regular_font = platform->func_load_font(assets, DQN_STRING8("Inter (Regular)"), DQN_STRING8("Data/Inter-Regular.otf"), font_size); pona->inter_regular_font = platform->func_load_font(assets, DQN_STRING8("Inter (Regular)"), DQN_STRING8("Data/Inter-Regular.otf"), font_size);
@ -214,12 +229,38 @@ void TELY_Game_EntityChangeState(TELY_GameEntity *entity, TELY_GameEntityState s
{ {
if (entity->state == state) if (entity->state == state)
return; return;
entity->state = state; entity->state = state;
entity->anim.frame = 0; entity->anim.frame = 0;
entity->anim.ticks = 0; entity->anim.ticks = 0;
// decouple the state from the animation, e.g. the wall doesn't have an animation
uint16_t desired_sprite_anim_index = 0;
switch (state) {
case TELY_GameEntityState_Nil: {
} break;
case TELY_GameEntityState_Idle: {
desired_sprite_anim_index = TELY_Asset_GetSpriteAnim(entity->sprite_anims, DQN_STRING8("Idle"));
} break;
case TELY_GameEntityState_Attack: {
desired_sprite_anim_index = TELY_Asset_GetSpriteAnim(entity->sprite_anims, DQN_STRING8("Attack A"));
} break;
case TELY_GameEntityState_Run: {
desired_sprite_anim_index = TELY_Asset_GetSpriteAnim(entity->sprite_anims, DQN_STRING8("Running"));
} break;
}
if (entity->sprite_sheet && entity->sprite_anims.size) {
TELY_AssetSpriteAnimation const *sprite_anim = entity->sprite_anims.data + entity->anim.index;
entity->anim.index = desired_sprite_anim_index;
}
} }
void FP_GameUpdate(TELY_Game *game, TELY_Renderer *renderer, TELY_PlatformInput *input) Dqn_f32 const FP_TILE_SIZE = 37.f;
void FP_GameUpdate(TELY_Platform *platform, TELY_Game *game, TELY_Renderer *renderer, TELY_PlatformInput *input)
{ {
if (TELY_Platform_InputKeyIsReleased(input->mouse_left)) if (TELY_Platform_InputKeyIsReleased(input->mouse_left))
game->clicked_entity = game->prev_active_entity; game->clicked_entity = game->prev_active_entity;
@ -252,6 +293,12 @@ void FP_GameUpdate(TELY_Game *game, TELY_Renderer *renderer, TELY_PlatformInput
} }
} }
} }
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_F1)) {
// NOTE: Do A* algorithm
Dqn_V2 world_pos = TELY_Game_CalcEntityWorldPos(game, player->handle);
Dqn_V2I player_tile = platform->core.window_size / FP_TILE_SIZE;
}
} else { } else {
game->camera.world_pos += dir_vector * 5.f; game->camera.world_pos += dir_vector * 5.f;
} }
@ -278,7 +325,24 @@ void FP_GameUpdate(TELY_Game *game, TELY_Renderer *renderer, TELY_PlatformInput
Dqn_f32 t = DQN_CAST(Dqn_f32)DQN_SQUARED(input->delta_s); Dqn_f32 t = DQN_CAST(Dqn_f32)DQN_SQUARED(input->delta_s);
Dqn_f32 t_squared = DQN_SQUARED(t); Dqn_f32 t_squared = DQN_SQUARED(t);
entity->velocity = (acceleration * t) + entity->velocity * 0.82f; entity->velocity = (acceleration * t) + entity->velocity * 0.82f;
entity->local_pos += (acceleration * 0.5f * t_squared) + (entity->velocity * t);
Dqn_V2 delta_p = (acceleration * 0.5f * t_squared) + (entity->velocity * t);
entity->local_pos += delta_p;
Dqn_Rect world_hit_box = TELY_Game_CalcEntityWorldHitBox(game, entity->handle);
Dqn_Rect new_world_hit_box = world_hit_box;
new_world_hit_box.pos += delta_p;
for (TELY_GameEntityIterator collider_it = {}; TELY_Game_DFSPostOrderWalkEntityTree(game, &collider_it, game->root_entity); ) {
TELY_GameEntity *collider = collider_it.entity;
if (collider->handle == entity->handle)
continue;
// TODO(doyle): Minkowski sweep?
Dqn_Rect collider_world_hit_box = TELY_Game_CalcEntityWorldHitBox(game, collider->handle);
if (Dqn_Rect_Intersects(new_world_hit_box, collider_world_hit_box)) {
}
}
} }
// NOTE: Move entity by mouse ============================================================== // NOTE: Move entity by mouse ==============================================================
@ -309,51 +373,36 @@ void FP_GameUpdate(TELY_Game *game, TELY_Renderer *renderer, TELY_PlatformInput
entity->local_hit_box_size = padded_bbox.size; entity->local_hit_box_size = padded_bbox.size;
} }
// NOTE: Handle animation state ============================================================ // NOTE: Tick entity action ================================================================
uint16_t desired_anim_index = 0;
switch (entity->state) {
case TELY_GameEntityState_Idle: {
desired_anim_index = TELY_Asset_GetSpriteAnim(entity->sprite_anims, DQN_STRING8("Idle"));
} break;
case TELY_GameEntityState_Attack: {
desired_anim_index = TELY_Asset_GetSpriteAnim(entity->sprite_anims, DQN_STRING8("Attack A"));
} break;
case TELY_GameEntityState_Run: {
desired_anim_index = TELY_Asset_GetSpriteAnim(entity->sprite_anims, DQN_STRING8("Run"));
} break;
}
{ {
bool action_is_done = false;
TELY_AssetSpriteAnimation const *sprite_anim = entity->sprite_anims.data + entity->anim.index; TELY_AssetSpriteAnimation const *sprite_anim = entity->sprite_anims.data + entity->anim.index;
if (desired_anim_index == entity->anim.index) { // NOTE: Current anim matches, check if its finished if (sprite_anim) {
if (entity->anim.frame >= sprite_anim->count) { // NOTE: Animation is finished if (entity->anim.frame >= sprite_anim->count) { // NOTE: Animation is finished
entity->anim.frame = 0; entity->anim.frame = 0;
entity->anim.ticks = 0; entity->anim.ticks = 0;
switch (entity->state) { action_is_done = true;
case TELY_GameEntityState_Idle: {
} break;
case TELY_GameEntityState_Attack: {
entity->state = TELY_GameEntityState_Idle;
} break;
case TELY_GameEntityState_Run: {
if (dir_vector.x == 0 && dir_vector.y == 0) {
entity->state = TELY_GameEntityState_Idle;
}
} break;
}
} else { } else {
if (entity->anim.ticks++ > 4 /*ticks_per_anim_frame*/) { if (entity->anim.ticks++ > 4 /*ticks_per_anim_frame*/) {
entity->anim.frame++; entity->anim.frame++;
entity->anim.ticks = 0; entity->anim.ticks = 0;
} }
} }
} else { }
// NOTE: Current animation does not match the desired animation, change anim
entity->anim.index = desired_anim_index; if (action_is_done) {
switch (entity->state) {
case TELY_GameEntityState_Nil: break;
case TELY_GameEntityState_Idle: break;
case TELY_GameEntityState_Attack: {
TELY_Game_EntityChangeState(entity, TELY_GameEntityState_Idle);
} break;
case TELY_GameEntityState_Run: {
if (dir_vector.x == 0 && dir_vector.y == 0)
TELY_Game_EntityChangeState(entity, TELY_GameEntityState_Idle);
} break;
}
} }
} }
@ -379,13 +428,10 @@ void FP_GameUpdate(TELY_Game *game, TELY_Renderer *renderer, TELY_PlatformInput
} }
} }
// NOTE: Resolve collision ==================================================================== // NOTE: Do attacks ============================================================================
for (TELY_GameEntityIterator attacker_it = {}; TELY_Game_DFSPostOrderWalkEntityTree(game, &attacker_it, game->root_entity); ) { for (TELY_GameEntityIterator attacker_it = {}; TELY_Game_DFSPostOrderWalkEntityTree(game, &attacker_it, game->root_entity); ) {
TELY_GameEntity *attacker = attacker_it.entity; TELY_GameEntity *attacker = attacker_it.entity;
// NOTE: Resolve box collision
Dqn_Rect attacker_hit_box = TELY_Game_CalcEntityWorldHitBox(game, attacker->handle);
// NOTE: Resolve attack boxes // NOTE: Resolve attack boxes
if (Dqn_V2_Area(attacker->attack_box_size)) { if (Dqn_V2_Area(attacker->attack_box_size)) {
Dqn_Rect attacker_box = TELY_Game_CalcEntityAttackWorldHitBox(game, attacker->handle); Dqn_Rect attacker_box = TELY_Game_CalcEntityAttackWorldHitBox(game, attacker->handle);
@ -426,6 +472,23 @@ void FP_GameRender(TELY_Game *game, TELY_Platform *platform, TELY_Renderer *rend
Dqn_M2x3 model_view = TELY_Game_CameraModelViewM2x3(game->camera, platform); Dqn_M2x3 model_view = TELY_Game_CameraModelViewM2x3(game->camera, platform);
Dqn_V2 world_mouse_p = Dqn_M2x3_MulV2(model_view, input->mouse_p); Dqn_V2 world_mouse_p = Dqn_M2x3_MulV2(model_view, input->mouse_p);
// NOTE: Draw tiles ============================================================================
Dqn_usize tile_count_x = DQN_CAST(Dqn_usize)(platform->core.window_size.w / FP_TILE_SIZE);
Dqn_usize tile_count_y = DQN_CAST(Dqn_usize)(platform->core.window_size.h / FP_TILE_SIZE);
for (Dqn_usize x = 0; x < tile_count_x; x++) {
Dqn_V2 start = Dqn_V2_InitNx2((x + 1) * FP_TILE_SIZE, 0);
Dqn_V2 end = Dqn_V2_InitNx2(start.x, platform->core.window_size.h);
TELY_Render_LineColourV4(renderer, start, end, TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, .25f), 1.f);
}
for (Dqn_usize y = 0; y < tile_count_y; y++) {
Dqn_V2 start = Dqn_V2_InitNx2(0, (y + 1) * FP_TILE_SIZE);
Dqn_V2 end = Dqn_V2_InitNx2(platform->core.window_size.w, start.y);
TELY_Render_LineColourV4(renderer, start, end, TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, .25f), 1.f);
}
// NOTE: Draw entities =========================================================================
for (TELY_GameEntityIterator it = {}; TELY_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity); ) { for (TELY_GameEntityIterator it = {}; TELY_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity); ) {
TELY_GameEntity *entity = it.entity; TELY_GameEntity *entity = it.entity;
entity->alive_time_s += input->delta_s; entity->alive_time_s += input->delta_s;
@ -498,14 +561,20 @@ void FP_GameRender(TELY_Game *game, TELY_Platform *platform, TELY_Renderer *rend
Dqn_V4 hot_colour = game->hot_entity == entity->handle ? TELY_COLOUR_RED_TOMATO_V4 : TELY_Colour_V4Alpha(TELY_COLOUR_YELLOW_SANDY_V4, .5f); Dqn_V4 hot_colour = game->hot_entity == entity->handle ? TELY_COLOUR_RED_TOMATO_V4 : TELY_Colour_V4Alpha(TELY_COLOUR_YELLOW_SANDY_V4, .5f);
TELY_Render_RectColourV4(renderer, world_hit_box, TELY_RenderShapeMode_Line, hot_colour); TELY_Render_RectColourV4(renderer, world_hit_box, TELY_RenderShapeMode_Line, hot_colour);
if (game->hot_entity == entity->handle && (entity->name.size)) { }
Dqn_V2 entity_world_pos = TELY_Game_CalcEntityWorldPos(game, entity->handle);
if (game->clicked_entity == entity->handle || game->hot_entity == entity->handle) {
if (entity->name.size) {
Dqn_V2I player_tile = Dqn_V2I_InitNx2(world_pos.x / FP_TILE_SIZE, world_pos.y / FP_TILE_SIZE);
Dqn_V2 entity_world_pos = TELY_Game_CalcEntityWorldPos(game, entity->handle);
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr); Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
Dqn_String8 label = Dqn_String8_InitF(scratch.allocator, Dqn_String8 label = Dqn_String8_InitF(scratch.allocator,
"%.*s (%.1f, %.1f)", "%.*s (%.1f, %.1f) (%I32d, %I32d)",
DQN_STRING_FMT(entity->name), DQN_STRING_FMT(entity->name),
entity_world_pos.x, entity_world_pos.x,
entity_world_pos.y); entity_world_pos.y,
player_tile.x,
player_tile.y);
TELY_Render_Text(renderer, world_mouse_p, Dqn_V2_InitNx2(0.f, 1), label); TELY_Render_Text(renderer, world_mouse_p, Dqn_V2_InitNx2(0.f, 1), label);
} }
} }
@ -606,7 +675,7 @@ void TELY_DLL_FrameUpdate(void *user_data)
} }
} }
FP_GameUpdate(game, renderer, input); FP_GameUpdate(platform, game, renderer, input);
FP_GameRender(game, platform, renderer); FP_GameRender(game, platform, renderer);
TELY_Audio_MixPlaybackSamples(audio, assets); TELY_Audio_MixPlaybackSamples(audio, assets);
} }