fp: Start drafting up swarming of buildings
This commit is contained in:
parent
158fcb12fe
commit
a35cb8d2a6
101
feely_pona.cpp
101
feely_pona.cpp
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -669,6 +669,10 @@ static Dqn_V2 FP_Game_CalcWaypointWorldPos(FP_Game *game, FP_GameWaypoint const
|
||||
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case FP_GameWaypointType_Offset: {
|
||||
result = FP_Game_CalcEntityWorldPos(game, waypoint_entity->handle) + waypoint->offset;
|
||||
} break;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -66,8 +66,9 @@ enum FP_GameWaypointArrive
|
||||
|
||||
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
|
||||
FP_GameWaypointType_At, // Move to the specified entity
|
||||
FP_GameWaypointType_Side, // Move to the side of the entity specified by the direction
|
||||
FP_GameWaypointType_Offset, // Move to the designed offset from the entity
|
||||
};
|
||||
|
||||
enum FP_GameDirection
|
||||
@ -82,10 +83,11 @@ enum FP_GameDirection
|
||||
struct FP_GameWaypoint
|
||||
{
|
||||
FP_GameWaypointType type;
|
||||
FP_GameDirection type_direction;
|
||||
FP_GameEntityHandle entity;
|
||||
FP_GameDirection type_direction; // Used if type is `FP_GameWaypointType_Side`
|
||||
FP_GameEntityHandle entity; // The entity to move to
|
||||
FP_GameWaypointArrive arrive;
|
||||
Dqn_f32 value;
|
||||
Dqn_f32 value; // Used for `arrive` threshold
|
||||
Dqn_V2 offset; // Used if type is `FP_GameWaypointType_Offset`
|
||||
};
|
||||
|
||||
struct FP_GameEntitySpawnList
|
||||
@ -120,6 +122,12 @@ struct FP_GameRenderSprite
|
||||
uint64_t started_at_clock_ms;
|
||||
};
|
||||
|
||||
struct FP_GameSwarm
|
||||
{
|
||||
Dqn_FArray<FP_SentinelList<FP_GameEntityHandle>, 8> slots;
|
||||
Dqn_usize slots_active;
|
||||
};
|
||||
|
||||
struct FP_GameEntity
|
||||
{
|
||||
FP_GameEntity *next;
|
||||
@ -145,6 +153,7 @@ struct FP_GameEntity
|
||||
|
||||
FP_SentinelList<FP_GameWaypoint> waypoints;
|
||||
FP_GameEntityHandle aggro_slot[FP_GameDirection_Count];
|
||||
FP_GameSwarm swarm[FP_GameDirection_Count];
|
||||
|
||||
// NOTE: The entity hit box is positioned at the center of the entity.
|
||||
Dqn_V2 local_hit_box_size;
|
||||
|
Loading…
Reference in New Issue
Block a user