summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2024-03-02 11:52:53 +0100
committerStanislaw Halik <sthalik@misaki.pl>2024-03-02 11:52:53 +0100
commita6481a7065852cb01846a5dc8a92fd415ba745fb (patch)
tree68321663f06ca3d3b54774e6a649283ef944df81
parent9ff017f1d4c1502fca9797aa4b38351c97e57982 (diff)
w
-rw-r--r--src/object.cpp42
-rw-r--r--src/object.hpp6
-rw-r--r--src/timer-ns.cpp16
-rw-r--r--src/timer.hpp15
-rw-r--r--test/critter.cpp55
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