summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2023-09-25 06:11:52 +0200
committerStanislaw Halik <sthalik@misaki.pl>2023-09-25 06:11:52 +0200
commit18d1db7d8be97fd9aea67c352e78b376d7145f4b (patch)
treeb28d9b272bf1a0e5bf971c4e162e8ef2bf44b037
parent627dc90720e083b2e458ab7efb4dcca739b7a19a (diff)
a
-rw-r--r--src/path-search.cpp50
-rw-r--r--src/path-search.hpp9
-rw-r--r--src/world.hpp2
-rw-r--r--test/path-search.cpp15
4 files changed, 67 insertions, 9 deletions
diff --git a/src/path-search.cpp b/src/path-search.cpp
index cf7d41d5..47ce6f61 100644
--- a/src/path-search.cpp
+++ b/src/path-search.cpp
@@ -176,10 +176,52 @@ auto path_search::make_neighbor_tile_bbox(Vector2i coord, Vector2ub own_size, ro
return { Vector2(min + shift), Vector2(max + shift) };
}
-Optional<path_search_result>
-path_search::operator()(world& w, object_id own_id,
- global_coords from, Vector2b from_offset, Vector2ub size,
- global_coords to, Vector2b to_offset)
+auto path_search::get_walkable_neighbor_tiles(world& w, global_coords coord, Vector2ub size, object_id own_id) -> neighbors
+{
+ auto ch = chunk_coords_{ coord.chunk(), coord.z() };
+ auto pos = Vector2i(coord.local());
+
+ if (auto [min, max] = make_neighbor_tile_bbox(pos, size, rotation_COUNT);
+ !is_passable(w, ch, min, max, own_id))
+ return {};
+
+ neighbors ns;
+
+ using enum rotation;
+ constexpr struct {
+ Vector2i off;
+ rotation r = {};
+ } nbs[] = {
+ { { 0, -1 }, N },
+ { { 1, 0 }, E },
+ { { 0, 1 }, S },
+ { { -1, 0 }, W },
+ };
+
+ for (auto [off, dir] : nbs)
+ {
+ auto [min, max] = make_neighbor_tile_bbox(pos, size, dir);
+ if (is_passable(w, ch, min, max, own_id))
+ ns.neighbors[ns.size++] = coord + off;
+ }
+
+ return ns;
+}
+
+auto path_search::bbox_union(bbox bb, Vector2i coord, Vector2b offset, Vector2ub size) -> bbox
+{
+ auto center = coord * iTILE_SIZE2 + Vector2i(offset);
+ auto min = center - Vector2i(size / 2u);
+ auto max = center + Vector2i(size);
+ return {
+ .min = Math::min(bb.min, Vector2(min)),
+ .max = Math::max(bb.max, Vector2(max)),
+ };
+}
+
+Optional<path_search_result> path_search::operator()(world& w, object_id own_id,
+ global_coords from, Vector2b from_offset, Vector2ub size,
+ global_coords to, Vector2b to_offset)
{
if (from.z() != to.z()) [[unlikely]]
return {};
diff --git a/src/path-search.hpp b/src/path-search.hpp
index 68cf41a4..4d3c7d23 100644
--- a/src/path-search.hpp
+++ b/src/path-search.hpp
@@ -41,9 +41,9 @@ struct path_search_result final
const global_coords* data() const;
private:
- mutable path_search_result* _next;
+ mutable path_search_result* _next = nullptr;
std::unique_ptr<global_coords[]> _path;
- size_t _size;
+ size_t _size = 0;
};
class path_search final
@@ -54,7 +54,7 @@ class path_search final
auto end() const { return neighbors.data() + size; }
std::array<global_coords, 4> neighbors;
- uint8_t size;
+ uint8_t size = 0;
};
struct chunk_tiles_cache
@@ -91,7 +91,8 @@ public:
static bool is_passable(world& w, global_coords coord, Vector2b offset, Vector2ub size, object_id own_id);
static bbox make_neighbor_tile_bbox(Vector2i coord, Vector2ub own_size, rotation r);
- static neighbors get_walkable_neighbor_tiles(world& w, global_coords pos, Vector2 size, object_id own_id);
+ static bbox bbox_union(bbox bb, Vector2i coord, Vector2b offset, Vector2ub size);
+ static neighbors get_walkable_neighbor_tiles(world& w, global_coords coord, Vector2ub size, object_id own_id);
};
} // namespace floormat
diff --git a/src/world.hpp b/src/world.hpp
index bda8d3a4..9b776c5e 100644
--- a/src/world.hpp
+++ b/src/world.hpp
@@ -98,7 +98,7 @@ public:
[[nodiscard]] object_id make_id() { return ++_object_counter; }
void set_object_counter(object_id value);
- struct neighbor_pair final { chunk* c; chunk_coords_ coord; };
+ struct neighbor_pair final { chunk* c = nullptr; chunk_coords_ coord; };
std::array<neighbor_pair, 8> neighbors(chunk_coords_ coord);
diff --git a/test/path-search.cpp b/test/path-search.cpp
index 3b1c4e93..6fad1fa5 100644
--- a/test/path-search.cpp
+++ b/test/path-search.cpp
@@ -23,6 +23,10 @@ void test_bbox()
return path_search::make_neighbor_tile_bbox(coord, {}, r);
};
+ constexpr auto neighbor_tiles = [](world& w, chunk_coords_ ch, Vector2i pos) {
+ return path_search::get_walkable_neighbor_tiles(w, {ch, pos}, {}, (object_id)-1);
+ };
+
const auto metal2 = loader.tile_atlas("metal2", {2, 2}, pass_mode::blocked);
const auto table = loader.scenery("table1");
@@ -61,19 +65,25 @@ void test_bbox()
fm_assert( is_passable_1(c, bbox({8, 6}, N)) );
fm_assert( !is_passable_1(c, bbox({8, 6}, S)) );
fm_assert( !is_passable_1(c, bbox({8, 7}, N)) );
+
fm_assert( is_passable_1(c, bbox({8, 8}, N)) );
fm_assert( is_passable_1(c, bbox({8, 8}, E)) );
fm_assert( !is_passable_1(c, bbox({8, 8}, S)) );
fm_assert( is_passable_1(c, bbox({8, 8}, W)) );
+ fm_assert(neighbor_tiles(w, ch, {8, 8}).size == 3);
+
c[{8, 8}].wall_north() = {metal2,0};
c.mark_passability_modified();
fm_assert( is_passable_1(c, bbox({8, 8}, C)));
fm_assert( !is_passable_1(c, bbox({8, 7}, S)) );
+
fm_assert( !is_passable_1(c, bbox({8, 8}, N)) );
fm_assert( is_passable_1(c, bbox({8, 8}, E)) );
fm_assert( !is_passable_1(c, bbox({8, 8}, S)) );
fm_assert( is_passable_1(c, bbox({8, 8}, W)) );
+
+ fm_assert(neighbor_tiles(w, ch, {8, 8}).size == 2);
}
{
using enum rotation;
@@ -92,6 +102,11 @@ void test_bbox()
is_passable_NESW(c, {8, 9}, { false, true, true, true });
is_passable_NESW(c, {2, 4}, { true, false, true, true });
is_passable_NESW(c, {4, 4}, { true, true, true, false });
+
+ fm_assert(neighbor_tiles(w, ch, {8, 8}).size == 0);
+ fm_assert(neighbor_tiles(w, ch, {8, 9}).size == 3);
+ fm_assert(neighbor_tiles(w, ch, {2, 4}).size == 3);
+ fm_assert(neighbor_tiles(w, ch, {4, 4}).size == 3);
}
}