Skip to content

Commit

Permalink
Moving converted objects from tiles with tilemap
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Vankata453 committed Apr 29, 2024
1 parent c6b1a95 commit 342b0f7
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 78 deletions.
106 changes: 99 additions & 7 deletions src/object/tilemap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@
#include <simplesquirrel/vm.hpp>

#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"
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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<MovingObject>(uid);
if (obj)
obj->move(m_movement);
}
}
} else {
}
else
{
set_offset(m_path_handle.get_pos(get_size() * 32, Vector(0, 0)));
}
}
Expand Down Expand Up @@ -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<MovingObject*>(&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<float>(static_cast<int>(pos.x) % 10) / 10;
get_parent()->add<PulsingLight>(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<float>(static_cast<int>(pos.x) % 10) / 10;
get_parent()->add<PulsingLight>(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)
Expand Down
8 changes: 8 additions & 0 deletions src/object/tilemap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,10 @@ class TileMap final : public GameObject,

const std::vector<uint32_t>& 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 &current, float remaining_time, float dt_sec);
Expand Down Expand Up @@ -299,6 +303,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<UID> m_converted_objects;

/** Objects that were touching the top of a solid tile at the last frame */
std::unordered_set<CollisionObject*> m_objects_hit_bottom;

Expand Down
71 changes: 4 additions & 67 deletions src/supertux/sector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand Down Expand Up @@ -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<TileMap>())
tm.convert_tiles_to_objects();

if (!m_level.is_worldmap())
{
Expand Down Expand Up @@ -790,69 +790,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<TileMap>())
{
// 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<float>(static_cast<int>(pos.x) % 10) / 10;
add<PulsingLight>(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<float>(static_cast<int>(pos.x) % 10) / 10;
add<PulsingLight>(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
{
Expand Down
4 changes: 0 additions & 4 deletions src/supertux/sector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,10 +230,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:
Expand Down

0 comments on commit 342b0f7

Please sign in to comment.