phantasia

Phantasia - 2D SDL3 RPG prototype.
git clone git://git.beep.wimdupont.com/phantasia.git
Log | Files | Refs | README | LICENSE

commit e66c15d34176c7ef99ff1114cf3cfe7fff38eab6
parent 0b33409cb0defb788ceb0a21f5ba77457ce0c01b
Author: beep <beep@wimdupont.com>
Date:   Sat,  4 Apr 2026 17:34:28 +0000

Block movement through entities

Diffstat:
Msrc/engine/world.c | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/engine/world.h | 4++++
Msrc/game/main.c | 15+++++++++++++++
3 files changed, 91 insertions(+), 2 deletions(-)

diff --git a/src/engine/world.c b/src/engine/world.c @@ -10,6 +10,7 @@ enum { PH_MAP_MAGIC = 0x50484d50, PH_MAP_VERSION = 1, PH_AREA_NAME_MAX = 64, + PH_ENTITY_BLOCK_RADIUS = 10, }; typedef struct { @@ -108,6 +109,65 @@ ph_position_blocked(const PhWorld *world, PhVec2 pos) } static void +ph_world_set_notice(PhWorld *world, const char *text) +{ + snprintf(world->notice, sizeof(world->notice), "%s", text); + world->notice_seconds = 1.25f; +} + +static const PhEntity * +ph_world_blocking_entity(const PhWorld *world, int self_index, PhVec2 pos) +{ + int i; + + for (i = 0; i < world->entity_count; ++i) { + const PhEntity *entity = &world->entities[i]; + const PhEntityDef *def; + + if (i == self_index || !entity->active) { + continue; + } + + def = ph_world_entity_def(world, entity->type_id); + if (!def || !def->blocks_movement) { + continue; + } + + if (ph_dist2(entity->pos, pos) < + (float)(PH_ENTITY_BLOCK_RADIUS * PH_ENTITY_BLOCK_RADIUS)) { + return entity; + } + } + + return NULL; +} + +static int +ph_player_step_blocked(PhWorld *world, int player_index, PhVec2 pos) +{ + const PhEntity *blocker; + const PhEntityDef *def; + + if (ph_position_blocked(world, pos)) { + return 1; + } + + blocker = ph_world_blocking_entity(world, player_index, pos); + if (!blocker) { + return 0; + } + + def = ph_world_entity_def(world, blocker->type_id); + if (def && def->name) { + char text[PH_NOTICE_SIZE]; + + snprintf(text, sizeof(text), "%s blocks your path.", def->name); + ph_world_set_notice(world, text); + } + return 1; +} + +static void ph_try_pickup(PhWorld *world, PhEntity *entity) { int i; @@ -320,6 +380,14 @@ ph_world_tick(PhWorld *world, PhInput input, float dt) return; } + if (world->notice_seconds > 0.0f) { + world->notice_seconds -= dt; + if (world->notice_seconds <= 0.0f) { + world->notice_seconds = 0.0f; + world->notice[0] = '\0'; + } + } + input = ph_orthogonal_input(input, player); next = player->pos; if (input.move_x != 0 || input.move_y != 0) { @@ -330,10 +398,12 @@ ph_world_tick(PhWorld *world, PhInput input, float dt) next.x += (float)input.move_x * speed * dt; next.y += (float)input.move_y * speed * dt; - if (!ph_position_blocked(world, ph_vec2(next.x, player->pos.y))) { + if (!ph_player_step_blocked(world, world->player_index, + ph_vec2(next.x, player->pos.y))) { player->pos.x = next.x; } - if (!ph_position_blocked(world, ph_vec2(player->pos.x, next.y))) { + if (!ph_player_step_blocked(world, world->player_index, + ph_vec2(player->pos.x, next.y))) { player->pos.y = next.y; } } diff --git a/src/engine/world.h b/src/engine/world.h @@ -9,6 +9,7 @@ enum { PH_MAX_ITEM_TYPES = 64, PH_MAX_ENTITIES = 128, PH_MAX_GROUND_ITEMS = 128, + PH_NOTICE_SIZE = 96, }; typedef enum { @@ -29,6 +30,7 @@ typedef struct { int move_speed; int sprite_tile_x; int sprite_tile_y; + int blocks_movement; PhEntityKind kind; } PhEntityDef; @@ -85,6 +87,8 @@ typedef struct { int entity_count; int ground_item_count; int player_talent_points; + char notice[PH_NOTICE_SIZE]; + float notice_seconds; } PhWorld; typedef struct { diff --git a/src/game/main.c b/src/game/main.c @@ -65,6 +65,7 @@ ph_make_world(PhWorld *world) .move_speed = 90, .sprite_tile_x = 0, .sprite_tile_y = 2, + .blocks_movement = 0, .kind = PH_ENTITY_PLAYER, }); ph_world_add_entity_def(world, (PhEntityDef){ @@ -74,6 +75,7 @@ ph_make_world(PhWorld *world) .move_speed = 45, .sprite_tile_x = 12, .sprite_tile_y = 0, + .blocks_movement = 1, .kind = PH_ENTITY_MONSTER, }); ph_world_add_item_def(world, (PhItemDef){ @@ -334,6 +336,19 @@ ph_render_frame(SDL_Renderer *renderer, const PhAssets *assets, PhWorld *world, ph_draw_area(renderer, assets, world); ph_draw_items(renderer, assets, world); ph_draw_entities(renderer, assets, world); + if (world->notice_seconds > 0.0f && world->notice[0] != '\0') { + SDL_FRect notice_bg = { + .x = 8.0f, + .y = (float)(PH_VIEW_H - 28), + .w = (float)(PH_VIEW_W - 16), + .h = 20.0f, + }; + + SDL_SetRenderDrawColor(renderer, 20, 24, 34, 255); + SDL_RenderFillRect(renderer, &notice_bg); + SDL_SetRenderDrawColor(renderer, 232, 236, 244, 255); + SDL_RenderDebugText(renderer, 14.0f, (float)(PH_VIEW_H - 22), world->notice); + } SDL_RenderPresent(renderer); }