diff --git a/src/object/light.hpp b/src/object/light.hpp index 88ee82425f..bce1c582e6 100644 --- a/src/object/light.hpp +++ b/src/object/light.hpp @@ -36,6 +36,8 @@ class Light : public GameObject virtual void update(float dt_sec) override; virtual void draw(DrawingContext& context) override; + inline void move(const Vector& dist) { position += dist; } + protected: Vector position; Color color; diff --git a/src/object/tilemap.cpp b/src/object/tilemap.cpp index 1d13934d7a..8e22576cb4 100644 --- a/src/object/tilemap.cpp +++ b/src/object/tilemap.cpp @@ -22,10 +22,13 @@ #include #include "editor/editor.hpp" +#include "object/pulsing_light.hpp" #include "supertux/autotile.hpp" #include "supertux/debug.hpp" +#include "supertux/game_object_factory.hpp" #include "supertux/gameconfig.hpp" #include "supertux/globals.hpp" +#include "supertux/moving_object.hpp" #include "supertux/resources.hpp" #include "supertux/sector.hpp" #include "supertux/tile.hpp" @@ -54,6 +57,8 @@ TileMap::TileMap(const TileSet *new_tileset) : m_z_pos(0), m_offset(Vector(0,0)), m_movement(0, 0), + m_converted_objects(), + m_converted_lights(), m_objects_hit_bottom(), m_ground_movement_manager(nullptr), m_flip(NO_FLIP), @@ -88,6 +93,8 @@ TileMap::TileMap(const TileSet *tileset_, const ReaderMapping& reader) : m_z_pos(0), m_offset(Vector(0, 0)), m_movement(Vector(0, 0)), + m_converted_objects(), + m_converted_lights(), m_objects_hit_bottom(), m_ground_movement_manager(nullptr), m_flip(NO_FLIP), @@ -385,20 +392,44 @@ TileMap::update(float dt_sec) } // if we have a path to follow, follow it - if (get_walker()) { + if (get_walker()) + { m_movement = Vector(0, 0); get_walker()->update(dt_sec); Vector v = get_walker()->get_pos(get_size() * 32, m_path_handle); - if (get_path() && get_path()->is_valid()) { + if (get_path() && get_path()->is_valid()) + { m_movement = v - get_offset(); set_offset(v); - if (m_ground_movement_manager != nullptr) { - for (CollisionObject* other_object : m_objects_hit_bottom) { - m_ground_movement_manager->register_movement(*this, *other_object, m_movement); - other_object->propagate_movement(m_movement); + + if (m_movement != Vector(0, 0)) + { + if (m_ground_movement_manager != nullptr) + { + for (CollisionObject* other_object : m_objects_hit_bottom) + { + m_ground_movement_manager->register_movement(*this, *other_object, m_movement); + other_object->propagate_movement(m_movement); + } + } + + // Move all objects (including lights), converted from tiles in this tilemap + for (const UID& uid : m_converted_objects) + { + MovingObject* obj = get_parent()->get_object_by_uid(uid); + if (obj) + obj->move(m_movement); + } + for (const UID& uid : m_converted_lights) + { + Light* obj = get_parent()->get_object_by_uid(uid); + if (obj) + obj->move(m_movement); } } - } else { + } + else + { set_offset(m_path_handle.get_pos(get_size() * 32, Vector(0, 0))); } } @@ -987,6 +1018,77 @@ TileMap::set_tileset(const TileSet* new_tileset) m_tileset = new_tileset; } +void +TileMap::convert_tiles_to_objects() +{ + // Since object setup is not yet complete, we have to manually add the offset. + // See https://github.com/SuperTux/supertux/issues/1378 for details. + const Path* path = get_path(); + const Vector offset = path ? path->get_base() : Vector(0.f, 0.f); + + for (int x = 0; x < m_width; ++x) + { + for (int y = 0; y < m_height; ++y) + { + const Tile& tile = get_tile(x, y); + + if (!tile.get_object_name().empty()) + { + // If a tile is associated with an object, insert that + // object and remove the tile. + if (is_solid() || tile.get_object_name() == "decal") + { + const Vector pos = get_tile_position(x, y) + offset; + try + { + GameObject& obj = get_parent()->add_object(GameObjectFactory::instance().create(tile.get_object_name(), pos, Direction::AUTO, tile.get_object_data())); + if (dynamic_cast(&obj)) + m_converted_objects.push_back(obj.get_uid()); + + m_tiles[y*m_width + x] = 0; + } + catch (const std::exception& err) + { + log_warning << "Error converting tile to object: " << err.what() << std::endl; + } + } + } + else + { + // Add lights for fire tiles + const uint32_t attributes = tile.get_attributes(); + if (attributes & Tile::FIRE) + { + const Vector pos = get_tile_position(x, y) + offset; + const Vector center = pos + Vector(16.f, 16.f); + + if (attributes & Tile::HURTS) + { + // Lava or lavaflow + // Space lights a bit + if ((get_tile(x - 1, y).get_attributes() != attributes || x % 3 == 0) && + (get_tile(x, y - 1).get_attributes() != attributes || y % 3 == 0)) + { + float pseudo_rnd = static_cast(static_cast(pos.x) % 10) / 10; + GameObject& obj = get_parent()->add(center, 1.0f + pseudo_rnd, 0.8f, 1.0f, + (Color(1.0f, 0.3f, 0.0f, 1.0f) * m_current_tint).validate()); + m_converted_lights.push_back(obj.get_uid()); + } + } + else + { + // Torch + const float pseudo_rnd = static_cast(static_cast(pos.x) % 10) / 10; + GameObject& obj = get_parent()->add(center, 1.0f + pseudo_rnd, 0.9f, 1.0f, + (Color(1.0f, 1.0f, 0.6f, 1.0f) * m_current_tint).validate()); + m_converted_lights.push_back(obj.get_uid()); + } + } + } + } + } +} + void TileMap::register_class(ssq::VM& vm) diff --git a/src/object/tilemap.hpp b/src/object/tilemap.hpp index 3922f1ced1..b0bac01df7 100644 --- a/src/object/tilemap.hpp +++ b/src/object/tilemap.hpp @@ -266,6 +266,10 @@ class TileMap final : public GameObject, const std::vector& get_tiles() const { return m_tiles; } + /** Convert tiles into their corresponding GameObjects (e.g. + bonusblocks, add light to lava tiles). */ + void convert_tiles_to_objects(); + private: void update_effective_solid(bool update_manager = true); void float_channel(float target, float ¤t, float remaining_time, float dt_sec); @@ -321,6 +325,11 @@ class TileMap final : public GameObject, Vector m_offset; Vector m_movement; /**< The movement that happened last frame */ + /** UIDs of MovingObjects and Lights, which have been created from tiles in this tilemap. + Will be moved together with this tilemap. */ + std::vector m_converted_objects; + std::vector m_converted_lights; + /** Objects that were touching the top of a solid tile at the last frame */ std::unordered_set m_objects_hit_bottom; diff --git a/src/supertux/sector.cpp b/src/supertux/sector.cpp index 023812f4d9..f55231c2de 100644 --- a/src/supertux/sector.cpp +++ b/src/supertux/sector.cpp @@ -37,7 +37,6 @@ #include "object/music_object.hpp" #include "object/player.hpp" #include "object/portable.hpp" -#include "object/pulsing_light.hpp" #include "object/smoke_cloud.hpp" #include "object/spawnpoint.hpp" #include "object/text_array_object.hpp" @@ -49,7 +48,6 @@ #include "supertux/colorscheme.hpp" #include "supertux/constants.hpp" #include "supertux/debug.hpp" -#include "supertux/game_object_factory.hpp" #include "supertux/level.hpp" #include "supertux/player_status_hud.hpp" #include "supertux/resources.hpp" @@ -102,8 +100,10 @@ Sector::finish_construction(bool editable) // but I don't know if it's going to introduce other bugs.. ~ Semphris try_process_resolve_requests(); - if (!editable) { - convert_tiles2gameobject(); + if (!editable) + { + for (auto& tm : get_objects_by_type()) + tm.convert_tiles_to_objects(); if (!m_level.is_worldmap()) { @@ -819,69 +819,6 @@ Sector::save(Writer &writer) writer.end_list("sector"); } -void -Sector::convert_tiles2gameobject() -{ - // add lights for special tiles - for (auto& tm : get_objects_by_type()) - { - // Since object setup is not yet complete, I have to manually add the offset - // See https://github.com/SuperTux/supertux/issues/1378 for details - Vector tm_offset = tm.get_path() ? tm.get_path()->get_base() : Vector(0, 0); - - for (int x=0; x < tm.get_width(); ++x) - { - for (int y=0; y < tm.get_height(); ++y) - { - const Tile& tile = tm.get_tile(x, y); - - if (!tile.get_object_name().empty()) - { - // If a tile is associated with an object, insert that - // object and remove the tile - if (tile.get_object_name() == "decal" || - tm.is_solid()) - { - Vector pos = tm.get_tile_position(x, y) + tm_offset; - try { - auto object = GameObjectFactory::instance().create(tile.get_object_name(), pos, Direction::AUTO, tile.get_object_data()); - add_object(std::move(object)); - tm.change(x, y, 0); - } catch(std::exception& e) { - log_warning << e.what() << "" << std::endl; - } - } - } - else - { - // add lights for fire tiles - uint32_t attributes = tile.get_attributes(); - Vector pos = tm.get_tile_position(x, y) + tm_offset; - Vector center = pos + Vector(16, 16); - - if (attributes & Tile::FIRE) { - if (attributes & Tile::HURTS) { - // lava or lavaflow - // space lights a bit - if ((tm.get_tile(x-1, y).get_attributes() != attributes || x%3 == 0) - && (tm.get_tile(x, y-1).get_attributes() != attributes || y%3 == 0)) { - float pseudo_rnd = static_cast(static_cast(pos.x) % 10) / 10; - add(center, 1.0f + pseudo_rnd, 0.8f, 1.0f, - (Color(1.0f, 0.3f, 0.0f, 1.0f) * tm.get_current_tint()).validate()); - } - } else { - // torch - float pseudo_rnd = static_cast(static_cast(pos.x) % 10) / 10; - add(center, 1.0f + pseudo_rnd, 0.9f, 1.0f, - (Color(1.0f, 1.0f, 0.6f, 1.0f) * tm.get_current_tint()).validate()); - } - } - } - } - } - } -} - Camera& Sector::get_camera() const { diff --git a/src/supertux/sector.hpp b/src/supertux/sector.hpp index e5208f9944..fd023eaf76 100644 --- a/src/supertux/sector.hpp +++ b/src/supertux/sector.hpp @@ -233,10 +233,6 @@ class Sector final : public Base::Sector int calculate_foremost_layer(bool including_transparent = true) const; - /** Convert tiles into their corresponding GameObjects (e.g. - bonusblocks, add light to lava tiles) */ - void convert_tiles2gameobject(); - SpawnPointMarker* get_spawn_point(const std::string& spawnpoint); private: