From 7a2bebf3c3f0640eeea173367274a92c54d1e1e8 Mon Sep 17 00:00:00 2001 From: doyle Date: Tue, 26 Sep 2023 00:07:39 +1000 Subject: [PATCH] fp: Use meters for calculations --- feely_pona.cpp | 41 ++++++++++++++++++++--------------------- feely_pona.h | 11 +++++------ feely_pona_entity.cpp | 24 ++++++++++++------------ feely_pona_game.cpp | 36 +++++++++++++++++++++++++++++++++--- feely_pona_game.h | 5 ++++- feely_pona_unity.h | 2 +- 6 files changed, 75 insertions(+), 44 deletions(-) diff --git a/feely_pona.cpp b/feely_pona.cpp index a1b0b5d..fe095ae 100644 --- a/feely_pona.cpp +++ b/feely_pona.cpp @@ -131,6 +131,8 @@ void TELY_DLL_Init(void *user_data) TELY_Assets *assets = &platform->assets; FP_Game *game = Dqn_Arena_New(&platform->arena, FP_Game, Dqn_ZeroMem_Yes); game->chunk_pool = &platform->chunk_pool; + game->meters_to_pixels = 65.416f; + platform->user_data = game; { TELY_AssetSpriteSheet *sheet = &game->hero_sprite_sheet; @@ -235,13 +237,11 @@ void TELY_DLL_Init(void *user_data) // NOTE: Mob spawner =========================================================================== { - FP_GameEntityHandle mob_spawner = FP_Entity_CreateMobSpawner(game, - Dqn_V2_InitNx2(50.f, platform->core.window_size.y * .5f), - 16 /*spawn_cap*/, - "Mob spawner"); + Dqn_V2 mob_spawner_pos = FP_Game_MetersToPixelsNx2(game, 2.f, 5.f); + FP_GameEntityHandle mob_spawner = FP_Entity_CreateMobSpawner(game, mob_spawner_pos, 16 /*spawn_cap*/, "Mob spawner"); FP_Game_PushParentEntity(game, mob_spawner); - FP_Entity_CreateWaypointF(game, Dqn_V2_InitNx2(800.f, -200.f), "Waypoint"); - FP_Entity_CreateWaypointF(game, Dqn_V2_InitNx2(932.f, 200.f), "Waypoint"); + FP_Entity_CreateWaypointF(game, FP_Game_MetersToPixelsNx2(game, 2.f, 4.f), "Waypoint A"); + FP_Entity_CreateWaypointF(game, FP_Game_MetersToPixelsNx2(game, 14.f, 8.f), "Waypoint B"); FP_Game_PopParentEntity(game); } @@ -638,7 +638,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input entity->alive_time_s += PHYSICS_STEP; // NOTE: Move entity by keyboard and gamepad =============================================== - Dqn_V2 acceleration = {}; + Dqn_V2 acceleration_meters_per_s = {}; if (game->clicked_entity == entity->handle) { if (entity->flags & (FP_GameEntityFlag_MoveByKeyboard | FP_GameEntityFlag_MoveByGamepad)) { bool move_entity = false; @@ -658,7 +658,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input } if (move_entity) { - acceleration = dir_vector * 10000000.f; + acceleration_meters_per_s = dir_vector * 8; if (dir_vector.x) entity->direction = dir_vector.x > 0.f ? FP_GameDirection_Right : FP_GameDirection_Left; else if (dir_vector.y) @@ -668,7 +668,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input } // NOTE: Determine AI movement ============================================================= - if (acceleration.x == 0 && acceleration.y == 0) { + if (acceleration_meters_per_s.x == 0 && acceleration_meters_per_s.y == 0) { Dqn_V2 entity_pos = FP_Game_CalcEntityWorldPos(game, entity->handle); if (entity->flags & FP_GameEntityFlag_AggrosWhenNearTerry) { @@ -689,7 +689,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input } } - if (closest_terry_dist < DQN_SQUARED(200.f)) { + if (closest_terry_dist < DQN_SQUARED(FP_Game_MetersToPixelsNx1(game, 5.f))) { FP_SentinelListLink *first_waypoint = FP_SentinelList_Front(&entity->waypoints); if (first_waypoint->data != closest_terry->handle) { FP_SentinelListLink *link = FP_SentinelList_MakeBefore(&entity->waypoints, first_waypoint, game->chunk_pool); @@ -720,7 +720,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input // 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; + acceleration_meters_per_s = entity_to_waypoint_norm * 4.f; break; } } @@ -734,13 +734,10 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input Dqn_f32 t = DQN_CAST(Dqn_f32)DQN_SQUARED(PHYSICS_STEP); Dqn_f32 t_squared = DQN_SQUARED(t); - Dqn_f32 velocity_falloff_coefficient = 0.25f; - if (entity->handle == game->clicked_entity) { - if (dir_vector.x || dir_vector.y) - velocity_falloff_coefficient = 0.82f; - } - - entity->velocity = (acceleration * t) + entity->velocity * velocity_falloff_coefficient; + Dqn_f32 velocity_falloff_coefficient = 0.82f; + Dqn_f32 acceleration_feel_good_factor = 15'000.f; + Dqn_V2 acceleration = FP_Game_MetersToPixelsV2(game, acceleration_meters_per_s) * acceleration_feel_good_factor; + entity->velocity = (acceleration * t) + entity->velocity * velocity_falloff_coefficient; // NOTE: Zero out velocity with epsilon if (DQN_ABS(entity->velocity.x) < 5.f) @@ -748,8 +745,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input if (DQN_ABS(entity->velocity.y) < 5.f) entity->velocity.y = 0.f; - Dqn_V2 delta_pos = (acceleration * 0.5f * t_squared) + (entity->velocity * t); - + Dqn_V2 delta_pos = (acceleration * 0.5f * t_squared) + (entity->velocity * t); Dqn_Rect entity_world_hit_box = FP_Game_CalcEntityWorldHitBox(game, entity->handle); Dqn_V2 entity_pos = Dqn_Rect_Center(entity_world_hit_box); Dqn_V2 entity_new_pos = entity_pos + delta_pos; @@ -1006,8 +1002,11 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer) } break; } + Dqn_f32 sprite_in_meters = src_rect.size.y * FP_Game_PixelsToMeters(game); + Dqn_f32 size_scale = entity->sprite_height.meters / sprite_in_meters; + Dqn_Rect dest_rect = {}; - dest_rect.size = src_rect.size * entity->size_scale; + dest_rect.size = src_rect.size * size_scale; dest_rect.pos = world_pos - (dest_rect.size * .5f); if (sprite.flip & TELY_AssetFlip_X) diff --git a/feely_pona.h b/feely_pona.h index 0f96b21..6720e68 100644 --- a/feely_pona.h +++ b/feely_pona.h @@ -3,12 +3,6 @@ #include "feely_pona_unity.h" #endif -#define FP_SentinelDoublyLinkedList_Insert(list, item) \ - item->next = list; \ - item->prev = list->prev; \ - item->next->prev = item; \ - item->prev->next = item; - enum FP_ProfileZone { FP_ProfileZone_FPUpdate = TELY_ProfileZone_Count, @@ -22,3 +16,8 @@ enum FP_ProfileZone FP_ProfileZone_FPRender, }; +struct FP_Meters +{ + Dqn_f32 meters; +}; + diff --git a/feely_pona_entity.cpp b/feely_pona_entity.cpp index c41c649..1c764e9 100644 --- a/feely_pona_entity.cpp +++ b/feely_pona_entity.cpp @@ -43,10 +43,10 @@ static FP_GameEntityHandle FP_Entity_CreateSmoochie(FP_Game *game, Dqn_V2 pos, D FP_GameEntityHandle result = entity->handle; va_end(args); - entity->type = FP_EntityType_Smoochie; - entity->local_pos = pos; - entity->size_scale = Dqn_V2_InitNx1(.25f); - entity->local_hit_box_size = Dqn_V2_InitNx2(428, 471) * entity->size_scale; + entity->type = FP_EntityType_Smoochie; + entity->local_pos = pos; + entity->sprite_height.meters = 1.6f; + entity->local_hit_box_size = Dqn_V2_InitNx2(0.4f, 1.6f) * FP_Game_MetersToPixels(game); FP_Entity_AddDebugEditorFlags(game, entity->handle); entity->flags |= FP_GameEntityFlag_NonTraversable; return result; @@ -105,10 +105,10 @@ static FP_GameEntityHandle FP_Entity_CreateTerry(FP_Game *game, Dqn_V2 pos, DQN_ FP_GameEntityHandle result = entity->handle; va_end(args); - entity->type = FP_EntityType_Terry; - entity->local_pos = pos; - entity->size_scale = Dqn_V2_InitNx1(0.25f); - entity->local_hit_box_size = Dqn_V2_InitNx2(428, 471) * entity->size_scale; + entity->type = FP_EntityType_Terry; + entity->local_pos = pos; + entity->sprite_height.meters = 1.8f; + entity->local_hit_box_size = Dqn_V2_InitNx2(0.5f, entity->sprite_height.meters) * FP_Game_MetersToPixels(game); FP_Entity_AddDebugEditorFlags(game, result); entity->flags |= FP_GameEntityFlag_NonTraversable; return result; @@ -122,10 +122,10 @@ static FP_GameEntityHandle FP_Entity_CreateMerchant(FP_Game *game, Dqn_V2 pos, D FP_GameEntityHandle result = entity->handle; va_end(args); - entity->type = FP_EntityType_Merchant; - entity->local_pos = pos; - entity->local_hit_box_size = Dqn_V2_InitNx2(50, 50); - entity->size_scale = Dqn_V2_InitNx1(0.25f); + entity->type = FP_EntityType_Merchant; + entity->local_pos = pos; + entity->local_hit_box_size = Dqn_V2_InitNx2(50, 50); + entity->sprite_height.meters = 3.66f; FP_Entity_AddDebugEditorFlags(game, result); entity->flags |= FP_GameEntityFlag_NonTraversable; diff --git a/feely_pona_game.cpp b/feely_pona_game.cpp index 9f46c98..5cc85f6 100644 --- a/feely_pona_game.cpp +++ b/feely_pona_game.cpp @@ -3,6 +3,36 @@ #include "feely_pona_unity.h" #endif +static Dqn_f32 FP_Game_PixelsToMeters(FP_Game const *game) +{ + Dqn_f32 result = game ? (1.f / game->meters_to_pixels) : 10.f; + return result; +} + +static Dqn_f32 FP_Game_MetersToPixels(FP_Game const *game) +{ + Dqn_f32 result = game ? game->meters_to_pixels : 1 / 10.f; + return result; +} + +static Dqn_V2 FP_Game_MetersToPixelsV2(FP_Game const *game, Dqn_V2 pos) +{ + Dqn_V2 result = pos * FP_Game_MetersToPixels(game); + return result; +} + +static Dqn_f32 FP_Game_MetersToPixelsNx1(FP_Game const *game, Dqn_f32 val) +{ + Dqn_f32 result = val * FP_Game_MetersToPixels(game); + return result; +} + +static Dqn_V2 FP_Game_MetersToPixelsNx2(FP_Game const *game, Dqn_f32 x, Dqn_f32 y) +{ + Dqn_V2 result = Dqn_V2_InitNx2(x, y) * FP_Game_MetersToPixels(game); + return result; +} + static bool operator==(FP_GameEntityHandle const &lhs, FP_GameEntityHandle const &rhs) { bool result = lhs.id == rhs.id; @@ -203,9 +233,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->size_scale = Dqn_V2_InitNx1(1); - result->parent = FP_Game_ActiveParentEntityPointer(game); - result->name = TELY_ChunkPool_AllocFmtFV(game->chunk_pool, fmt, args); + result->sprite_height.meters = 1; + result->parent = FP_Game_ActiveParentEntityPointer(game); + result->name = TELY_ChunkPool_AllocFmtFV(game->chunk_pool, fmt, args); // NOTE: Attach entity as a child to the parent FP_GameEntity *parent = result->parent; diff --git a/feely_pona_game.h b/feely_pona_game.h index 25f17ba..e5a9852 100644 --- a/feely_pona_game.h +++ b/feely_pona_game.h @@ -97,7 +97,9 @@ struct FP_GameEntity Dqn_String8 name; FP_GameEntityHandle handle; - Dqn_V2 size_scale; + // The target size to render the sprite in meters. The width of the sprite + // is scaled uniformly with respect to the height. + FP_Meters sprite_height; FP_GameEntityAction action; Dqn_V2 velocity; @@ -175,6 +177,7 @@ struct FP_Game FP_GameCamera camera; TELY_RFui rfui; + Dqn_f32 meters_to_pixels; uint64_t clock_ms; }; diff --git a/feely_pona_unity.h b/feely_pona_unity.h index d747d96..8114bbe 100644 --- a/feely_pona_unity.h +++ b/feely_pona_unity.h @@ -61,10 +61,10 @@ DQN_MSVC_WARNING_DISABLE(4505) // warning C4505: unreferenced function with inte #include "External/tely/tely_rfui.cpp" // NOTE: feely_pona ================================================================================ +#include "feely_pona.h" #include "feely_pona_stdlib.h" #include "feely_pona_entity.h" #include "feely_pona_game.h" -#include "feely_pona.h" #include "feely_pona_game.cpp" #include "feely_pona_entity.cpp"