From aa72cfe4a40dcd4de2b3910bcbe9a37ec93e0494 Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Fri, 18 Jul 2025 13:09:53 -0400 Subject: [PATCH] Now have a working compass based directional player sprite in the map, but using the compass isn't going to work long term. Need to move that into the raycaster.cpp and get real degrees for facing direction. --- assets/enemies.json | 2 +- assets/map_tiles.json | 2 +- assets/map_tiles.png | Bin 9176 -> 9148 bytes assets/tiles.json | 12 +---- gui/map_view.cpp | 6 ++- gui/map_view.hpp | 1 + systems.cpp | 99 ++++++++++++++++++++++++------------------ systems.hpp | 4 +- tests/map.cpp | 5 ++- 9 files changed, 70 insertions(+), 61 deletions(-) diff --git a/assets/enemies.json b/assets/enemies.json index 18d3a36..cfb673f 100644 --- a/assets/enemies.json +++ b/assets/enemies.json @@ -2,7 +2,7 @@ "PLAYER_TILE": { "placement": "fixed", "components": [ - {"_type": "Tile", "display": 41981, + {"_type": "Tile", "display": 10733, "foreground": "enemies/fg:player", "background": "color:transparent" }, diff --git a/assets/map_tiles.json b/assets/map_tiles.json index 3523cd8..7a8adb0 100644 --- a/assets/map_tiles.json +++ b/assets/map_tiles.json @@ -109,7 +109,7 @@ }, { "centered": true, - "display": 41981, + "display": 10733, "x": 512, "y": 64 }, diff --git a/assets/map_tiles.png b/assets/map_tiles.png index 5cb4c96f6675270338311e915eba174ef6da2722..6da17711234bb8e782522ac581415fef29084db8 100644 GIT binary patch delta 3986 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, $map_tiles(matrix::make(map_width, map_height)) { + auto player = $level.world->get_the(); + $player_display = $level.world->get(player.entity).display; } void MapViewUI::update_level(GameLevel &level) { @@ -60,8 +62,8 @@ namespace gui { void MapViewUI::render(sf::RenderWindow &window, int compass_dir) { $gui.render(window); - System::draw_map($level, $map_tiles, $entity_map, compass_dir); - System::render_map($map_tiles, $entity_map, *$map_render); + System::draw_map($level, $map_tiles, $entity_map); + System::render_map($map_tiles, $entity_map, *$map_render, compass_dir, $player_display); $map_sprite.setTexture($map_render->getTexture(), true); window.draw($map_sprite); // $gui.debug_layout(window); diff --git a/gui/map_view.hpp b/gui/map_view.hpp index 5262c43..b5d9836 100644 --- a/gui/map_view.hpp +++ b/gui/map_view.hpp @@ -9,6 +9,7 @@ namespace gui { class MapViewUI { public: guecs::UI $gui; + wchar_t $player_display = L'@'; DinkyECS::Entity $log_to; EntityGrid $entity_map; std::deque $messages; diff --git a/systems.cpp b/systems.cpp index db9c301..5169a3e 100644 --- a/systems.cpp +++ b/systems.cpp @@ -407,47 +407,6 @@ void System::plan_motion(World& world, Position move_to) { motion.dy = move_to.location.y - player_position.location.y; } -void System::draw_map(GameLevel& level, Matrix& grid, EntityGrid& entity_map, int compass_dir) { - (void)compass_dir; - World &world = *level.world; - Map &map = *level.map; - size_t view_x = matrix::width(grid) - 1; - size_t view_y = matrix::height(grid) - 1; - - entity_map.clear(); - - auto player_pos = world.get(level.player).location; - Point cam_orig = map.center_camera(player_pos, view_x, view_y); - auto &tiles = map.tiles(); - auto &tile_set = textures::get_map_tile_set(); - - /* I'm doing double tid->wchar_t conversion here, maybe just - * render the tids into the grid then let someone else do this. */ - - // first fill it with the map cells - for(shiterator::each_cell_t it{grid}; it.next();) { - size_t tile_y = size_t(it.y) + cam_orig.y; - size_t tile_x = size_t(it.x) + cam_orig.x; - - if(matrix::inbounds(tiles, tile_x, tile_y)) { - size_t tid = tiles[tile_y][tile_x]; - grid[it.y][it.x] = tile_set[tid]; - } else { - grid[it.y][it.x] = L' '; - } - } - - // then get the enemy/item/device tiles and fill those in - world.query([&](auto, auto &pos, auto &entity_glyph) { - // BUG: don't I have a within bounds macro somewhere? - if(pos.location.x >= cam_orig.x && pos.location.x <= cam_orig.x + view_x - && pos.location.y >= cam_orig.y && pos.location.y <= cam_orig.y + view_y) - { - Point view_pos = map.map_to_camera(pos.location, cam_orig); - entity_map.insert_or_assign(view_pos, entity_glyph.display); - } - }); -} void System::player_status(GameLevel &level) { auto& combat = level.world->get(level.player); @@ -567,7 +526,49 @@ bool System::inventory_occupied(GameLevel& level, Entity container_id, const std } -void System::render_map(Matrix& tiles, EntityGrid& entity_map, sf::RenderTexture& render) { +void System::draw_map(GameLevel& level, Matrix& grid, EntityGrid& entity_map) { + World &world = *level.world; + Map &map = *level.map; + size_t view_x = matrix::width(grid) - 1; + size_t view_y = matrix::height(grid) - 1; + + entity_map.clear(); + + auto player_pos = world.get(level.player).location; + Point cam_orig = map.center_camera(player_pos, view_x, view_y); + auto &tiles = map.tiles(); + auto &tile_set = textures::get_map_tile_set(); + + /* I'm doing double tid->wchar_t conversion here, maybe just + * render the tids into the grid then let someone else do this. */ + + // first fill it with the map cells + for(shiterator::each_cell_t it{grid}; it.next();) { + size_t tile_y = size_t(it.y) + cam_orig.y; + size_t tile_x = size_t(it.x) + cam_orig.x; + + if(matrix::inbounds(tiles, tile_x, tile_y)) { + size_t tid = tiles[tile_y][tile_x]; + grid[it.y][it.x] = tile_set[tid]; + } else { + grid[it.y][it.x] = L' '; + } + } + + // then get the enemy/item/device tiles and fill those in + world.query([&](auto, auto &pos, auto &entity_glyph) { + // BUG: don't I have a within bounds macro somewhere? + if(pos.location.x >= cam_orig.x && pos.location.x <= cam_orig.x + view_x + && pos.location.y >= cam_orig.y && pos.location.y <= cam_orig.y + view_y) + { + Point view_pos = map.map_to_camera(pos.location, cam_orig); + entity_map.insert_or_assign(view_pos, entity_glyph.display); + } + }); +} + + +void System::render_map(Matrix& tiles, EntityGrid& entity_map, sf::RenderTexture& render, int compass_dir, wchar_t player_display) { sf::Vector2i size{MAP_TILE_DIM,MAP_TILE_DIM}; unsigned int width = matrix::width(tiles); unsigned int height = matrix::height(tiles); @@ -591,7 +592,19 @@ void System::render_map(Matrix& tiles, EntityGrid& entity_map, sf::RenderTexture for(auto [point, display] : entity_map) { auto& sprite = textures::get_map_sprite(display); - sprite.setPosition({float(point.x * size.x), float(point.y * size.y)}); + + if(display == player_display) { + sf::Vector2f size = sprite.getLocalBounds().size; + sf::Vector2f center{size.x / 2, size.y / 2}; + float degrees = (((compass_dir * 45) + 270) % 360); + + sprite.setOrigin(center); + sprite.setRotation(sf::degrees(degrees)); + sprite.setPosition({float(point.x * size.x) + center.x, float(point.y * size.y) + center.y}); + } else { + sprite.setPosition({float(point.x * size.x), float(point.y * size.y)}); + } + render.draw(sprite); } diff --git a/systems.hpp b/systems.hpp index 943aea9..727d848 100644 --- a/systems.hpp +++ b/systems.hpp @@ -19,7 +19,6 @@ namespace System { void init_positions(World &world, SpatialMap &collider); void device(World &world, Entity actor, Entity item); void plan_motion(World& world, Position move_to); - void draw_map(GameLevel& level, Matrix& grid, EntityGrid& entity_map, int compass_dir); Entity spawn_item(World& world, const string& name); bool drop_item(GameLevel& level, Entity item); @@ -40,5 +39,6 @@ namespace System { void inventory_swap(GameLevel &level, Entity container_id, const std::string& a_name, const std::string &b_name); bool inventory_occupied(GameLevel& level, Entity container_id, const std::string& name); - void render_map(Matrix& tiles, EntityGrid& entity_map, sf::RenderTexture& render); + void draw_map(GameLevel& level, Matrix& grid, EntityGrid& entity_map); + void render_map(Matrix& tiles, EntityGrid& entity_map, sf::RenderTexture& render, int compass_dir, wchar_t player_display); } diff --git a/tests/map.cpp b/tests/map.cpp index 7eadb91..9a1a463 100644 --- a/tests/map.cpp +++ b/tests/map.cpp @@ -95,13 +95,14 @@ TEST_CASE("map image test", "[map-sprite]") { sf::Sprite sprite{render->getTexture()}; auto player = level.world->get_the(); auto& player_pos = level.world->get(player.entity); + auto player_display = level.world->get(player.entity).display; for(matrix::each_row it{level.map->walls()}; it.next();) { player_pos.location.x = it.x; player_pos.location.y = it.y; - System::draw_map(level, map_tiles, entity_map, 2); - System::render_map(map_tiles, entity_map, *render); + System::draw_map(level, map_tiles, entity_map); + System::render_map(map_tiles, entity_map, *render, 2, player_display); #ifdef TEST_RENDER // confirm we get two different maps