diff options
-rw-r--r-- | src/object.cpp | 42 | ||||
-rw-r--r-- | src/object.hpp | 6 | ||||
-rw-r--r-- | src/timer-ns.cpp | 16 | ||||
-rw-r--r-- | src/timer.hpp | 15 | ||||
-rw-r--r-- | test/critter.cpp | 55 |
5 files changed, 107 insertions, 27 deletions
diff --git a/src/object.cpp b/src/object.cpp index 041a6d48..208f4fe2 100644 --- a/src/object.cpp +++ b/src/object.cpp @@ -213,18 +213,25 @@ bool object::can_move_to(Vector2i delta) return can_move_to(delta, coord, offset, bbox_offset, bbox_size); } -void object::move_to(size_t& i, Vector2i delta, rotation new_r) +void object::teleport_to(size_t& i, point pt, rotation new_r) { - if (!can_rotate(new_r)) - return; + return teleport_to(i, pt.coord(), pt.offset(), new_r); +} - auto& es = c->_objects; - fm_debug_assert(i < es.size()); - auto e_ = es[i]; +void object::teleport_to(size_t& i, global_coords coord_, Vector2b offset_, rotation new_r) +{ + if (new_r == rotation_COUNT) + new_r = r; + else if (!atlas->check_rotation(new_r) || true) + { + const auto& info = atlas->info(); + const auto *obj = info.object_name.data(), *anim = info.anim_name.data(); + fm_abort("wrong rotation %d for %s/%s!", (int)new_r, obj, anim); + } + fm_assert(i < c->_objects.size()); + const auto e_ = c->_objects[i]; fm_assert(&*e_ == this); - auto& w = *c->_world; - const auto [coord_, offset_] = normalize_coords(coord, offset, delta); if (coord_ == coord && offset_ == offset) return; @@ -247,26 +254,37 @@ void object::move_to(size_t& i, Vector2i delta, rotation new_r) } else { + auto& w = *c->_world; + auto& c2 = w[coord_.chunk3()]; if (!is_dynamic()) c2.mark_scenery_modified(); c2._add_bbox(bb1); c->remove_object(i); auto& es = c2._objects; - auto it = std::lower_bound(es.cbegin(), es.cend(), e_, object_id_lessp); const_cast<global_coords&>(coord) = coord_; set_bbox_(offset_, bb_offset, bb_size, pass); const_cast<rotation&>(r) = new_r; const_cast<class chunk*&>(c) = &c2; - i = (size_t)std::distance(es.cbegin(), it); + i = (size_t)std::distance(es.cbegin(), std::lower_bound(es.cbegin(), es.cend(), e_, object_id_lessp)); arrayInsert(es, i, move(e_)); } } -void object::move_to(Magnum::Vector2i delta) + +bool object::move_to(size_t& i, Vector2i delta, rotation new_r) +{ + if (!can_rotate(new_r)) + return false; + const auto [coord_, offset_] = normalize_coords(coord, offset, delta); + teleport_to(i, coord_, offset_, new_r); + return true; +} + +bool object::move_to(Magnum::Vector2i delta) { auto i = index(); - move_to(i, delta, r); + return move_to(i, delta, r); } uint32_t object::allocate_frame_time(Ns dt, uint16_t& accum, uint32_t hz, float speed) diff --git a/src/object.hpp b/src/object.hpp index 49d861aa..9f029efa 100644 --- a/src/object.hpp +++ b/src/object.hpp @@ -82,8 +82,10 @@ struct object virtual bool is_dynamic() const; bool can_rotate(rotation new_r); bool can_move_to(Vector2i delta); - void move_to(size_t& i, Vector2i delta, rotation new_r); - void move_to(Vector2i delta); + bool move_to(size_t& i, Vector2i delta, rotation new_r); + bool move_to(Vector2i delta); + void teleport_to(size_t& i, global_coords coord, Vector2b offset, rotation new_r); + void teleport_to(size_t& i, point pt, rotation new_r); static uint32_t allocate_frame_time(Ns dt, uint16_t& accum, uint32_t hz, float speed); uint32_t allocate_frame_time(Ns dt, float speed); diff --git a/src/timer-ns.cpp b/src/timer-ns.cpp index a6d1a073..45d0411c 100644 --- a/src/timer-ns.cpp +++ b/src/timer-ns.cpp @@ -56,6 +56,14 @@ Ns operator*(uint64_t a, const Ns& rhs) return Ns{a} * b; } +Ns operator*(const Ns& lhs, float b_) +{ + long double a(lhs.stamp), b(b_); + auto x = a * b; + fm_assert(x <= 1 << 24 && x >= 0); + return Ns{uint64_t(x)}; +} + uint64_t operator/(const Ns& lhs, const Ns& rhs) { auto a = lhs.stamp, b = rhs.stamp; @@ -96,6 +104,14 @@ std::strong_ordering operator<=>(const Ns& lhs, const Ns& rhs) return a <=> b; } +Ns Ns::from_millis(uint64_t a) +{ + constexpr auto b = uint64_t(1e6); + const auto x = a * b; + fm_assert(a == 0 || x / a == b); + return Ns{x}; +}; + Ns::operator uint64_t() const { return stamp; } Ns::operator float() const { return float(stamp); } uint64_t Ns::operator*() const { return stamp; } diff --git a/src/timer.hpp b/src/timer.hpp index 8eef447e..a05cc507 100644 --- a/src/timer.hpp +++ b/src/timer.hpp @@ -5,13 +5,9 @@ namespace floormat { struct Ns { - static constexpr uint64_t Min = 0, Max = (uint64_t)-1; - static constexpr uint64_t Second = 1000000000, Millisecond = 1000000; - - uint64_t stamp; - explicit constexpr Ns(): stamp{0} {} explicit constexpr Ns(uint64_t x) : stamp{x} {} + static Ns from_millis(uint64_t x); explicit operator uint64_t() const; explicit operator float() const; @@ -21,6 +17,8 @@ struct Ns friend Ns operator-(const Ns& lhs, const Ns& rhs); friend Ns operator*(const Ns& lhs, uint64_t rhs); friend Ns operator*(uint64_t lhs, const Ns& rhs); + friend Ns operator*(const Ns& lhs, float rhs); + friend Ns operator*(float lhs, const Ns& rhs); friend uint64_t operator/(const Ns& lhs, const Ns& rhs); friend Ns operator/(const Ns& lhs, uint64_t rhs); @@ -29,10 +27,15 @@ struct Ns friend bool operator==(const Ns& lhs, const Ns& rhs); friend std::strong_ordering operator<=>(const Ns& lhs, const Ns& rhs); - friend Debug& operator<<(Debug& dbg, const Ns& box); + + uint64_t stamp; + + static constexpr uint64_t Min = 0, Max = (uint64_t)-1; }; +constexpr inline Ns Second{1000000000}, Millisecond{1000000}; + struct Time final { static Time now() noexcept; diff --git a/test/critter.cpp b/test/critter.cpp index 6eb42315..fe9a2b07 100644 --- a/test/critter.cpp +++ b/test/critter.cpp @@ -3,12 +3,40 @@ #include "src/critter.hpp" #include "src/world.hpp" #include "src/wall-atlas.hpp" +#include "src/timer.hpp" #include "loader/loader.hpp" namespace floormat { namespace { +constexpr auto constantly(const auto& x) noexcept { + return [x]<typename... Ts> (const Ts&...) constexpr -> const auto& { return x; }; +} + +template<typename F> +void run(StringView name, const F& make_dt, critter& npc, const uint32_t max_steps, + const point expected_pt, const Ns expected_time, + const uint32_t fuzz_pixels, const Ns fuzz_time) +{ + fm_assert(max_steps <= 1000); + + Ns time{0}; + uint32_t steps; + + Debug{} << "==>" << name; + + for (uint32_t i = 0; i < max_steps; i++) + { + auto dt = Ns{make_dt()}; + Debug{} << ">>" << i << dt; + fm_assert(dt <= Ns(1e9)); + Debug{} << " " << i << npc.position(); + } + + Debug{} << "done"; +} + /* ***** TEST 1 ***** * * wall n 0x0 - 8:9 @@ -20,7 +48,20 @@ namespace { * after chunk=0x0 tile=8:9 offset=-8:-16 */ -template<typename F> void test1(F&& make_dt) +critter_proto make_proto(int accel) +{ + critter_proto proto; + proto.atlas = loader.anim_atlas("npc-walk", loader.ANIM_PATH); + proto.name = "Player"_s; + proto.speed = accel; + proto.playable = true; + proto.offset = {}; + proto.bbox_offset = {}; + proto.bbox_size = Vector2ub(tile_size_xy/2); + return proto; +} + +template<typename F> void test1(const F& make_dt, int accel) { const auto W = wall_image_proto{ loader.wall_atlas("empty"), 0 }; @@ -28,13 +69,13 @@ template<typename F> void test1(F&& make_dt) w[{{0,0,0}, {8,9}}].t.wall_north() = W; w[{{0,1,0}, {8,0}}].t.wall_north() = W; - critter_proto cproto; - cproto.name = "Player"_s; - cproto.speed = 10; - cproto.playable = true; + constexpr point init {{0,0,0}, {8,15}, {-8, 8}}; + constexpr point end {{0,0,0}, {8, 9}, {-8,-16}}; object_id id = 0; - w.ensure_player_character(id, move(cproto)); + auto player = w.ensure_player_character(id, make_proto(accel)).ptr; + auto index = player->index(); + player->teleport_to(index, ); w[chunk_coords_{0,0,0}].mark_modified(); w[chunk_coords_{0,1,0}].mark_modified(); @@ -49,7 +90,7 @@ template<typename F> void test2(F&& make_dt) void test_app::test_critter() { - + test1(constantly(Ns::Millisecond*16.666667), 1); } } // namespace floormat |