From 3829a2bdc9b29b1f76c83e06d1552404cda3fa6f Mon Sep 17 00:00:00 2001 From: doyle Date: Fri, 29 Sep 2023 14:50:40 +1000 Subject: [PATCH] fp: First draft swarming on entity --- feely_pona.cpp | 53 ++++++++++++++++++++++++++++----------------- feely_pona_game.cpp | 45 ++++++++++++++++++++++++++++++++++++++ feely_pona_game.h | 26 +++++++++++++++------- 3 files changed, 96 insertions(+), 28 deletions(-) diff --git a/feely_pona.cpp b/feely_pona.cpp index 44966bc..3c3497a 100644 --- a/feely_pona.cpp +++ b/feely_pona.cpp @@ -880,35 +880,54 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input if (closest_terry_dist < DQN_SQUARED(FP_Game_MetersToPixelsNx1(game, 2.f))) { FP_SentinelListLink *first_waypoint = FP_SentinelList_Front(&entity->waypoints); if (first_waypoint->data.entity != closest_terry->handle) { + + FP_GameDirection aggro_direction = FP_GameDirection_Count; + DQN_FOR_UINDEX(dir_index, FP_GameDirection_Count) { + FP_GameEntityHandle slot_entity_handle = closest_terry->aggro_slot[dir_index]; + FP_GameEntity *slot_entity = FP_Game_GetEntity(game, slot_entity_handle); + if (FP_Game_IsNilEntity(slot_entity)) { + aggro_direction = DQN_CAST(FP_GameDirection)dir_index; + break; + } + } + FP_SentinelListLink *link = FP_SentinelList_MakeBefore(&entity->waypoints, first_waypoint, game->chunk_pool); - link->data.entity = closest_terry->handle; + FP_GameWaypoint *waypoint = &link->data; + waypoint->entity = closest_terry->handle; + + if (aggro_direction != FP_GameDirection_Count) { + waypoint->type = FP_GameWaypointType_Side; + waypoint->type_direction = aggro_direction; + closest_terry->aggro_slot[aggro_direction] = entity->handle; + } } } } while (entity->waypoints.size) { FP_SentinelListLink *waypoint_link = entity->waypoints.sentinel->next; - FP_GameEntity *waypoint = FP_Game_GetEntity(game, waypoint_link->data.entity); - if (FP_Game_IsNilEntity(waypoint)) { + FP_GameWaypoint const *waypoint = &waypoint_link->data; + FP_GameEntity *waypoint_entity = FP_Game_GetEntity(game, waypoint_link->data.entity); + if (FP_Game_IsNilEntity(waypoint_entity)) { FP_SentinelList_Erase(&entity->waypoints, waypoint_link, game->chunk_pool); continue; } // NOTE: We found a waypoint that is valid to move towards - Dqn_V2 waypoint_pos = FP_Game_CalcEntityWorldPos(game, waypoint->handle); - Dqn_V2 entity_to_waypoint = waypoint_pos - entity_pos; + Dqn_V2 target_pos = FP_Game_CalcWaypointWorldPos(game, waypoint); + Dqn_V2 entity_to_waypoint = target_pos - entity_pos; // NOTE: Check if we've arrived at the waypoint Dqn_f32 dist_to_waypoint_sq = Dqn_V2_LengthSq(entity_to_waypoint); Dqn_f32 arrival_threshold = {}; - switch (waypoint_link->data.arrive) { + switch (waypoint->arrive) { case FP_GameWaypointArrive_Default: { arrival_threshold = FP_Game_MetersToPixelsNx1(game, 1.f); } break; case FP_GameWaypointArrive_WhenWithinEntitySize: { - arrival_threshold = DQN_MAX(waypoint->local_hit_box_size.w, waypoint->local_hit_box_size.h) * waypoint_link->data.value; + arrival_threshold = DQN_MAX(waypoint_entity->local_hit_box_size.w, waypoint_entity->local_hit_box_size.h) * waypoint_link->data.value; } break; } @@ -920,7 +939,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input } // NOTE: We have arrived at the waypoint - if ((entity->flags & FP_GameEntityFlag_AggrosWhenNearTerry) && waypoint->type == FP_EntityType_Terry) { + if ((entity->flags & FP_GameEntityFlag_AggrosWhenNearTerry) && waypoint_entity->type == FP_EntityType_Terry) { // NOTE: We had a waypoint to move to Terry because he has // drawn our aggro and we've arrived at Terry @@ -1330,6 +1349,7 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer) TELY_Render_TextureColourV4(renderer, sprite->asset.sheet->tex_handle, src_rect, dest_rect, TELY_COLOUR_WHITE_V4); } + // NOTE: Render waypoint entities ========================================================== if (entity->flags & FP_GameEntityFlag_MobSpawner) { Dqn_V2 start = world_pos; for (FP_GameEntity *waypoint_entity = entity->first_child; waypoint_entity; waypoint_entity = waypoint_entity->next) { @@ -1357,19 +1377,12 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer) TELY_Render_RectColourV4(renderer, world_hit_box, TELY_RenderShapeMode_Line, TELY_COLOUR_WHITE_PALE_GOLDENROD_V4); // NOTE: Draw the waypoints that the entity is moving along - if (entity->waypoints.size) { - Dqn_V2 start = world_pos; - for (FP_SentinelListLink *link = nullptr; FP_SentinelList_Iterate(&entity->waypoints, &link); ) { - FP_GameEntity *waypoint = FP_Game_GetEntity(game, link->data.entity); - if (FP_Game_IsNilEntity(waypoint)) - continue; - - Dqn_V2 end = FP_Game_CalcEntityWorldPos(game, waypoint->handle); - TELY_Render_LineColourV4(renderer, start, end, TELY_COLOUR_WHITE_PALE_GOLDENROD_V4, 2.f); - start = end; - } + Dqn_V2 start = world_pos; + for (FP_SentinelListLink *link = nullptr; FP_SentinelList_Iterate(&entity->waypoints, &link); ) { + Dqn_V2 end = FP_Game_CalcWaypointWorldPos(game, &link->data); + TELY_Render_LineColourV4(renderer, start, end, TELY_COLOUR_WHITE_PALE_GOLDENROD_V4, 2.f); + start = end; } - } else if (game->hot_entity == entity->handle || (entity->flags & FP_GameEntityFlag_DrawHitBox)) { 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); diff --git a/feely_pona_game.cpp b/feely_pona_game.cpp index 0c430a9..6b2bcc1 100644 --- a/feely_pona_game.cpp +++ b/feely_pona_game.cpp @@ -630,3 +630,48 @@ static Dqn_Slice FP_Game_AStarPathFind(FP_Game *game, DQN_ASSERT(result.size == slice_size); return result; } + +static Dqn_V2 FP_Game_CalcWaypointWorldPos(FP_Game *game, FP_GameWaypoint const *waypoint) +{ + Dqn_V2 result = {}; + if (!game || !waypoint) + return result; + + FP_GameEntity *waypoint_entity = FP_Game_GetEntity(game, waypoint->entity); + if (FP_Game_IsNilEntity(waypoint_entity)) + return result; + + // NOTE: We found a waypoint that is valid to move towards + switch (waypoint->type) { + case FP_GameWaypointType_At: { + result = FP_Game_CalcEntityWorldPos(game, waypoint_entity->handle); + } break; + + case FP_GameWaypointType_Side: { + Dqn_Rect entity_rect = FP_Game_CalcEntityWorldHitBox(game, waypoint_entity->handle); + switch (waypoint->type_direction) { + case FP_GameDirection_Up: { + result = Dqn_V2_InitNx2(entity_rect.pos.x + entity_rect.size.w * .5f, entity_rect.pos.y - entity_rect.size.h * .5f); + } break; + + case FP_GameDirection_Down: { + result = Dqn_V2_InitNx2(entity_rect.pos.x + entity_rect.size.w * .5f, entity_rect.pos.y + entity_rect.size.h + (entity_rect.size.h * .5f)); + } break; + + case FP_GameDirection_Left: { + result = Dqn_V2_InitNx2(entity_rect.pos.x - entity_rect.size.w * .5f, entity_rect.pos.y + entity_rect.size.h * .5f); + } break; + + case FP_GameDirection_Right: { + result = Dqn_V2_InitNx2(entity_rect.pos.x + entity_rect.size.w + entity_rect.size.w * .5f, entity_rect.pos.y + entity_rect.size.h * .5f); + } break; + + case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break; + } + } break; + } + + return result; +} + + diff --git a/feely_pona_game.h b/feely_pona_game.h index 26bed44..97e5eb9 100644 --- a/feely_pona_game.h +++ b/feely_pona_game.h @@ -63,8 +63,25 @@ enum FP_GameWaypointArrive FP_GameWaypointArrive_WhenWithinEntitySize, }; +enum FP_GameWaypointType +{ + FP_GameWaypointType_At, // Move to the specified entity + FP_GameWaypointType_Side, // Move to the side of the entity specified by the direction +}; + +enum FP_GameDirection +{ + FP_GameDirection_Up, + FP_GameDirection_Down, + FP_GameDirection_Left, + FP_GameDirection_Right, + FP_GameDirection_Count, +}; + struct FP_GameWaypoint { + FP_GameWaypointType type; + FP_GameDirection type_direction; FP_GameEntityHandle entity; FP_GameWaypointArrive arrive; Dqn_f32 value; @@ -93,14 +110,6 @@ struct FP_GameEntityAction uint64_t end_at_clock_ms; }; -enum FP_GameDirection -{ - FP_GameDirection_Up, - FP_GameDirection_Down, - FP_GameDirection_Left, - FP_GameDirection_Right, -}; - struct FP_GameRenderSprite { Dqn_V2 offset; @@ -134,6 +143,7 @@ struct FP_GameEntity Dqn_FArray extra_cosmetic_anims; FP_SentinelList waypoints; + FP_GameEntityHandle aggro_slot[FP_GameDirection_Count]; // NOTE: The entity hit box is positioned at the center of the entity. Dqn_V2 local_hit_box_size;