From a2cb7a9e820b8deb81e1e4a8aaa9edfc094073c3 Mon Sep 17 00:00:00 2001 From: Vankata453 <78196474+Vankata453@users.noreply.github.com> Date: Mon, 29 Apr 2024 19:01:50 +0300 Subject: [PATCH 1/2] Moving converted objects from tiles with tilemap When a `TileMap` is moving on a set path, any objects that have been converted from tiles in it, are now moved together with it as well. --- src/object/tilemap.cpp | 106 +++++++++++++++++++++++++++++++++++++--- src/object/tilemap.hpp | 8 +++ src/supertux/sector.cpp | 71 ++------------------------- src/supertux/sector.hpp | 4 -- 4 files changed, 111 insertions(+), 78 deletions(-) diff --git a/src/object/tilemap.cpp b/src/object/tilemap.cpp index 422474fc05e..3c73678ae44 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,7 @@ TileMap::TileMap(const TileSet *new_tileset) : m_z_pos(0), m_offset(Vector(0,0)), m_movement(0, 0), + m_converted_objects(), m_objects_hit_bottom(), m_ground_movement_manager(nullptr), m_flip(NO_FLIP), @@ -88,6 +92,7 @@ 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_objects_hit_bottom(), m_ground_movement_manager(nullptr), m_flip(NO_FLIP), @@ -371,20 +376,38 @@ 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, 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); } } - } else { + } + else + { set_offset(m_path_handle.get_pos(get_size() * 32, Vector(0, 0))); } } @@ -968,6 +991,75 @@ 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()); + + change(x, y, 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; + 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()); + } + } + else + { + // Torch + float pseudo_rnd = static_cast(static_cast(pos.x) % 10) / 10; + 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()); + } + } + } + } + } +} + void TileMap::register_class(ssq::VM& vm) diff --git a/src/object/tilemap.hpp b/src/object/tilemap.hpp index 332b52c3ec2..d4aeccd89e2 100644 --- a/src/object/tilemap.hpp +++ b/src/object/tilemap.hpp @@ -269,6 +269,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); @@ -301,6 +305,10 @@ class TileMap final : public GameObject, Vector m_offset; Vector m_movement; /**< The movement that happened last frame */ + /** UIDs of MovingObjects, which have been converted from tiles in this tilemap. + Will be moved together with this tilemap. */ + std::vector m_converted_objects; + /** 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 592b769d6bd..bf1bef4762b 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()) { @@ -818,69 +818,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 bcc603f07c3..7674e4c3464 100644 --- a/src/supertux/sector.hpp +++ b/src/supertux/sector.hpp @@ -234,10 +234,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: From 1015deffd0351f514b01b8a535b2a04f90f8bf7d Mon Sep 17 00:00:00 2001 From: Vankata453 <78196474+Vankata453@users.noreply.github.com> Date: Mon, 25 Nov 2024 15:59:24 +0200 Subject: [PATCH 2/2] Move converted `Light`s from tiles with tilemap --- src/object/light.hpp | 2 ++ src/object/tilemap.cpp | 24 +++++++++++++++++------- src/object/tilemap.hpp | 3 ++- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/object/light.hpp b/src/object/light.hpp index 88ee82425f5..bce1c582e66 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 e3e241f63c7..8e22576cb4e 100644 --- a/src/object/tilemap.cpp +++ b/src/object/tilemap.cpp @@ -58,6 +58,7 @@ TileMap::TileMap(const TileSet *new_tileset) : 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), @@ -93,6 +94,7 @@ TileMap::TileMap(const TileSet *tileset_, const ReaderMapping& reader) : 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), @@ -411,13 +413,19 @@ TileMap::update(float dt_sec) } } - // Move all objects, converted from tiles in this tilemap + // 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 @@ -1037,7 +1045,7 @@ TileMap::convert_tiles_to_objects() if (dynamic_cast(&obj)) m_converted_objects.push_back(obj.get_uid()); - change(x, y, 0); + m_tiles[y*m_width + x] = 0; } catch (const std::exception& err) { @@ -1062,16 +1070,18 @@ TileMap::convert_tiles_to_objects() (get_tile(x, y - 1).get_attributes() != attributes || y % 3 == 0)) { float pseudo_rnd = static_cast(static_cast(pos.x) % 10) / 10; - 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()); + 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 - float pseudo_rnd = static_cast(static_cast(pos.x) % 10) / 10; - 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()); + 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()); } } } diff --git a/src/object/tilemap.hpp b/src/object/tilemap.hpp index ab04368b7bb..b0bac01df7d 100644 --- a/src/object/tilemap.hpp +++ b/src/object/tilemap.hpp @@ -325,9 +325,10 @@ class TileMap final : public GameObject, Vector m_offset; Vector m_movement; /**< The movement that happened last frame */ - /** UIDs of MovingObjects, which have been converted from tiles in this tilemap. + /** 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;