fp: Start drafting up swarming of buildings

This commit is contained in:
2023-09-29 22:44:27 +10:00
parent 158fcb12fe
commit a35cb8d2a6
3 changed files with 117 additions and 7 deletions
+99 -2
View File
@@ -91,6 +91,83 @@ TELY_AssetSpriteSheet FP_LoadSpriteSheetFromSpec(TELY_Platform *platform, TELY_A
return result;
}
struct FP_GameSwarmSlot
{
Dqn_usize count;
Dqn_V2 world_pos;
};
Dqn_FArray<FP_GameSwarmSlot, 32> FP_Entity_GetSwarmingPositions(FP_Game *game, FP_GameEntityHandle entity_handle)
{
Dqn_FArray<FP_GameSwarmSlot, 32> result = {};
FP_GameEntity *entity = FP_Game_GetEntity(game, entity_handle);
if (FP_Game_IsNilEntity(entity))
return result;
DQN_FOR_UINDEX (dir_index, FP_GameDirection_Count) {
FP_GameSwarm *swarm = entity->swarm + dir_index;
Dqn_f32 const min_dist_between_slots = FP_Game_MetersToPixelsNx1(game, 1.f);
// NOTE: Calculate the number of swarming slots we need for this entity
if (swarm->slots_active == 0) {
switch (DQN_CAST(FP_GameDirection)dir_index) {
case FP_GameDirection_Up: /*FALLTHRU*/
case FP_GameDirection_Down: {
swarm->slots_active = DQN_CAST(Dqn_usize)(entity->local_hit_box_size.w / min_dist_between_slots);
} break;
case FP_GameDirection_Left: /*FALLTHRU*/
case FP_GameDirection_Right: {
swarm->slots_active = DQN_CAST(Dqn_usize)(entity->local_hit_box_size.h / min_dist_between_slots);
} break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
DQN_ASSERT(swarm->slots_active < Dqn_FArray_Max(&swarm->slots));
}
// NOTE: Calculate potential swarming positions ========================
Dqn_Rect entity_world_hit_box = FP_Game_CalcEntityWorldHitBox(game, entity->handle);
DQN_FOR_UINDEX (slot_index, swarm->slots_active) {
FP_SentinelList<FP_GameEntityHandle> *list = swarm->slots.data + slot_index;
FP_GameSwarmSlot *slot = Dqn_FArray_Make(&result, Dqn_ZeroMem_No);
slot->count = list->size;
switch (DQN_CAST(FP_GameDirection)dir_index) {
case FP_GameDirection_Up: {
Dqn_V2 start = Dqn_V2_InitNx2(entity_world_hit_box.pos.x,
entity_world_hit_box.pos.y - entity_world_hit_box.size.h * .1f);
slot->world_pos = Dqn_V2_InitNx2(start.x + slot_index * min_dist_between_slots, start.y);
} break;
case FP_GameDirection_Down: {
Dqn_V2 start = Dqn_V2_InitNx2(entity_world_hit_box.pos.x,
entity_world_hit_box.pos.y + entity_world_hit_box.size.h + entity_world_hit_box.size.h * .1f);
slot->world_pos = Dqn_V2_InitNx2(start.x + slot_index * min_dist_between_slots, start.y);
} break;
case FP_GameDirection_Left: {
Dqn_V2 start = Dqn_V2_InitNx2(entity_world_hit_box.pos.x - entity_world_hit_box.size.w * .1f,
entity_world_hit_box.pos.y);
slot->world_pos = Dqn_V2_InitNx2(start.x, start.y + slot_index * min_dist_between_slots);
} break;
case FP_GameDirection_Right: {
Dqn_V2 start = Dqn_V2_InitNx2(entity_world_hit_box.pos.x + entity_world_hit_box.size.w + entity_world_hit_box.size.w * .1f,
entity_world_hit_box.pos.y);
slot->world_pos = Dqn_V2_InitNx2(start.x, start.y + slot_index * min_dist_between_slots);
} break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
}
}
return result;
}
static void FP_Game_MoveEntity(FP_Game *game, FP_GameEntityHandle entity_handle, Dqn_V2 acceleration_meters_per_s)
{
// f"(t) = a
@@ -986,6 +1063,13 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
}
}
if (entity->type == FP_EntityType_ClubTerry) {
Dqn_FArray<FP_GameSwarmSlot, 32> candidate_swarm_slots = FP_Entity_GetSwarmingPositions(game, entity->handle);
DQN_ASSERT(candidate_swarm_slots.size);
for (FP_GameSwarmSlot& slot : candidate_swarm_slots)
TELY_Render_CircleColourV4(&platform->renderer, slot.world_pos, 8.f, TELY_RenderShapeMode_Line, TELY_COLOUR_RED_TOMATO_V4);
}
if (entity->flags & FP_GameEntityFlag_RespondsToClubTerry) {
FP_GameFindClosestEntityResult closest_result = FP_Game_FindClosestEntityWithType(game, entity->handle, FP_EntityType_ClubTerry);
if (closest_result.dist_squared < DQN_SQUARED(FP_Game_MetersToPixelsNx1(game, 4.f))) {
@@ -993,11 +1077,24 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
if (first_waypoint->data.entity != closest_result.entity) {
FP_GameEntity *club_terry = FP_Game_GetEntity(game, closest_result.entity);
Dqn_FArray<FP_GameSwarmSlot, 32> candidate_swarm_slots = FP_Entity_GetSwarmingPositions(game, closest_result.entity);
DQN_ASSERT(candidate_swarm_slots.size);
Dqn_f32 closest_swarm_dist = DQN_F32_MAX;
Dqn_V2 closest_swarm_pos = {};
for (FP_GameSwarmSlot& slot : candidate_swarm_slots) {
Dqn_f32 dist = Dqn_V2_Length_V2x2(slot.world_pos, entity_pos);
if (dist < closest_swarm_dist) {
closest_swarm_dist = dist;
closest_swarm_pos = slot.world_pos;
}
}
FP_SentinelListLink<FP_GameWaypoint> *link = FP_SentinelList_MakeBefore(&entity->waypoints, first_waypoint, game->chunk_pool);
FP_GameWaypoint *waypoint = &link->data;
waypoint->entity = club_terry->handle;
waypoint->type = FP_GameWaypointType_Side;
waypoint->type_direction = FP_GameDirection_Down;
waypoint->type = FP_GameWaypointType_Offset;
waypoint->offset = closest_swarm_pos - entity_pos;
}
}
}