From d1016f68a01d48b151e394675ae1f0fddef07da7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Madar=C3=A1sz?= Date: Mon, 9 Aug 2021 19:30:39 +0200 Subject: [PATCH] code: add basic vehicle logic --- code/game/src/debug_ui_actions.c | 13 ++- code/game/src/entity_view.c | 1 + code/game/src/platform_raylib.c | 7 ++ code/game/src/vehicle.c | 2 +- code/game/src/world/world.c | 21 +++++ code/game/src/world/world.h | 5 + code/modules/modules/components.c | 3 + code/modules/modules/components.h | 5 + code/modules/modules/systems.c | 149 ++++++++++++++++++------------ 9 files changed, 143 insertions(+), 63 deletions(-) diff --git a/code/game/src/debug_ui_actions.c b/code/game/src/debug_ui_actions.c index 89ae57d..f6cf75d 100644 --- a/code/game/src/debug_ui_actions.c +++ b/code/game/src/debug_ui_actions.c @@ -1,8 +1,12 @@ #include "debug_ui.h" #include "raylib.h" #include "vehicle.h" +#include "camera.h" +#include "world/world.h" #include "game.h" +#include "modules/components.h" + static inline void ActExitGame(void) { game_request_close(); @@ -10,5 +14,10 @@ ActExitGame(void) { static inline void ActSpawnCar(void) { - vehicle_spawn(); -} \ No newline at end of file + ecs_entity_t e = vehicle_spawn(); + ecs_entity_t plr = camera_get().ent_id; + + Position const* origin = ecs_get(world_ecs(), plr, Position); + Position * dest = ecs_get_mut(world_ecs(), e, Position, NULL); + *dest = *origin; +} diff --git a/code/game/src/entity_view.c b/code/game/src/entity_view.c index 96e00c5..eb9cc8f 100644 --- a/code/game/src/entity_view.c +++ b/code/game/src/entity_view.c @@ -5,6 +5,7 @@ ZPL_TABLE_DEFINE(entity_view_tbl, entity_view_tbl_, entity_view); pkt_desc pkt_entity_view_desc[] = { + { PKT_UINT(entity_view, kind) }, { PKT_UINT(entity_view, flag) }, { PKT_HALF(entity_view, x) }, diff --git a/code/game/src/platform_raylib.c b/code/game/src/platform_raylib.c index 251ce0b..8a13537 100644 --- a/code/game/src/platform_raylib.c +++ b/code/game/src/platform_raylib.c @@ -217,6 +217,13 @@ void DEBUG_draw_entities(uint64_t key, entity_view * data) { #endif DrawCircleEco(x, y, size, ColorAlpha(YELLOW, data->tran_time)); }break; + case EKIND_VEHICLE: { + float x = data->x; + float y = data->y; + float const w = 50; + float const h = 80; + DrawRectanglePro((Rectangle){x,y,w,h}, (Vector2){w/2.0f,h/2.0f}, 0.0f, ColorAlpha(RED, data->tran_time)); + }break; default:break; } } diff --git a/code/game/src/vehicle.c b/code/game/src/vehicle.c index 6a0331c..7a39054 100644 --- a/code/game/src/vehicle.c +++ b/code/game/src/vehicle.c @@ -8,7 +8,7 @@ uint64_t vehicle_spawn(void) { ecs_entity_t e = entity_spawn(EKIND_VEHICLE); - ecs_add(world_ecs(), e, Vehicle); + ecs_set(world_ecs(), e, Vehicle, {0}); return (uint64_t)e; } diff --git a/code/game/src/world/world.c b/code/game/src/world/world.c index 2c527a8..b42f84f 100644 --- a/code/game/src/world/world.c +++ b/code/game/src/world/world.c @@ -382,3 +382,24 @@ uint8_t world_chunk_is_dirty(ecs_entity_t e) { if (chunk) return chunk->is_dirty; return false; } + +int64_t *world_chunk_fetch_entities(librg_chunk chunk_id, size_t *ents_len) { + ZPL_ASSERT_NOT_NULL(ents_len); + static int64_t ents[UINT16_MAX]; + *ents_len = UINT16_MAX; + librg_world_fetch_chunk(world.tracker, chunk_id, ents, ents_len); + return ents; +} + +int64_t *world_chunk_fetch_entities_realpos(float x, float y, size_t *ents_len) { + return world_chunk_fetch_entities(librg_chunk_from_realpos(world.tracker, x, y, 0), ents_len); +} + +int64_t *world_chunk_query_entities(int64_t e, size_t *ents_len, int8_t radius) { + ZPL_ASSERT_NOT_NULL(ents_len); + static int64_t ents[UINT16_MAX]; + *ents_len = UINT16_MAX; + librg_entity_radius_set(world.tracker, e, radius); + librg_world_query(world.tracker, e, ents, ents_len); + return ents; +} \ No newline at end of file diff --git a/code/game/src/world/world.h b/code/game/src/world/world.h index b9167fa..0ed9cdf 100644 --- a/code/game/src/world/world.h +++ b/code/game/src/world/world.h @@ -77,3 +77,8 @@ void world_chunk_replace_block(int64_t id, uint16_t block_idx, uint8_t block_id) uint8_t *world_chunk_get_blocks(int64_t id); void world_chunk_mark_dirty(ecs_entity_t e); uint8_t world_chunk_is_dirty(ecs_entity_t e); + +// NOTE(zaklaus): Uses locally persistent buffer !! +int64_t *world_chunk_fetch_entities(librg_chunk chunk_id, size_t *ents_len); +int64_t *world_chunk_fetch_entities_realpos(float x, float y, size_t *ents_len); +int64_t *world_chunk_query_entities(int64_t e, size_t *ents_len, int8_t radius); \ No newline at end of file diff --git a/code/modules/modules/components.c b/code/modules/modules/components.c index 58fc41b..fec291b 100644 --- a/code/modules/modules/components.c +++ b/code/modules/modules/components.c @@ -12,6 +12,7 @@ ECS_COMPONENT_DECLARE(Classify); ECS_COMPONENT_DECLARE(Vehicle); ECS_TAG_DECLARE(EcsActor); ECS_TAG_DECLARE(EcsDemoNPC); +ECS_TAG_DECLARE(EcsInVehicle); ECS_TYPE_DECLARE(Player); ECS_TYPE_DECLARE(Movement); ECS_TYPE_DECLARE(Walking); @@ -47,6 +48,7 @@ void ComponentsImport(ecs_world_t *ecs) { ECS_TAG_DEFINE(ecs, EcsActor); ECS_TAG_DEFINE(ecs, EcsDemoNPC); + ECS_TAG_DEFINE(ecs, EcsInVehicle); ECS_PREFAB(ecs, Base, Position, Velocity, Input, EcsActor); ECS_TYPE_DEFINE(ecs, Movement, Walking, Flying); @@ -66,5 +68,6 @@ void ComponentsImport(ecs_world_t *ecs) { ECS_SET_ENTITY(Flying); ECS_SET_ENTITY(EcsActor); ECS_SET_ENTITY(EcsDemoNPC); + ECS_SET_ENTITY(EcsInVehicle); ECS_SET_TYPE(Movement); } diff --git a/code/modules/modules/components.h b/code/modules/modules/components.h index 9aaff09..3b15dc8 100644 --- a/code/modules/modules/components.h +++ b/code/modules/modules/components.h @@ -27,6 +27,8 @@ ECS_STRUCT(Input, { uint8_t use; uint8_t sprint; uint8_t is_blocked; + + ecs_entity_t parent; }); ECS_STRUCT(ClientInfo, { @@ -63,6 +65,7 @@ ECS_COMPONENT_EXTERN(Classify); ECS_COMPONENT_EXTERN(Vehicle); ECS_TAG_EXTERN(EcsActor); ECS_TAG_EXTERN(EcsDemoNPC); +ECS_TAG_EXTERN(EcsInVehicle); ECS_TYPE_EXTERN(Player); ECS_TYPE_EXTERN(Movement); ECS_TYPE_EXTERN(Walking); @@ -82,6 +85,7 @@ typedef struct { ECS_DECLARE_COMPONENT(Vehicle); ECS_DECLARE_ENTITY(EcsActor); ECS_DECLARE_ENTITY(EcsDemoNPC); + ECS_DECLARE_ENTITY(EcsInVehicle); ECS_DECLARE_TYPE(Player); ECS_DECLARE_TYPE(Builder); ECS_DECLARE_TYPE(Movement); @@ -109,5 +113,6 @@ ECS_IMPORT_ENTITY(handles, EcsDemoNPC);\ ECS_IMPORT_ENTITY(handles, Walking);\ ECS_IMPORT_ENTITY(handles, Flying);\ ECS_IMPORT_ENTITY(handles, EcsClient);\ +ECS_IMPORT_ENTITY(handles, EcsInVehicle);\ void ComponentsImport(ecs_world_t *ecs); diff --git a/code/modules/modules/systems.c b/code/modules/modules/systems.c index 0e27cf7..96077be 100644 --- a/code/modules/modules/systems.c +++ b/code/modules/modules/systems.c @@ -62,64 +62,6 @@ void IntegratePositions(ecs_iter_t *it) { } } -#define PHY_PUSHOUT_DIST ((64.0f*WORLD_BLOCK_SIZE)) - -void PushOutOverlappingEntities(ecs_iter_t *it) { - Position *p = ecs_column(it, Position, 1); - - for (int i = 0; i <= it->count; i++) { -#if 1 - // NOTE(zaklaus): slow path. iterate over all the entities in the table. - for (int k = 0; k <= it->count; k++) { - if (i == k) continue; -#else - // TODO(zaklaus): use a shared internal buffer instead !!! - static int64_t ents[UINT32_MAX]; - size_t ents_count = UINT32_MAX; - librg_world_fetch_chunk(world_tracker(), librg_chunk_from_realpos(world_tracker(), p[i].x, p[i].y, 0), ents, &ents_count); - - // NOTE(zaklaus): iterate over all entities inside this chunk - for (size_t j = 0; j < ents_count; j++) { - ecs_entity_t e = ents[j]; - - if (e == it->entities[i]) - continue; - - // NOTE(zaklaus): reverse lookup - int k = 0; - for (; k <= it->count; k++) { - if (k == it->count) { - k = -1; - break; - } - if (it->entities[k] == e) { - break; - } - } - - if (k == -1) - continue; -#endif - - float dx = p[i].x - p[k].x; - float dy = p[i].y - p[k].y; - float dist = zpl_sqrt(dx*dx + dy*dy); - if (dist < PHY_PUSHOUT_DIST) { - p[i].x = zpl_sign(dx); - p[i].y = zpl_sign(dy); -#if 0 - p[k].x += zpl_sign(dx); - p[k].y += zpl_sign(dy); -#endif - } - } - } - } - -#if 0 -} -#endif - void UpdateTrackerPos(ecs_iter_t *it) { Position *p = ecs_column(it, Position, 1); @@ -136,6 +78,7 @@ void MovementImpulse(ecs_iter_t *it) { Velocity *v = ecs_column(it, Velocity, 2); for (int i = 0; i < it->count; i++) { + if (ecs_is_alive(world_ecs(), in[i].parent)) continue; double speed = PLR_MOVE_SPEED * (in[i].sprint ? PLR_MOVE_SPEED_MULT : 1.0); if (zpl_abs(v[i].x) < speed && in[i].x) v[i].x = in[i].x*speed; @@ -205,20 +148,106 @@ void RegenerateHP(ecs_iter_t *it) { } } +#define VEH_ENTER_RADIUS 45.0f + +void EnterOrLeaveVehicle(ecs_iter_t *it) { + Input *in = ecs_column(it, Input, 1); + Position *p = ecs_column(it, Position, 2); + + for (int i = 0; i < it->count; i++) { + if (!in[i].use) continue; + + if (!ecs_is_alive(world_ecs(), in[i].parent)) { + size_t ents_count; + int64_t *ents = world_chunk_query_entities(it->entities[i], &ents_count, 2); + + for (size_t j = 0; j < ents_count; j++) { + if (ecs_get(world_ecs(), ents[j], Vehicle)) { + Vehicle *veh = ecs_get_mut(world_ecs(), ents[j], Vehicle, NULL); + Position const* p2 = ecs_get(world_ecs(), ents[j], Position); + + float dx = p2->x - p[i].x; + float dy = p2->y - p[i].y; + float range = zpl_sqrt(dx*dx + dy*dy); + if (range <= VEH_ENTER_RADIUS) { + for (int k = 0; k < 4; k++) { + if (veh->seats[k] != 0) continue; + + // NOTE(zaklaus): We can enter the vehicle, yay! + veh->seats[k] = it->entities[i]; + in[i].parent = ents[j]; + p[i] = *p2; + break; + } + } + } + } + } else { + if (ecs_get(world_ecs(), in[i].parent, Vehicle)) { + Vehicle *veh = ecs_get_mut(world_ecs(), in[i].parent, Vehicle, NULL); + + for (int k = 0; k < 4; k++) { + if (veh->seats[k] == it->entities[i]) { + veh->seats[k] = 0; + break; + } + } + + in[i].parent = 0; + } else { + ZPL_PANIC("unreachable code"); + } + } + } +} + +void VehicleHandling(ecs_iter_t *it) { + Vehicle *veh = ecs_column(it, Vehicle, 1); + Position *p = ecs_column(it, Position, 2); + Velocity *v = ecs_column(it, Velocity, 3); + + for (int i = 0; i < it->count; i++) { + for (int j = 0; j < 4; j++) { + // NOTE(zaklaus): Perform seat cleanup + if (!ecs_is_alive(world_ecs(), veh[i].seats[j])) { + veh[i].seats[j] = 0; + continue; + } + + ecs_entity_t pe = veh[i].seats[j]; + + // NOTE(zaklaus): Update passenger position + { + Position *p2 = ecs_get_mut(world_ecs(), pe, Position, NULL); + *p2 = p[i]; + } + + // NOTE(zaklaus): Handle driver input + if (j == 0) { + // TODO(zaklaus): Be lazy about it for now, implement wheels later + Input const* in = ecs_get(world_ecs(), pe, Input); + v[i].x += in->x; + v[i].y += in->y; + } + } + } +} + void SystemsImport(ecs_world_t *ecs) { ECS_MODULE(ecs, Systems); ECS_IMPORT(ecs, Components); ECS_SYSTEM(ecs, MovementImpulse, EcsOnLoad, components.Input, components.Velocity); - ECS_SYSTEM(ecs, DemoPlaceIceBlock, EcsOnLoad, components.Input, components.Position); + //ECS_SYSTEM(ecs, DemoPlaceIceBlock, EcsOnLoad, components.Input, components.Position); ECS_SYSTEM(ecs, DemoNPCMoveAround, EcsOnLoad, components.Velocity, components.EcsDemoNPC); + ECS_SYSTEM(ecs, EnterOrLeaveVehicle, EcsOnLoad, components.Input, components.Position); ECS_SYSTEM(ecs, MoveWalk, EcsOnUpdate, components.Position, components.Velocity); ECS_SYSTEM(ecs, HurtOnHazardBlock, EcsOnUpdate, components.Position, components.Health); ECS_SYSTEM(ecs, RegenerateHP, EcsOnUpdate, components.Health); + ECS_SYSTEM(ecs, VehicleHandling, EcsOnUpdate, components.Vehicle, components.Position, components.Velocity); ECS_SYSTEM(ecs, IntegratePositions, EcsOnValidate, components.Position, components.Velocity); - //ECS_SYSTEM(ecs, PushOutOverlappingEntities, EcsOnValidate, components.Position, Velocity); ECS_SYSTEM(ecs, UpdateTrackerPos, EcsPostUpdate, components.Position); }