fp: Add sentinel DS, fix physics step, fix waypoints
This commit is contained in:
		
							parent
							
								
									677486e094
								
							
						
					
					
						commit
						219425fc96
					
				
							
								
								
									
										232
									
								
								feely_pona.cpp
									
									
									
									
									
								
							
							
						
						
									
										232
									
								
								feely_pona.cpp
									
									
									
									
									
								
							| @ -3,6 +3,7 @@ | |||||||
| #include "feely_pona_unity.h" | #include "feely_pona_unity.h" | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | Dqn_f32 const PHYSICS_STEP = 1 / 60.f; | ||||||
| struct FP_GlobalAnimations | struct FP_GlobalAnimations | ||||||
| { | { | ||||||
|     Dqn_String8 terry_walk_idle       = DQN_STRING8("terry_walk_idle"); |     Dqn_String8 terry_walk_idle       = DQN_STRING8("terry_walk_idle"); | ||||||
| @ -257,28 +258,60 @@ void TELY_DLL_Init(void *user_data) | |||||||
|     // NOTE: Mob spawner ===========================================================================
 |     // NOTE: Mob spawner ===========================================================================
 | ||||||
|     { |     { | ||||||
|         FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, "Mob spawner"); |         FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, "Mob spawner"); | ||||||
|         entity->local_pos     = Dqn_V2_InitNx2(50.f, platform->core.window_size.y * .5f); |         { | ||||||
|         entity->flags        |= FP_GameEntityFlag_Clickable; |             entity->local_pos           = Dqn_V2_InitNx2(50.f, platform->core.window_size.y * .5f); | ||||||
|         entity->flags        |= FP_GameEntityFlag_MoveByKeyboard; |             entity->local_hit_box_size  = Dqn_V2_InitNx1(32); | ||||||
|         entity->flags        |= FP_GameEntityFlag_MoveByMouse; |             entity->flags              |= FP_GameEntityFlag_Clickable; | ||||||
|         entity->flags        |= FP_GameEntityFlag_MoveByGamepad; |             entity->flags              |= FP_GameEntityFlag_MoveByKeyboard; | ||||||
|         entity->flags        |= FP_GameEntityFlag_MobSpawner; |             entity->flags              |= FP_GameEntityFlag_MoveByMouse; | ||||||
|  |             entity->flags              |= FP_GameEntityFlag_MoveByGamepad; | ||||||
|  |             entity->flags              |= FP_GameEntityFlag_MobSpawner; | ||||||
| 
 | 
 | ||||||
|         entity->spawn_cap        = 16; |             entity->spawn_cap  = 16; | ||||||
|         entity->spawn_list       = TELY_ChunkPool_New(game->chunk_pool, FP_GameEntitySpawnList); |             entity->spawn_list = FP_SentinelList_Init<FP_GameEntityHandle>(game->chunk_pool); | ||||||
|         entity->spawn_list->next = entity->spawn_list; | 
 | ||||||
|         entity->spawn_list->prev = entity->spawn_list; |             FP_GameShape *shape  = Dqn_FArray_Make(&entity->shapes, Dqn_ZeroMem_Yes); | ||||||
|  |             shape->type          = FP_GameShapeType_Rect; | ||||||
|  |             shape->p1            = {}; | ||||||
|  |             shape->p2            = entity->local_hit_box_size; | ||||||
|  |             shape->render_mode   = TELY_RenderShapeMode_Line; | ||||||
|  |             shape->colour        = TELY_COLOUR_BLUE_CADET_V4; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         FP_Game_PushParentEntity(game, entity->handle); |         FP_Game_PushParentEntity(game, entity->handle); | ||||||
|         { |         { | ||||||
|             { |             { | ||||||
|                 FP_GameEntity *waypoint = FP_Game_MakeEntityPointerF(game, "Waypoint"); |                 FP_GameEntity *waypoint      = FP_Game_MakeEntityPointerF(game, "Waypoint"); | ||||||
|                 waypoint->local_pos     = Dqn_V2_InitNx2(800.f, 100.f); |                 waypoint->local_pos          = Dqn_V2_InitNx2(800.f, -200.f); | ||||||
|  |                 waypoint->local_hit_box_size = Dqn_V2_InitNx1(32); | ||||||
|                 waypoint->flags        |= FP_GameEntityFlag_Clickable; |                 waypoint->flags        |= FP_GameEntityFlag_Clickable; | ||||||
|                 waypoint->flags        |= FP_GameEntityFlag_MoveByKeyboard; |                 waypoint->flags        |= FP_GameEntityFlag_MoveByKeyboard; | ||||||
|                 waypoint->flags        |= FP_GameEntityFlag_MoveByMouse; |                 waypoint->flags        |= FP_GameEntityFlag_MoveByMouse; | ||||||
|                 waypoint->flags        |= FP_GameEntityFlag_MoveByGamepad; |                 waypoint->flags        |= FP_GameEntityFlag_MoveByGamepad; | ||||||
|                 waypoint->flags        |= FP_GameEntityFlag_MobSpawnerWaypoint; |                 waypoint->flags        |= FP_GameEntityFlag_MobSpawnerWaypoint; | ||||||
|  | 
 | ||||||
|  |                 FP_GameShape *shape  = Dqn_FArray_Make(&waypoint->shapes, Dqn_ZeroMem_Yes); | ||||||
|  |                 shape->type          = FP_GameShapeType_Circle; | ||||||
|  |                 shape->circle_radius = 16.f; | ||||||
|  |                 shape->render_mode   = TELY_RenderShapeMode_Line; | ||||||
|  |                 shape->colour        = TELY_COLOUR_BLUE_CADET_V4; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             { | ||||||
|  |                 FP_GameEntity *waypoint      = FP_Game_MakeEntityPointerF(game, "Waypoint"); | ||||||
|  |                 waypoint->local_pos          = Dqn_V2_InitNx2(932.f, 200.f); | ||||||
|  |                 waypoint->local_hit_box_size = Dqn_V2_InitNx1(32); | ||||||
|  |                 waypoint->flags        |= FP_GameEntityFlag_Clickable; | ||||||
|  |                 waypoint->flags        |= FP_GameEntityFlag_MoveByKeyboard; | ||||||
|  |                 waypoint->flags        |= FP_GameEntityFlag_MoveByMouse; | ||||||
|  |                 waypoint->flags        |= FP_GameEntityFlag_MoveByGamepad; | ||||||
|  |                 waypoint->flags        |= FP_GameEntityFlag_MobSpawnerWaypoint; | ||||||
|  | 
 | ||||||
|  |                 FP_GameShape *shape  = Dqn_FArray_Make(&waypoint->shapes, Dqn_ZeroMem_Yes); | ||||||
|  |                 shape->type          = FP_GameShapeType_Circle; | ||||||
|  |                 shape->circle_radius = 16.f; | ||||||
|  |                 shape->render_mode   = TELY_RenderShapeMode_Line; | ||||||
|  |                 shape->colour        = TELY_COLOUR_BLUE_CADET_V4; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         FP_Game_PopParentEntity(game); |         FP_Game_PopParentEntity(game); | ||||||
| @ -444,7 +477,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga | |||||||
|                         } |                         } | ||||||
| 
 | 
 | ||||||
|                         Dqn_V2 dash_acceleration = dash_dir * 400'000'000.f; |                         Dqn_V2 dash_acceleration = dash_dir * 400'000'000.f; | ||||||
|                         Dqn_f32 t                = DQN_CAST(Dqn_f32)DQN_SQUARED(input->delta_s); |                         Dqn_f32 t                = DQN_CAST(Dqn_f32)DQN_SQUARED(PHYSICS_STEP); | ||||||
|                         entity->velocity         = (dash_acceleration * t) + entity->velocity * 2.0f; |                         entity->velocity         = (dash_acceleration * t) + entity->velocity * 2.0f; | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
| @ -618,7 +651,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_Renderer *renderer, TELY_PlatformInput *input) | void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input) | ||||||
| { | { | ||||||
|     Dqn_Profiler_ZoneScopeWithIndex("FP_Update", FP_ProfileZone_FPUpdate); |     Dqn_Profiler_ZoneScopeWithIndex("FP_Update", FP_ProfileZone_FPUpdate); | ||||||
| 
 | 
 | ||||||
| @ -662,7 +695,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_Renderer *renderer, | |||||||
|     Dqn_ProfilerZone update_zone = Dqn_Profiler_BeginZoneWithIndex(DQN_STRING8("FP_Update: Entity loop"), FP_ProfileZone_FPUpdate_EntityLoop); |     Dqn_ProfilerZone update_zone = Dqn_Profiler_BeginZoneWithIndex(DQN_STRING8("FP_Update: Entity loop"), FP_ProfileZone_FPUpdate_EntityLoop); | ||||||
|     for (FP_GameEntityIterator it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity); ) { |     for (FP_GameEntityIterator it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity); ) { | ||||||
|         FP_GameEntity *entity  = it.entity; |         FP_GameEntity *entity  = it.entity; | ||||||
|         entity->alive_time_s    += input->delta_s; |         entity->alive_time_s  += PHYSICS_STEP; | ||||||
| 
 | 
 | ||||||
|         // NOTE: Move entity by keyboard and gamepad ===============================================
 |         // NOTE: Move entity by keyboard and gamepad ===============================================
 | ||||||
|         Dqn_V2 acceleration = {}; |         Dqn_V2 acceleration = {}; | ||||||
| @ -671,16 +704,17 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_Renderer *renderer, | |||||||
|                 bool move_entity = false; |                 bool move_entity = false; | ||||||
|                 switch (entity->type) { |                 switch (entity->type) { | ||||||
|                     case FP_EntityType_Terry: { |                     case FP_EntityType_Terry: { | ||||||
|                         FP_EntityTerryState *state = DQN_CAST(FP_EntityTerryState *)&entity->action.state; |                         auto *state = DQN_CAST(FP_EntityTerryState *)&entity->action.state; | ||||||
|                         move_entity              = *state == FP_EntityTerryState_Run || *state == FP_EntityTerryState_Idle; |                         move_entity = *state == FP_EntityTerryState_Run || *state == FP_EntityTerryState_Idle; | ||||||
|                     } break; |                     } break; | ||||||
| 
 | 
 | ||||||
|                     case FP_EntityType_Smoochie: { |                     case FP_EntityType_Smoochie: { | ||||||
|                         FP_EntitySmoochieState *state = DQN_CAST(FP_EntitySmoochieState *)&entity->action.state; |                         auto *state = DQN_CAST(FP_EntitySmoochieState *)&entity->action.state; | ||||||
|                         move_entity                 = *state == FP_EntitySmoochieState_Run || *state == FP_EntitySmoochieState_Idle; |                         move_entity = *state == FP_EntitySmoochieState_Run || *state == FP_EntitySmoochieState_Idle; | ||||||
|                     } break; |                     } break; | ||||||
| 
 | 
 | ||||||
|                     case FP_EntityType_Merchant: break; |                     case FP_EntityType_Merchant: move_entity = true; break; | ||||||
|  |                     case FP_EntityType_Nil:      move_entity = true; break; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if (move_entity) { |                 if (move_entity) { | ||||||
| @ -693,61 +727,33 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_Renderer *renderer, | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // NOTE: Stalk entity ======================================================================
 |         // NOTE: Determine acceleration to move towards next waypoint if we have one
 | ||||||
|         Dqn_V2 entity_world_pos = FP_Game_CalcEntityWorldPos(game, entity->handle); |         if (acceleration.x == 0 && acceleration.y == 0) { | ||||||
|         #if 0 |             while (entity->waypoints.size) { | ||||||
|         { |                 FP_SentinelListLink<FP_GameEntityHandle> *waypoint_link = entity->waypoints.sentinel->next; | ||||||
|             FP_GameEntity *stalk_entity = FP_Game_GetEntity(game, entity->stalk_entity); |                 FP_GameEntity *waypoint = FP_Game_GetEntity(game, waypoint_link->data); | ||||||
|             if (stalk_entity->handle.id) { |                 if (FP_Game_IsNilEntity(waypoint)) { | ||||||
|                 Dqn_Profiler_ZoneScopeWithIndex("FP_Update: Path finding", FP_ProfileZone_FPUpdate_PathFinding); |                     FP_SentinelList_Erase(&entity->waypoints, waypoint_link, game->chunk_pool); | ||||||
|                 Dqn_V2 stalk_world_pos = FP_Game_CalcEntityWorldPos(game, stalk_entity->handle); |                     continue; | ||||||
|                 Dqn_V2I stalk_tile     = Dqn_V2I_InitNx2(stalk_world_pos.x / game->tile_size, stalk_world_pos.y / game->tile_size); |  | ||||||
|                 if (entity->stalk_entity_last_known_tile != stalk_tile) { |  | ||||||
|                     entity->stalk_entity_last_known_tile = stalk_tile; |  | ||||||
| 
 |  | ||||||
|                     // NOTE: Dealloc all waypoints
 |  | ||||||
|                     for (FP_GameWaypoint *waypoint = entity->waypoints->next; waypoint != entity->waypoints; ) { |  | ||||||
|                         FP_GameWaypoint *next = waypoint->next; |  | ||||||
|                         TELY_ChunkPool_Dealloc(game->chunk_pool, waypoint); |  | ||||||
|                         waypoint               = next; |  | ||||||
|                     } |  | ||||||
|                     entity->waypoints->next = entity->waypoints; |  | ||||||
|                     entity->waypoints->prev = entity->waypoints; |  | ||||||
| 
 |  | ||||||
|                     Dqn_Slice<Dqn_V2I> path_find = FP_Game_AStarPathFind(game, &platform->frame_arena, platform, entity->handle, stalk_tile); |  | ||||||
|                     for (Dqn_usize index = path_find.size - 1; index < path_find.size; index--) { |  | ||||||
|                         FP_GameWaypoint *waypoint = TELY_ChunkPool_New(game->chunk_pool, FP_GameWaypoint); |  | ||||||
|                         waypoint->pos             = path_find.data[index]; |  | ||||||
|                         waypoint->next            = entity->waypoints; |  | ||||||
|                         waypoint->prev            = entity->waypoints->prev; |  | ||||||
|                         waypoint->next->prev      = waypoint; |  | ||||||
|                         waypoint->prev->next      = waypoint; |  | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         #endif |  | ||||||
| 
 | 
 | ||||||
|         // NOTE: Render the waypoints
 |                 // NOTE: We found a waypoint that is valid to move towards
 | ||||||
|         for (FP_GameWaypoint *waypoint = entity->waypoints->next; waypoint != entity->waypoints; waypoint = waypoint->next) { |                 Dqn_V2 waypoint_pos       = FP_Game_CalcEntityWorldPos(game, waypoint->handle); | ||||||
|             Dqn_V2 circle_pos = Dqn_V2_InitNx2(waypoint->pos.x, waypoint->pos.y); |                 Dqn_V2 entity_pos         = FP_Game_CalcEntityWorldPos(game, entity->handle); | ||||||
|             TELY_Render_CircleColourV4(renderer, circle_pos, 4.f, TELY_RenderShapeMode_Fill, TELY_COLOUR_MAGENTA_V4); |                 Dqn_V2 entity_to_waypoint = waypoint_pos - entity_pos; | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         if (entity->waypoints->next != entity->waypoints) { |                 // NOTE: Check if we've arrived at the waypoint
 | ||||||
|             FP_GameWaypoint *waypoint   = entity->waypoints->next; |                 Dqn_f32 dist_to_waypoint_sq = Dqn_V2_LengthSq(entity_to_waypoint); | ||||||
|             Dqn_V2 target_pos           = Dqn_V2_InitV2I(entity->waypoints->next->pos); |                 Dqn_f32 arrival_threshold   = DQN_MIN(DQN_SQUARED(entity->local_hit_box_size.x * .5f), 10.f); | ||||||
|             Dqn_V2 entity_to_target_pos = target_pos - entity_world_pos; |                 if (dist_to_waypoint_sq < arrival_threshold) { | ||||||
| 
 |                     FP_SentinelList_Erase(&entity->waypoints, waypoint_link, game->chunk_pool); | ||||||
|             if (Dqn_V2_LengthSq(entity_to_target_pos) < DQN_SQUARED(entity->local_hit_box_size.x * .5f)) { |                     continue; | ||||||
|                 waypoint->next->prev = waypoint->prev; |  | ||||||
|                 waypoint->prev->next = waypoint->next; |  | ||||||
|                 TELY_ChunkPool_Dealloc(game->chunk_pool, waypoint); |  | ||||||
|             } else { |  | ||||||
|                 Dqn_V2 entity_to_target_pos_norm = Dqn_V2_Normalise(entity_to_target_pos); |  | ||||||
|                 if (acceleration.x == 0 && acceleration.y == 0) { |  | ||||||
|                     acceleration = entity_to_target_pos_norm * 1'000'000.f; |  | ||||||
|                 } |                 } | ||||||
|  | 
 | ||||||
|  |                 // NOTE: We haven't arrived yet, calculate an acceleration vector to the waypoint
 | ||||||
|  |                 Dqn_V2 entity_to_waypoint_norm = Dqn_V2_Normalise(entity_to_waypoint); | ||||||
|  |                 acceleration                   = entity_to_waypoint_norm * 1'000'000.f; | ||||||
|  |                 break; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -757,7 +763,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_Renderer *renderer, | |||||||
|             // f"(t) = a
 |             // f"(t) = a
 | ||||||
|             // f'(t) = at + v
 |             // f'(t) = at + v
 | ||||||
|             // f (t) = 0.5f*a(t^2) + vt + p
 |             // f (t) = 0.5f*a(t^2) + vt + p
 | ||||||
|             Dqn_f32 t          = DQN_CAST(Dqn_f32)DQN_SQUARED(input->delta_s); |             Dqn_f32 t          = DQN_CAST(Dqn_f32)DQN_SQUARED(PHYSICS_STEP); | ||||||
|             Dqn_f32 t_squared  = DQN_SQUARED(t); |             Dqn_f32 t_squared  = DQN_SQUARED(t); | ||||||
| 
 | 
 | ||||||
|             Dqn_f32 velocity_falloff_coefficient = 0.25f; |             Dqn_f32 velocity_falloff_coefficient = 0.25f; | ||||||
| @ -785,6 +791,10 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_Renderer *renderer, | |||||||
|                 if (collider->handle == entity->handle) |                 if (collider->handle == entity->handle) | ||||||
|                     continue; |                     continue; | ||||||
| 
 | 
 | ||||||
|  |                 // TODO(doyle): Calculate the list of collidables at the start of the frame
 | ||||||
|  |                 if ((collider->flags & FP_GameEntityFlag_NonTraversable) == 0) | ||||||
|  |                     continue; | ||||||
|  | 
 | ||||||
|                 // NOTE: Sweep collider with half the radius of the source entity
 |                 // NOTE: Sweep collider with half the radius of the source entity
 | ||||||
|                 Dqn_Rect collider_world_hit_box       = FP_Game_CalcEntityWorldHitBox(game, collider->handle); |                 Dqn_Rect collider_world_hit_box       = FP_Game_CalcEntityWorldHitBox(game, collider->handle); | ||||||
|                 Dqn_Rect swept_collider_world_hit_box = collider_world_hit_box; |                 Dqn_Rect swept_collider_world_hit_box = collider_world_hit_box; | ||||||
| @ -875,50 +885,33 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_Renderer *renderer, | |||||||
| 
 | 
 | ||||||
|         // NOTE: Mob spawner =======================================================================
 |         // NOTE: Mob spawner =======================================================================
 | ||||||
|         if (entity->flags & FP_GameEntityFlag_MobSpawner) { |         if (entity->flags & FP_GameEntityFlag_MobSpawner) { | ||||||
|             // NOTE: Check if any spawned entities dies to remove it from the spawn cap tracker
 |  | ||||||
|             for (FP_GameEntitySpawnList *link = entity->spawn_list->next; link != entity->spawn_list;) { |  | ||||||
|                 FP_GameEntity *spawned_entity = FP_Game_GetEntity(game, link->entity); |  | ||||||
|                 if (spawned_entity) { |  | ||||||
|                     // NOTE: Spawned entity is still alive
 |  | ||||||
|                     link = link->next; |  | ||||||
|                     continue; |  | ||||||
|                 } |  | ||||||
| 
 | 
 | ||||||
|                 DQN_ASSERT(entity->spawn_count); |             // NOTE: Flush any spawn entities that are dead
 | ||||||
|                 entity->spawn_count--; |             for (FP_SentinelListLink<FP_GameEntityHandle> *link = nullptr; FP_SentinelList_Iterate<FP_GameEntityHandle>(&entity->spawn_list, &link); ) { | ||||||
| 
 |                 FP_GameEntity *spawned_entity = FP_Game_GetEntity(game, link->data); | ||||||
|                 // NOTE: Entity is dead remove it from the linked list
 |                 if (FP_Game_IsNilEntity(spawned_entity)) // NOTE: Entity is dead remove it from the linked list
 | ||||||
|                 FP_GameEntitySpawnList *link_to_delete = link; |                     link = FP_SentinelList_Erase(&entity->spawn_list, link, game->chunk_pool); | ||||||
|                 link->next->prev                       = link->prev; |  | ||||||
|                 link->prev->next                       = link->next; |  | ||||||
|                 link                                   = link->next; |  | ||||||
|                 TELY_ChunkPool_Dealloc(game->chunk_pool, link_to_delete); |  | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if (entity->spawn_count < entity->spawn_cap) { // NOTE: Spawn new entities
 |             if (entity->spawn_list.size < entity->spawn_cap) { // NOTE: Spawn new entities
 | ||||||
|                 if (input->timer_s >= entity->next_spawn_timestamp_s) { |                 if (input->timer_s >= entity->next_spawn_timestamp_s) { | ||||||
|                     entity->next_spawn_timestamp_s = DQN_CAST(uint64_t)(input->timer_s + 5.f); |                     entity->next_spawn_timestamp_s = DQN_CAST(uint64_t)(input->timer_s + 5.f); | ||||||
|                     entity->spawn_count++; |  | ||||||
| 
 | 
 | ||||||
|                     FP_GameEntitySpawnList *item = TELY_ChunkPool_New(game->chunk_pool, FP_GameEntitySpawnList); |                     Dqn_V2 entity_world_pos                        = FP_Game_CalcEntityWorldPos(game, entity->handle); | ||||||
|                     item->entity                 = FP_Game_EntityAddMob(game, entity_world_pos); |                     FP_SentinelListLink<FP_GameEntityHandle> *link = FP_SentinelList_Make(&entity->spawn_list, game->chunk_pool); | ||||||
|                     FP_SentinelDoublyLinkedList_Insert(entity->spawn_list, item); |                     link->data                                     = FP_Game_EntityAddMob(game, entity_world_pos); | ||||||
| 
 | 
 | ||||||
|                     // NOTE: Setup the mob with a sentinel waypoint
 |                     // NOTE: Setup the mob with waypoints
 | ||||||
|                     FP_GameEntity *mob = FP_Game_GetEntity(game, item->entity); |                     FP_GameEntity *mob = FP_Game_GetEntity(game, link->data); | ||||||
|                     mob->waypoints     = TELY_ChunkPool_New(game->chunk_pool, FP_GameWaypoint); |                     mob->waypoints     = FP_SentinelList_Init<FP_GameEntityHandle>(game->chunk_pool); | ||||||
|                     mob->waypoints->next = mob->waypoints; |  | ||||||
|                     mob->waypoints->prev = mob->waypoints; |  | ||||||
| 
 | 
 | ||||||
|                     for (FP_GameEntity *waypoint_entity = entity->first_child; waypoint_entity; waypoint_entity = waypoint_entity->next) { |                     for (FP_GameEntity *waypoint_entity = entity->first_child; waypoint_entity; waypoint_entity = waypoint_entity->next) { | ||||||
|                         if ((waypoint_entity->flags & FP_GameEntityFlag_MobSpawnerWaypoint) == 0) |                         if ((waypoint_entity->flags & FP_GameEntityFlag_MobSpawnerWaypoint) == 0) | ||||||
|                             continue; |                             continue; | ||||||
| 
 | 
 | ||||||
|                         // NOTE: Add the waypoint
 |                         // NOTE: Add the waypoint
 | ||||||
|                         FP_GameWaypoint *waypoint = TELY_ChunkPool_New(game->chunk_pool, FP_GameWaypoint); |                         FP_SentinelListLink<FP_GameEntityHandle> *waypoint = FP_SentinelList_Make(&mob->waypoints, game->chunk_pool); | ||||||
|                         Dqn_V2 waypoint_pos       = FP_Game_CalcEntityWorldPos(game, waypoint_entity->handle); |                         waypoint->data                                     = waypoint_entity->handle; | ||||||
|                         waypoint->pos             = Dqn_V2I_InitV2(waypoint_pos); |  | ||||||
|                         FP_SentinelDoublyLinkedList_Insert(mob->waypoints, waypoint); |  | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -955,7 +948,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_Renderer *renderer, | |||||||
|                 attack_dir_vector.x = -1.f; |                 attack_dir_vector.x = -1.f; | ||||||
| 
 | 
 | ||||||
|             Dqn_V2 acceleration  = attack_dir_vector * 500'000.f; |             Dqn_V2 acceleration  = attack_dir_vector * 500'000.f; | ||||||
|             Dqn_f32 t            = DQN_CAST(Dqn_f32)DQN_SQUARED(input->delta_s); |             Dqn_f32 t            = DQN_CAST(Dqn_f32)DQN_SQUARED(PHYSICS_STEP); | ||||||
|             Dqn_f32 t_squared    = DQN_SQUARED(t); |             Dqn_f32 t_squared    = DQN_SQUARED(t); | ||||||
| 
 | 
 | ||||||
|             Dqn_V2 delta_p     = (acceleration * 0.5f * t_squared) + (defender->velocity * t); |             Dqn_V2 delta_p     = (acceleration * 0.5f * t_squared) + (defender->velocity * t); | ||||||
| @ -991,7 +984,6 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer) | |||||||
|     // NOTE: Draw entities =========================================================================
 |     // NOTE: Draw entities =========================================================================
 | ||||||
|     for (FP_GameEntityIterator it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity); ) { |     for (FP_GameEntityIterator it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity); ) { | ||||||
|         FP_GameEntity *entity  = it.entity; |         FP_GameEntity *entity  = it.entity; | ||||||
|         entity->alive_time_s    += input->delta_s; |  | ||||||
| 
 | 
 | ||||||
|         // NOTE: Render shapes in entity ===========================================================
 |         // NOTE: Render shapes in entity ===========================================================
 | ||||||
|         Dqn_V2 world_pos = FP_Game_CalcEntityWorldPos(game, entity->handle); |         Dqn_V2 world_pos = FP_Game_CalcEntityWorldPos(game, entity->handle); | ||||||
| @ -1058,6 +1050,18 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer) | |||||||
|             TELY_Render_TextureColourV4(renderer, sprite.sheet->tex_handle, src_rect, dest_rect, TELY_COLOUR_WHITE_V4); |             TELY_Render_TextureColourV4(renderer, sprite.sheet->tex_handle, src_rect, dest_rect, TELY_COLOUR_WHITE_V4); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         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) { | ||||||
|  |                 if ((waypoint_entity->flags & FP_GameEntityFlag_MobSpawnerWaypoint) == 0) | ||||||
|  |                     continue; | ||||||
|  | 
 | ||||||
|  |                 Dqn_V2 end = FP_Game_CalcEntityWorldPos(game, waypoint_entity->handle); | ||||||
|  |                 TELY_Render_LineColourV4(renderer, start, end, TELY_COLOUR_BLUE_CADET_V4, 2.f); | ||||||
|  |                 start = end; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         // NOTE: Render attack box =================================================================
 |         // NOTE: Render attack box =================================================================
 | ||||||
|         { |         { | ||||||
|             Dqn_Rect attack_box = FP_Game_CalcEntityAttackWorldHitBox(game, entity->handle); |             Dqn_Rect attack_box = FP_Game_CalcEntityAttackWorldHitBox(game, entity->handle); | ||||||
| @ -1071,6 +1075,21 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer) | |||||||
|         Dqn_Rect world_hit_box = FP_Game_CalcEntityWorldHitBox(game, entity->handle); |         Dqn_Rect world_hit_box = FP_Game_CalcEntityWorldHitBox(game, entity->handle); | ||||||
|         if (game->clicked_entity == entity->handle) { |         if (game->clicked_entity == entity->handle) { | ||||||
|             TELY_Render_RectColourV4(renderer, world_hit_box, TELY_RenderShapeMode_Line, TELY_COLOUR_WHITE_PALE_GOLDENROD_V4); |             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<FP_GameEntityHandle> *link = nullptr; FP_SentinelList_Iterate(&entity->waypoints, &link); ) { | ||||||
|  |                     FP_GameEntity *waypoint = FP_Game_GetEntity(game, link->data); | ||||||
|  |                     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; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|         } else if (game->hot_entity == entity->handle || (entity->flags & FP_GameEntityFlag_DrawHitBox)) { |         } 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); |             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); | ||||||
| @ -1158,11 +1177,10 @@ void TELY_DLL_FrameUpdate(void *user_data) | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     Dqn_f32 const PHYSICS_STEP = 1 / 60.f; |  | ||||||
|     for (game->delta_s_accumulator += DQN_CAST(Dqn_f32)input->delta_s; |     for (game->delta_s_accumulator += DQN_CAST(Dqn_f32)input->delta_s; | ||||||
|          game->delta_s_accumulator > PHYSICS_STEP; |          game->delta_s_accumulator > PHYSICS_STEP; | ||||||
|          game->delta_s_accumulator -= PHYSICS_STEP) { |          game->delta_s_accumulator -= PHYSICS_STEP) { | ||||||
|         FP_Update(platform, game, renderer, input); |         FP_Update(platform, game, input); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     FP_Render(game, platform, renderer); |     FP_Render(game, platform, renderer); | ||||||
|  | |||||||
| @ -203,12 +203,9 @@ static FP_GameEntity *FP_Game_MakeEntityPointerFV(FP_Game *game, DQN_FMT_STRING_ | |||||||
|         result->handle.id = (game->entities.size - 1) & FP_GAME_ENTITY_HANDLE_INDEX_MASK; |         result->handle.id = (game->entities.size - 1) & FP_GAME_ENTITY_HANDLE_INDEX_MASK; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     result->size_scale      = Dqn_V2_InitNx1(1); |     result->size_scale = Dqn_V2_InitNx1(1); | ||||||
|     result->parent          = FP_Game_ActiveParentEntityPointer(game); |     result->parent     = FP_Game_ActiveParentEntityPointer(game); | ||||||
|     result->name            = TELY_ChunkPool_AllocFmtFV(game->chunk_pool, fmt, args); |     result->name       = TELY_ChunkPool_AllocFmtFV(game->chunk_pool, fmt, args); | ||||||
|     result->waypoints       = TELY_ChunkPool_New(game->chunk_pool, FP_GameWaypoint); |  | ||||||
|     result->waypoints->next = result->waypoints; |  | ||||||
|     result->waypoints->prev = result->waypoints; |  | ||||||
| 
 | 
 | ||||||
|     // NOTE: Attach entity as a child to the parent
 |     // NOTE: Attach entity as a child to the parent
 | ||||||
|     FP_GameEntity *parent = result->parent; |     FP_GameEntity *parent = result->parent; | ||||||
| @ -292,8 +289,8 @@ static void FP_Game_DetachEntityIntoFreeList(FP_Game *game, FP_GameEntityHandle | |||||||
|     if (entity->name.size) |     if (entity->name.size) | ||||||
|         TELY_ChunkPool_Dealloc(game->chunk_pool, entity->name.data); |         TELY_ChunkPool_Dealloc(game->chunk_pool, entity->name.data); | ||||||
| 
 | 
 | ||||||
|     if (entity->spawn_list) |     FP_SentinelList_Deinit(&entity->spawn_list, game->chunk_pool); | ||||||
|         TELY_ChunkPool_Dealloc(game->chunk_pool, entity->spawn_list); |     FP_SentinelList_Deinit(&entity->waypoints, game->chunk_pool); | ||||||
| 
 | 
 | ||||||
|     if (new_entity_generation > entity_generation) { |     if (new_entity_generation > entity_generation) { | ||||||
|         // NOTE: Update the incremented handle disassociating all prior handles
 |         // NOTE: Update the incremented handle disassociating all prior handles
 | ||||||
| @ -654,17 +651,15 @@ static FP_GameEntityHandle FP_Game_EntityAddWallAtTile(FP_Game *game, Dqn_String | |||||||
| 
 | 
 | ||||||
| static FP_GameEntityHandle FP_Game_EntityAddMob(FP_Game *game, Dqn_V2 pos) | static FP_GameEntityHandle FP_Game_EntityAddMob(FP_Game *game, Dqn_V2 pos) | ||||||
| { | { | ||||||
|     FP_GameEntity *entity           = FP_Game_MakeEntityPointerF(game, "Mob"); |     FP_GameEntity *entity       = FP_Game_MakeEntityPointerF(game, "Mob"); | ||||||
|     entity->type                    = FP_EntityType_Smoochie; |     entity->type                = FP_EntityType_Smoochie; | ||||||
|     entity->local_pos               = pos; |     entity->local_pos           = pos; | ||||||
|     entity->size_scale              = Dqn_V2_InitNx1(.25f); |     entity->size_scale          = Dqn_V2_InitNx1(.25f); | ||||||
|     entity->local_hit_box_size      = Dqn_V2_InitNx2(428, 471) * entity->size_scale; |     entity->local_hit_box_size  = Dqn_V2_InitNx2(428, 471) * entity->size_scale; | ||||||
|     entity->flags                  |= FP_GameEntityFlag_Clickable; |     entity->flags              |= FP_GameEntityFlag_Clickable; | ||||||
|     entity->flags                  |= FP_GameEntityFlag_MoveByKeyboard; |     entity->flags              |= FP_GameEntityFlag_MoveByKeyboard; | ||||||
|     entity->flags                  |= FP_GameEntityFlag_MoveByMouse; |     entity->flags              |= FP_GameEntityFlag_MoveByMouse; | ||||||
|     entity->flags                  |= FP_GameEntityFlag_NonTraversable; |     entity->flags              |= FP_GameEntityFlag_NonTraversable; | ||||||
|     entity->stalk_entity            = game->player; |     FP_GameEntityHandle result  = entity->handle; | ||||||
| 
 |  | ||||||
|     FP_GameEntityHandle result = entity->handle; |  | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
|  | |||||||
| @ -92,36 +92,33 @@ struct FP_GameEntity | |||||||
|     FP_GameEntity                         *last_child; |     FP_GameEntity                         *last_child; | ||||||
|     FP_GameEntity                         *parent; |     FP_GameEntity                         *parent; | ||||||
| 
 | 
 | ||||||
|     FP_EntityType                          type; |     FP_EntityType                         type; | ||||||
|     Dqn_String8                            name; |     Dqn_String8                           name; | ||||||
|     FP_GameEntityHandle                    handle; |     FP_GameEntityHandle                   handle; | ||||||
| 
 | 
 | ||||||
|     Dqn_V2                                 size_scale; |     Dqn_V2                                size_scale; | ||||||
|     FP_GameEntityAction                    action; |     FP_GameEntityAction                   action; | ||||||
|     Dqn_V2                                 velocity; |     Dqn_V2                                velocity; | ||||||
| 
 | 
 | ||||||
|     FP_GameEntityHandle                    stalk_entity; |     FP_SentinelList<FP_GameEntityHandle>  waypoints; | ||||||
|     Dqn_V2I                                stalk_entity_last_known_tile; |  | ||||||
|     FP_GameWaypoint                       *waypoints; |  | ||||||
| 
 | 
 | ||||||
|     // NOTE: The entity hit box is positioned at the center of the entity.
 |     // NOTE: The entity hit box is positioned at the center of the entity.
 | ||||||
|     Dqn_V2                                 local_hit_box_size; |     Dqn_V2                                local_hit_box_size; | ||||||
|     Dqn_V2                                 local_hit_box_offset; |     Dqn_V2                                local_hit_box_offset; | ||||||
| 
 | 
 | ||||||
|     Dqn_V2                                 attack_box_size; |     Dqn_V2                                attack_box_size; | ||||||
|     Dqn_V2                                 attack_box_offset; |     Dqn_V2                                attack_box_offset; | ||||||
| 
 | 
 | ||||||
|     Dqn_FArray<Dqn_V2, 8>                  spawner_waypoints; |     Dqn_FArray<Dqn_V2, 8>                 spawner_waypoints; | ||||||
|     FP_GameEntitySpawnList                *spawn_list; |     FP_SentinelList<FP_GameEntityHandle>  spawn_list; | ||||||
|     uint64_t                               next_spawn_timestamp_s; |     uint64_t                              next_spawn_timestamp_s; | ||||||
|     uint64_t                               spawn_count; |     uint64_t                              spawn_cap; | ||||||
|     uint64_t                               spawn_cap; |  | ||||||
| 
 | 
 | ||||||
|     uint64_t                               flags; |     uint64_t                              flags; | ||||||
|     FP_GameDirection                       direction; |     FP_GameDirection                      direction; | ||||||
|     Dqn_V2                                 local_pos; |     Dqn_V2                                local_pos; | ||||||
|     Dqn_f64                                alive_time_s; |     Dqn_f64                               alive_time_s; | ||||||
|     Dqn_FArray<FP_GameShape, 4>            shapes; |     Dqn_FArray<FP_GameShape, 4>           shapes; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct FP_GameEntityIterator | struct FP_GameEntityIterator | ||||||
|  | |||||||
							
								
								
									
										88
									
								
								feely_pona_stdlib.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								feely_pona_stdlib.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,88 @@ | |||||||
|  | #if defined(__clang__) | ||||||
|  | #pragma once | ||||||
|  | #include "feely_pona_unity.h" | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | template <typename T> | ||||||
|  | struct FP_SentinelListLink | ||||||
|  | { | ||||||
|  |     T                       data; | ||||||
|  |     FP_SentinelListLink<T> *next; | ||||||
|  |     FP_SentinelListLink<T> *prev; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | template <typename T> | ||||||
|  | struct FP_SentinelList | ||||||
|  | { | ||||||
|  |     Dqn_usize               size; | ||||||
|  |     FP_SentinelListLink<T> *sentinel; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | template <typename T> | ||||||
|  | bool FP_SentinelList_Iterate(FP_SentinelList<T> *list, FP_SentinelListLink<T> **it) | ||||||
|  | { | ||||||
|  |     if (!list || !list->sentinel || !it) | ||||||
|  |         return false; | ||||||
|  | 
 | ||||||
|  |     if (!DQN_CHECK(list->sentinel->next && list->sentinel->prev)) | ||||||
|  |         return false; | ||||||
|  | 
 | ||||||
|  |     if (!(*it)) | ||||||
|  |         *it = list->sentinel; | ||||||
|  | 
 | ||||||
|  |     bool result = list && (*it)->next != list->sentinel; | ||||||
|  |     if (result) | ||||||
|  |         (*it) = (*it)->next; | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template <typename T> | ||||||
|  | FP_SentinelList<T> FP_SentinelList_Init(TELY_ChunkPool *pool) | ||||||
|  | { | ||||||
|  |     FP_SentinelList<T> result = {}; | ||||||
|  |     result.sentinel           = TELY_ChunkPool_New(pool, FP_SentinelListLink<T>); | ||||||
|  |     result.sentinel->next     = result.sentinel->prev = result.sentinel; | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template <typename T> | ||||||
|  | FP_SentinelListLink<T> *FP_SentinelList_Make(FP_SentinelList<T> *list, TELY_ChunkPool *pool) | ||||||
|  | { | ||||||
|  |     DQN_ASSERT(list->sentinel->next); | ||||||
|  |     DQN_ASSERT(list->sentinel->prev); | ||||||
|  |     DQN_ASSERT(list->sentinel->prev->next == list->sentinel); | ||||||
|  |     DQN_ASSERT(list->sentinel->next->prev == list->sentinel); | ||||||
|  | 
 | ||||||
|  |     FP_SentinelListLink<T> *result = TELY_ChunkPool_New(pool, FP_SentinelListLink<T>); | ||||||
|  |     result->next                   = list->sentinel; | ||||||
|  |     result->prev                   = list->sentinel->prev; | ||||||
|  |     result->next->prev             = result; | ||||||
|  |     result->prev->next             = result; | ||||||
|  |     list->size++; | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template <typename T> | ||||||
|  | FP_SentinelListLink<T> *FP_SentinelList_Erase(FP_SentinelList<T> *list, FP_SentinelListLink<T> *link, TELY_ChunkPool *pool) | ||||||
|  | { | ||||||
|  |     FP_SentinelListLink<T> *result = link->prev; | ||||||
|  |     link->next->prev               = link->prev; | ||||||
|  |     link->prev->next               = link->next; | ||||||
|  |     TELY_ChunkPool_Dealloc(pool, link); | ||||||
|  |     list->size--; | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template <typename T> | ||||||
|  | void FP_SentinelList_Deinit(FP_SentinelList<T> *list, TELY_ChunkPool *pool) | ||||||
|  | { | ||||||
|  |     if (!list || !pool) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     for (FP_SentinelListLink<T> *link = nullptr; FP_SentinelList_Iterate(list, &link); ) | ||||||
|  |         link = FP_SentinelList_Erase(list, link, pool); | ||||||
|  | 
 | ||||||
|  |     TELY_ChunkPool_Dealloc(pool, list->sentinel); | ||||||
|  |     *list = {}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| @ -61,6 +61,7 @@ DQN_MSVC_WARNING_DISABLE(4505) // warning C4505: unreferenced function with inte | |||||||
| #include "External/tely/tely_rfui.cpp" | #include "External/tely/tely_rfui.cpp" | ||||||
| 
 | 
 | ||||||
| // NOTE: feely_pona ================================================================================
 | // NOTE: feely_pona ================================================================================
 | ||||||
|  | #include "feely_pona_stdlib.h" | ||||||
| #include "feely_pona_entity.h" | #include "feely_pona_entity.h" | ||||||
| #include "feely_pona_game.h" | #include "feely_pona_game.h" | ||||||
| #include "feely_pona.h" | #include "feely_pona.h" | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user