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…
Reference in New Issue
Block a user