From d90c38ce59d406cdfd4303c836ee524a71ad0979 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Fri, 1 Sep 2023 22:36:26 +0200 Subject: rename character -> critter --- editor/app.cpp | 12 +-- editor/app.hpp | 2 +- editor/draw.cpp | 2 +- editor/inspect-types.cpp | 21 ++--- editor/update.cpp | 4 +- serialize/world-impl.hpp | 2 +- serialize/world-reader.cpp | 14 +-- serialize/world-writer.cpp | 16 ++-- src/character.cpp | 220 --------------------------------------------- src/character.hpp | 50 ----------- src/chunk-scenery.cpp | 2 +- src/critter.cpp | 220 +++++++++++++++++++++++++++++++++++++++++++++ src/critter.hpp | 50 +++++++++++ src/object-type.hpp | 2 +- test/serializer.cpp | 10 +-- 15 files changed, 314 insertions(+), 313 deletions(-) delete mode 100644 src/character.cpp delete mode 100644 src/character.hpp create mode 100644 src/critter.cpp create mode 100644 src/critter.hpp diff --git a/editor/app.cpp b/editor/app.cpp index 43e3116c..7f6f4171 100644 --- a/editor/app.cpp +++ b/editor/app.cpp @@ -6,7 +6,7 @@ #include "loader/loader.hpp" #include "world.hpp" #include "src/anim-atlas.hpp" -#include "src/character.hpp" +#include "src/critter.hpp" #include #include #include @@ -39,7 +39,7 @@ void app::reset_world() void app::ensure_player_character(world& w) { if (_character_id) - if (auto C = w.find_object(_character_id); C && C->type() == object_type::character) + if (auto C = w.find_object(_character_id); C && C->type() == object_type::critter) return; _character_id = 0; @@ -50,9 +50,9 @@ void app::ensure_player_character(world& w) for (const auto& e_ : c.objects()) { const auto& e = *e_; - if (e.type() == object_type::character) + if (e.type() == object_type::critter) { - const auto& C = static_cast(e); + const auto& C = static_cast(e); if (C.playable) id = std::min(id, C.id); } @@ -63,10 +63,10 @@ void app::ensure_player_character(world& w) _character_id = id; else { - character_proto cproto; + critter_proto cproto; cproto.name = "Player"_s; cproto.playable = true; - _character_id = w.make_object(w.make_id(), global_coords{}, cproto)->id; + _character_id = w.make_object(w.make_id(), global_coords{}, cproto)->id; } } diff --git a/editor/app.hpp b/editor/app.hpp index d3a02017..57849a08 100644 --- a/editor/app.hpp +++ b/editor/app.hpp @@ -24,7 +24,7 @@ struct tile_atlas; struct tile_editor; struct fm_settings; struct anim_atlas; -struct character; +struct critter; struct cursor_state final { Optional pixel; diff --git a/editor/draw.cpp b/editor/draw.cpp index bd0d863d..539b6c53 100644 --- a/editor/draw.cpp +++ b/editor/draw.cpp @@ -7,7 +7,7 @@ #include "draw/anim.hpp" #include "src/camera-offset.hpp" #include "src/world.hpp" -#include "character.hpp" +#include "src/critter.hpp" #include "rotation.inl" #include "src/RTree-search.hpp" diff --git a/editor/inspect-types.cpp b/editor/inspect-types.cpp index 84fbbd5d..5996597f 100644 --- a/editor/inspect-types.cpp +++ b/editor/inspect-types.cpp @@ -6,7 +6,8 @@ #include "inspect.hpp" #include "loader/loader.hpp" #include "chunk.hpp" -#include "src/character.hpp" +#include "src/critter.hpp" + #include "src/light.hpp" #include #include @@ -95,7 +96,7 @@ template<> struct has_anim_atlas : std::true_type { static const anim_atlas& get_atlas(const object& x) { return *x.atlas; } }; template<> struct has_anim_atlas : has_anim_atlas {}; -template<> struct has_anim_atlas : has_anim_atlas {}; +template<> struct has_anim_atlas : has_anim_atlas {}; #endif using enum_pair = std::pair; @@ -174,18 +175,18 @@ static bool inspect_type(T& x, Intent) } template<> -struct entity_accessors { +struct entity_accessors { static constexpr auto accessors() { - using E = Entity; + using E = Entity; auto tuple0 = entity_accessors::accessors(); auto tuple = std::tuple{ E::type::field{"name"_s, - [](const character& x) { return x.name; }, - [](character& x, const String& value) { x.name = value; }}, + [](const critter& x) { return x.name; }, + [](critter& x, const String& value) { x.name = value; }}, E::type::field{"playable"_s, - [](const character& x) { return x.playable; }, - [](character& x, bool value) { x.playable = value; }, + [](const critter& x) { return x.playable; }, + [](critter& x, bool value) { x.playable = value; }, constantly(constraints::max_length{128}), }, }; @@ -235,7 +236,7 @@ struct entity_accessors //template bool inspect_type(object&); template bool inspect_type(scenery&, inspect_intent_t); -template bool inspect_type(character&, inspect_intent_t); +template bool inspect_type(critter&, inspect_intent_t); template bool inspect_type(light&, inspect_intent_t); bool inspect_object_subtype(object& x) @@ -245,7 +246,7 @@ bool inspect_object_subtype(object& x) default: fm_warn_once("unknown object subtype '%d'", (int)type); return false; //case object_type::none: return inspect_type(x); case object_type::scenery: return inspect_type(static_cast(x), inspect_intent_t{}); - case object_type::character: return inspect_type(static_cast(x), inspect_intent_t{}); + case object_type::critter: return inspect_type(static_cast(x), inspect_intent_t{}); case object_type::light: return inspect_type(static_cast(x), inspect_intent_t{}); } } diff --git a/editor/update.cpp b/editor/update.cpp index 4dacaf8a..aa1495c1 100644 --- a/editor/update.cpp +++ b/editor/update.cpp @@ -5,7 +5,7 @@ #include "main/clickable.hpp" #include "floormat/events.hpp" #include "floormat/main.hpp" -#include "src/character.hpp" +#include "src/critter.hpp" #include "src/tile-iterator.hpp" #include "keys.hpp" #include "loader/loader.hpp" @@ -234,7 +234,7 @@ void app::update_character([[maybe_unused]] float dt) if (_character_id) { auto& w = M->world(); - auto c = w.find_object(_character_id); + auto c = w.find_object(_character_id); if (c && c->playable) c->set_keys(keys[key_left], keys[key_right], keys[key_up], keys[key_down]); } diff --git a/serialize/world-impl.hpp b/serialize/world-impl.hpp index b01e81ba..f01276be 100644 --- a/serialize/world-impl.hpp +++ b/serialize/world-impl.hpp @@ -54,7 +54,7 @@ constexpr inline proto_t proto_version = 16; constexpr inline size_t atlas_name_max = 128; constexpr inline auto null_atlas = (atlasid)-1LL; -constexpr inline size_t character_name_max = 128; +constexpr inline size_t critter_name_max = 128; constexpr inline size_t string_max = 512; constexpr inline proto_t min_proto_version = 1; diff --git a/serialize/world-reader.cpp b/serialize/world-reader.cpp index 769dda20..53b675ea 100644 --- a/serialize/world-reader.cpp +++ b/serialize/world-reader.cpp @@ -3,7 +3,7 @@ #include "binary-reader.inl" #include "src/world.hpp" #include "src/scenery.hpp" -#include "src/character.hpp" +#include "src/critter.hpp" #include "src/light.hpp" #include "loader/loader.hpp" #include "loader/scenery.hpp" @@ -77,7 +77,7 @@ bool read_object_flags(binary_reader& s, U& e) e.closing = !!(flags & 1 << 3); e.interactive = !!(flags & 1 << 4); } - else if constexpr(tag == object_type::character) + else if constexpr(tag == object_type::critter) { e.playable = !!(flags & 1 << 2); } @@ -259,8 +259,8 @@ void reader_state::read_chunks(reader_t& s) SET_CHUNK_SIZE(); switch (type) { - case object_type::character: { - character_proto proto; + case object_type::critter: { + critter_proto proto; proto.offset = offset; uint8_t id; id << s; proto.r = rotation(id >> sizeof(id)*8-1-rotation_BITS & rotation_MASK); @@ -278,12 +278,12 @@ void reader_state::read_chunks(reader_t& s) { uint32_t id; id << s; auto name = lookup_string(id); - fm_soft_assert(name.size() < character_name_max); + fm_soft_assert(name.size() < critter_name_max); proto.name = name; } else { - auto [buf, len] = s.read_asciiz_string(); + auto [buf, len] = s.read_asciiz_string(); auto name = StringView{buf, len}; proto.name = name; } @@ -297,7 +297,7 @@ void reader_state::read_chunks(reader_t& s) read_bbox(s, proto); } SET_CHUNK_SIZE(); - auto e = _world->make_object(oid, {ch, local}, proto); + auto e = _world->make_object(oid, {ch, local}, proto); e->offset_frac = offset_frac; (void)e; break; diff --git a/serialize/world-writer.cpp b/serialize/world-writer.cpp index 6d32762f..fedf96d6 100644 --- a/serialize/world-writer.cpp +++ b/serialize/world-writer.cpp @@ -9,7 +9,7 @@ #include "src/emplacer.hpp" #include "loader/loader.hpp" #include "src/scenery.hpp" -#include "src/character.hpp" +#include "src/critter.hpp" #include "loader/scenery.hpp" #include "src/anim-atlas.hpp" #include "src/light.hpp" @@ -77,7 +77,7 @@ private: constexpr auto tile_size = sizeof(tilemeta) + (sizeof(atlasid) + sizeof(variant_t)) * 3; constexpr auto chunkbuf_size = sizeof(chunk_magic) + sizeof(chunk_coords_) + tile_size * TILE_COUNT + sizeof(uint32_t); -constexpr auto object_size = std::max({ sizeof(character), sizeof(scenery), sizeof(light), }); +constexpr auto object_size = std::max({ sizeof(critter), sizeof(scenery), sizeof(light), }); writer_state::writer_state(const world& world) : _world{&world} { @@ -194,7 +194,7 @@ void write_object_flags(binary_writer& s, const U& e) flags |= (1 << 3) * e.closing; flags |= (1 << 4) * e.interactive; } - else if constexpr(tag == object_type::character) + else if constexpr(tag == object_type::critter) { flags |= (1 << 2) * e.playable; } @@ -299,7 +299,7 @@ void writer_state::serialize_scenery_names() void writer_state::serialize_strings() { - static_assert(character_name_max <= string_max); + static_assert(critter_name_max <= string_max); auto len = 0uz; for (const auto& [k, v] : string_map) { @@ -351,8 +351,8 @@ void writer_state::serialize_scenery(const chunk& c, writer_t& s) { default: fm_abort("invalid object type '%d'", (int)type); - case object_type::character: { - const auto& C = static_cast(e); + case object_type::critter: { + const auto& C = static_cast(e); uint8_t id = 0; const auto sc_exact = C.bbox_offset.isZero() && @@ -367,7 +367,7 @@ void writer_state::serialize_scenery(const chunk& c, writer_t& s) s << C.frame; s << C.offset_frac[0]; s << C.offset_frac[1]; - fm_assert(C.name.size() < character_name_max); + fm_assert(C.name.size() < critter_name_max); s << intern_string(C.name); if (!sc_exact) write_bbox(s, C); @@ -542,7 +542,7 @@ ArrayView writer_state::serialize_world() case object_type::scenery: intern_scenery(static_cast(e), false); break; - case object_type::character: + case object_type::critter: case object_type::light: break; default: diff --git a/src/character.cpp b/src/character.cpp deleted file mode 100644 index 3e252e7a..00000000 --- a/src/character.cpp +++ /dev/null @@ -1,220 +0,0 @@ -#include "character.hpp" -#include "src/anim-atlas.hpp" -#include "loader/loader.hpp" -#include "src/world.hpp" -#include "src/object.hpp" -#include "shaders/shader.hpp" -#include "src/RTree-search.hpp" -#include "compat/exception.hpp" -#include -#include -#include -#include - -namespace floormat { - -namespace { - -template constexpr T sgn(T val) { return T(T(0) < val) - T(val < T(0)); } - -constexpr int tile_size_1 = iTILE_SIZE2.sum()/2, - framerate = 96 * 3, move_speed = tile_size_1 * 2 * 3; -constexpr float frame_time = 1.f/framerate; - -constexpr auto arrows_to_dir(bool left, bool right, bool up, bool down) -{ - if (left == right) - left = right = false; - if (up == down) - up = down = false; - - const auto bits = unsigned(left << 3 | right << 2 | up << 1 | down << 0); - constexpr unsigned L = 1 << 3, R = 1 << 2, U = 1 << 1, D = 1 << 0; - - switch (bits) - { - using enum rotation; - case 0: return rotation{rotation_COUNT}; - case L | U: return W; - case L | D: return S; - case R | U: return N; - case R | D: return E; - case L: return SW; - case D: return SE; - case R: return NE; - case U: return NW; - } - std::unreachable(); -} - -constexpr Vector2i rotation_to_vec(rotation r) -{ - CORRADE_ASSUME(r < rotation_COUNT); - switch (r) - { - using enum rotation; - case N: return { 0, -1 }; - case NE: return { 1, -1 }; - case E: return { 1, 0 }; - case SE: return { 1, 1 }; - case S: return { 0, 1 }; - case SW: return { -1, 1 }; - case W: return { -1, 0 }; - case NW: return { -1, -1 }; - } - std::unreachable(); -} - -constexpr std::array rotation_to_similar(rotation r) -{ - CORRADE_ASSUME(r < rotation_COUNT); - switch (r) - { - using enum rotation; - case N: return { N, NW, NE }; - case NE: return { NE, N, E }; - case E: return { E, NE, SE }; - case SE: return { SE, E, S }; - case S: return { S, SE, SW }; - case SW: return { SW, S, W }; - case W: return { W, SW, NW }; - case NW: return { NW, W, N }; - } - std::unreachable(); -} - -} // namespace - -character_proto::character_proto(const character_proto&) = default; -character_proto::~character_proto() noexcept = default; -character_proto& character_proto::operator=(const character_proto&) = default; - -character_proto::character_proto() -{ - type = object_type::character; - atlas = loader.anim_atlas("npc-walk", loader.ANIM_PATH); -} - -bool character_proto::operator==(const object_proto& e0) const -{ - if (type != e0.type) - return false; - - if (!object_proto::operator==(e0)) - return false; - - const auto& s0 = static_cast(e0); - return name == s0.name && playable == s0.playable; -} - -int character::allocate_frame_time(float dt) -{ - int d = int(delta) + int(65535u * dt); - constexpr int framerate_ = 65535/framerate; - static_assert(framerate_ > 0); - auto ret = d / framerate_; - delta = (uint16_t)std::clamp(d - ret*65535LL, 0LL, 65535LL); - return ret; -} - -Vector2 character::move_vec(Vector2i vec) -{ - const int left_right = vec[0], top_bottom = vec[1]; - constexpr auto c = move_speed * frame_time; - return c * Vector2((float)sgn(left_right), (float)sgn(top_bottom)).normalized(); -} - -void character::set_keys(bool L, bool R, bool U, bool D) -{ - b_L = L; - b_R = R; - b_U = U; - b_D = D; -} - -float character::depth_offset() const -{ - return tile_shader::character_depth_offset; -} - -Vector2 character::ordinal_offset(Vector2b offset) const -{ - (void)offset; - return Vector2(offset); -} - -void character::update(size_t i, float dt) -{ - const auto new_r = arrows_to_dir(b_L, b_R, b_U, b_D); - if (new_r == rotation{rotation_COUNT}) - { - delta = 0; - return; - } - - int nframes = allocate_frame_time(dt); - - if (nframes == 0) - return; - - auto [_0, _1, _2] = rotation_to_similar(r); - const Vector2 move_vecs[] = { - move_vec(rotation_to_vec(_0)), - move_vec(rotation_to_vec(_1)), - move_vec(rotation_to_vec(_2)), - }; - - - if (r != new_r) - if (is_dynamic()) - rotate(i, new_r); - - c->ensure_passability(); - - for (int k = 0; k < nframes; k++) - { - for (auto j = 0uz; j < 3; j++) - { - auto vec = move_vecs[j]; - constexpr auto frac = Vector2(32767); - constexpr auto inv_frac = 1.f / frac; - auto offset_ = vec + Vector2(offset_frac) * inv_frac; - offset_frac = Vector2s(Vector2(std::fmod(offset_[0], 1.f), std::fmod(offset_[1], 1.f)) * frac); - auto off_i = Vector2i(offset_); - if (can_move_to(off_i)) - { - move_to(i, off_i, new_r); - ++frame %= atlas->info().nframes; - goto done; - } - } - delta = 0; - break; -done: - (void)0; - } -} - -object_type character::type() const noexcept { return object_type::character; } - -character::operator character_proto() const -{ - character_proto ret; - static_cast(ret) = object::operator object_proto(); - ret.name = name; - ret.playable = playable; - return ret; -} - -character::character(object_id id, struct chunk& c, const character_proto& proto) : - object{id, c, proto}, - name{proto.name}, - playable{proto.playable} -{ - if (!name) - name = "(Unnamed)"_s; - fm_soft_assert(atlas->check_rotation(r)); - object::set_bbox_(offset, bbox_offset, Vector2ub(iTILE_SIZE2/2), pass); -} - -} // namespace floormat diff --git a/src/character.hpp b/src/character.hpp deleted file mode 100644 index 2c7543a5..00000000 --- a/src/character.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once -#include "src/global-coords.hpp" -#include "src/rotation.hpp" -#include "src/object.hpp" -#include - -namespace floormat { - -struct anim_atlas; -struct world; - -struct character_proto : object_proto -{ - String name; - bool playable : 1 = false; - - character_proto(); - character_proto(const character_proto&); - ~character_proto() noexcept override; - character_proto& operator=(const character_proto&); - bool operator==(const object_proto& proto) const override; -}; - -struct character final : object -{ - object_type type() const noexcept override; - explicit operator character_proto() const; - - void update(size_t i, float dt) override; - void set_keys(bool L, bool R, bool U, bool D); - Vector2 ordinal_offset(Vector2b offset) const override; - float depth_offset() const override; - - String name; - Vector2s offset_frac; - bool b_L : 1 = false, b_R : 1 = false, b_U : 1 = false, b_D : 1 = false; - bool playable : 1 = false; - -private: - int allocate_frame_time(float dt); - static Vector2 move_vec(Vector2i vec); - - friend struct world; - character(object_id id, struct chunk& c, const character_proto& proto); -}; - -template<> struct object_type_ : std::integral_constant {}; -template<> struct object_type_ : std::integral_constant {}; - -} // namespace floormat diff --git a/src/chunk-scenery.cpp b/src/chunk-scenery.cpp index d211b6a4..6fc48821 100644 --- a/src/chunk-scenery.cpp +++ b/src/chunk-scenery.cpp @@ -122,7 +122,7 @@ auto chunk::make_topo_sort_data(object& e, uint32_t mesh_idx) -> topo_sort_data break; } } - else if (e.type() == object_type::character) + else if (e.type() == object_type::critter) data.mode = topo_sort_data::mode_character; return data; } diff --git a/src/critter.cpp b/src/critter.cpp new file mode 100644 index 00000000..9111aaf6 --- /dev/null +++ b/src/critter.cpp @@ -0,0 +1,220 @@ +#include "critter.hpp" +#include "src/anim-atlas.hpp" +#include "loader/loader.hpp" +#include "src/world.hpp" +#include "src/object.hpp" +#include "shaders/shader.hpp" +#include "src/RTree-search.hpp" +#include "compat/exception.hpp" +#include +#include +#include +#include + +namespace floormat { + +namespace { + +template constexpr T sgn(T val) { return T(T(0) < val) - T(val < T(0)); } + +constexpr int tile_size_1 = iTILE_SIZE2.sum()/2, + framerate = 96 * 3, move_speed = tile_size_1 * 2 * 3; +constexpr float frame_time = 1.f/framerate; + +constexpr auto arrows_to_dir(bool left, bool right, bool up, bool down) +{ + if (left == right) + left = right = false; + if (up == down) + up = down = false; + + const auto bits = unsigned(left << 3 | right << 2 | up << 1 | down << 0); + constexpr unsigned L = 1 << 3, R = 1 << 2, U = 1 << 1, D = 1 << 0; + + switch (bits) + { + using enum rotation; + case 0: return rotation{rotation_COUNT}; + case L | U: return W; + case L | D: return S; + case R | U: return N; + case R | D: return E; + case L: return SW; + case D: return SE; + case R: return NE; + case U: return NW; + } + std::unreachable(); +} + +constexpr Vector2i rotation_to_vec(rotation r) +{ + CORRADE_ASSUME(r < rotation_COUNT); + switch (r) + { + using enum rotation; + case N: return { 0, -1 }; + case NE: return { 1, -1 }; + case E: return { 1, 0 }; + case SE: return { 1, 1 }; + case S: return { 0, 1 }; + case SW: return { -1, 1 }; + case W: return { -1, 0 }; + case NW: return { -1, -1 }; + } + std::unreachable(); +} + +constexpr std::array rotation_to_similar(rotation r) +{ + CORRADE_ASSUME(r < rotation_COUNT); + switch (r) + { + using enum rotation; + case N: return { N, NW, NE }; + case NE: return { NE, N, E }; + case E: return { E, NE, SE }; + case SE: return { SE, E, S }; + case S: return { S, SE, SW }; + case SW: return { SW, S, W }; + case W: return { W, SW, NW }; + case NW: return { NW, W, N }; + } + std::unreachable(); +} + +} // namespace + +critter_proto::critter_proto(const critter_proto&) = default; +critter_proto::~critter_proto() noexcept = default; +critter_proto& critter_proto::operator=(const critter_proto&) = default; + +critter_proto::critter_proto() +{ + type = object_type::critter; + atlas = loader.anim_atlas("npc-walk", loader.ANIM_PATH); +} + +bool critter_proto::operator==(const object_proto& e0) const +{ + if (type != e0.type) + return false; + + if (!object_proto::operator==(e0)) + return false; + + const auto& s0 = static_cast(e0); + return name == s0.name && playable == s0.playable; +} + +int critter::allocate_frame_time(float dt) +{ + int d = int(delta) + int(65535u * dt); + constexpr int framerate_ = 65535/framerate; + static_assert(framerate_ > 0); + auto ret = d / framerate_; + delta = (uint16_t)std::clamp(d - ret*65535LL, 0LL, 65535LL); + return ret; +} + +Vector2 critter::move_vec(Vector2i vec) +{ + const int left_right = vec[0], top_bottom = vec[1]; + constexpr auto c = move_speed * frame_time; + return c * Vector2((float)sgn(left_right), (float)sgn(top_bottom)).normalized(); +} + +void critter::set_keys(bool L, bool R, bool U, bool D) +{ + b_L = L; + b_R = R; + b_U = U; + b_D = D; +} + +float critter::depth_offset() const +{ + return tile_shader::character_depth_offset; +} + +Vector2 critter::ordinal_offset(Vector2b offset) const +{ + (void)offset; + return Vector2(offset); +} + +void critter::update(size_t i, float dt) +{ + const auto new_r = arrows_to_dir(b_L, b_R, b_U, b_D); + if (new_r == rotation{rotation_COUNT}) + { + delta = 0; + return; + } + + int nframes = allocate_frame_time(dt); + + if (nframes == 0) + return; + + auto [_0, _1, _2] = rotation_to_similar(r); + const Vector2 move_vecs[] = { + move_vec(rotation_to_vec(_0)), + move_vec(rotation_to_vec(_1)), + move_vec(rotation_to_vec(_2)), + }; + + + if (r != new_r) + if (is_dynamic()) + rotate(i, new_r); + + c->ensure_passability(); + + for (int k = 0; k < nframes; k++) + { + for (auto j = 0uz; j < 3; j++) + { + auto vec = move_vecs[j]; + constexpr auto frac = Vector2(32767); + constexpr auto inv_frac = 1.f / frac; + auto offset_ = vec + Vector2(offset_frac) * inv_frac; + offset_frac = Vector2s(Vector2(std::fmod(offset_[0], 1.f), std::fmod(offset_[1], 1.f)) * frac); + auto off_i = Vector2i(offset_); + if (can_move_to(off_i)) + { + move_to(i, off_i, new_r); + ++frame %= atlas->info().nframes; + goto done; + } + } + delta = 0; + break; +done: + (void)0; + } +} + +object_type critter::type() const noexcept { return object_type::critter; } + +critter::operator critter_proto() const +{ + critter_proto ret; + static_cast(ret) = object::operator object_proto(); + ret.name = name; + ret.playable = playable; + return ret; +} + +critter::critter(object_id id, struct chunk& c, const critter_proto& proto) : + object{id, c, proto}, + name{proto.name}, + playable{proto.playable} +{ + if (!name) + name = "(Unnamed)"_s; + fm_soft_assert(atlas->check_rotation(r)); + object::set_bbox_(offset, bbox_offset, Vector2ub(iTILE_SIZE2/2), pass); +} + +} // namespace floormat diff --git a/src/critter.hpp b/src/critter.hpp new file mode 100644 index 00000000..34ff9b33 --- /dev/null +++ b/src/critter.hpp @@ -0,0 +1,50 @@ +#pragma once +#include "src/global-coords.hpp" +#include "src/rotation.hpp" +#include "src/object.hpp" +#include + +namespace floormat { + +struct anim_atlas; +struct world; + +struct critter_proto : object_proto +{ + String name; + bool playable : 1 = false; + + critter_proto(); + critter_proto(const critter_proto&); + ~critter_proto() noexcept override; + critter_proto& operator=(const critter_proto&); + bool operator==(const object_proto& proto) const override; +}; + +struct critter final : object +{ + object_type type() const noexcept override; + explicit operator critter_proto() const; + + void update(size_t i, float dt) override; + void set_keys(bool L, bool R, bool U, bool D); + Vector2 ordinal_offset(Vector2b offset) const override; + float depth_offset() const override; + + String name; + Vector2s offset_frac; + bool b_L : 1 = false, b_R : 1 = false, b_U : 1 = false, b_D : 1 = false; + bool playable : 1 = false; + +private: + int allocate_frame_time(float dt); + static Vector2 move_vec(Vector2i vec); + + friend struct world; + critter(object_id id, struct chunk& c, const critter_proto& proto); +}; + +template<> struct object_type_ : std::integral_constant {}; +template<> struct object_type_ : std::integral_constant {}; + +} // namespace floormat diff --git a/src/object-type.hpp b/src/object-type.hpp index 1a1d1aff..3a6a92e9 100644 --- a/src/object-type.hpp +++ b/src/object-type.hpp @@ -3,7 +3,7 @@ namespace floormat { enum class object_type : unsigned char { - none, character, scenery, light, + none, critter, scenery, light, }; constexpr inline size_t object_type_BITS = 3; diff --git a/test/serializer.cpp b/test/serializer.cpp index 20413afe..9387f827 100644 --- a/test/serializer.cpp +++ b/test/serializer.cpp @@ -2,7 +2,7 @@ #include "src/world.hpp" #include "loader/loader.hpp" #include "src/scenery.hpp" -#include "src/character.hpp" +#include "src/critter.hpp" #include "src/light.hpp" #include "src/tile-atlas.hpp" #include "src/anim-atlas.hpp" @@ -64,10 +64,10 @@ void assert_chunks_equal(const chunk& a, const chunk& b) fm_assert(ae.type() == be.type()); switch (ae.type()) { - case object_type::character: { - const auto& e1 = static_cast(ae); - const auto& e2 = static_cast(be); - const auto p1 = character_proto(e1), p2 = character_proto(e2); + case object_type::critter: { + const auto& e1 = static_cast(ae); + const auto& e2 = static_cast(be); + const auto p1 =critter_proto(e1), p2 =critter_proto(e2); fm_assert(p1 == p2); break; } -- cgit v1.2.3