From 1f83a019bf1c828a079606010f5e6fdec7786c93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Ferreira?= Date: Fri, 6 Jun 2025 12:09:07 +0100 Subject: [PATCH 1/4] feat: add Floating Platform object to Supertux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Floating Platform has the following characteristics: - Floats on top of water - Has a wave-like motion on water - Reacts to Tux jumping on it with bubbles and a sound effect - If not placed on water, behaves like a normal object with normal gravity - Is placed slightly under water to simulate floating - If it has rocks on top, it sinks faster or slower based on the number of rocks - If it's sinking and the rocks are removed, it floats again This object was created from scratch. We designed the sprite, implemented the FloatingPlatform class, and added it to the Level Editor so players can place it in custom levels. Co-authored-by: Tomás Correia --- data/images/engine/editor/objects.stoi | 3 + .../objects/platforms/floating_platform.png | Bin 0 -> 3863 bytes .../platforms/floating_platform.sprite | 6 + src/object/floating_platform.cpp | 183 ++++++++++++++++++ src/object/floating_platform.hpp | 59 ++++++ src/supertux/flip_level_transformer.hpp | 1 + src/supertux/game_object_factory.cpp | 3 + 7 files changed, 255 insertions(+) create mode 100644 data/images/objects/platforms/floating_platform.png create mode 100644 data/images/objects/platforms/floating_platform.sprite create mode 100644 src/object/floating_platform.cpp create mode 100644 src/object/floating_platform.hpp diff --git a/data/images/engine/editor/objects.stoi b/data/images/engine/editor/objects.stoi index 3557c3ba543..77d471d9d88 100644 --- a/data/images/engine/editor/objects.stoi +++ b/data/images/engine/editor/objects.stoi @@ -342,6 +342,9 @@ (object (class "editor-comment") (icon "images/engine/editor/editor-comment.png")) + (object + (class "floating_platform") + (icon "images/objects/platforms/floating_platform.png")) ) (layers diff --git a/data/images/objects/platforms/floating_platform.png b/data/images/objects/platforms/floating_platform.png new file mode 100644 index 0000000000000000000000000000000000000000..f943f8665242a562b66f431f1435e40ef174f11a GIT binary patch literal 3863 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 Z{tw5BO{SrTO@06X002ovPDHLkV1kIzKfV9} literal 0 HcmV?d00001 diff --git a/data/images/objects/platforms/floating_platform.sprite b/data/images/objects/platforms/floating_platform.sprite new file mode 100644 index 00000000000..8fa09b8042c --- /dev/null +++ b/data/images/objects/platforms/floating_platform.sprite @@ -0,0 +1,6 @@ +(supertux-sprite + (action + (name "default") + (images "floating_platform.png") + ) +) diff --git a/src/object/floating_platform.cpp b/src/object/floating_platform.cpp new file mode 100644 index 00000000000..aab86cabe9b --- /dev/null +++ b/src/object/floating_platform.cpp @@ -0,0 +1,183 @@ +// SuperTux +// Copyright (C) 2006 Matthias Braun +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "object/floating_platform.hpp" +#include "badguy/crusher.hpp" +#include "object/player.hpp" +#include "object/rock.hpp" +#include "supertux/sector.hpp" +#include "supertux/tile.hpp" +#include "supertux/flip_level_transformer.hpp" +#include "object/rainsplash.hpp" +#include "audio/sound_manager.hpp" + +namespace { +const float GROUND_FRICTION = 0.1f; +const std::string SPLASH_SOUND = "sounds/splash.ogg"; +} + +FloatingPlatform::FloatingPlatform(const ReaderMapping& reader) : + MovingSprite(reader, "images/objects/platforms/floating_platform.sprite", LAYER_OBJECTS, COLGROUP_MOVING_STATIC), + m_physic(), + m_on_ground(false), + m_at_ceiling(false), + m_floating(false), + m_last_sector_gravity(1.f), + m_sink_offset(0), + m_player_offset(0), + m_player_on_platform(false) +{ + set_group(COLGROUP_MOVING_STATIC); + SoundManager::current()->preload(SPLASH_SOUND); +} + +void FloatingPlatform::update(float dt_sec) +{ + if (get_bbox().get_top() > Sector::get().get_height()) { + remove_me(); + return; + } + + + Rectf water_check_bbox = get_bbox(); + water_check_bbox.set_bottom(water_check_bbox.get_bottom() - 15.0f); // Expand downward + bool in_water = !Sector::get().is_free_of_tiles(water_check_bbox, true, Tile::WATER); + if(in_water) + m_floating = true; + + Vector movement; + if(!m_floating){ + movement = m_physic.get_movement(dt_sec) * + Vector(1.f, 1.f); + } else{ + movement = m_physic.get_movement(dt_sec) * + Vector(1.f, in_water ? -0.05f : 0.01f); + } + + if (m_sink_offset > 0) { + set_pos(get_pos() + Vector(0, m_sink_offset * dt_sec)); + + } + + if (m_player_offset > 0) { + set_pos(get_pos() + Vector(0, m_player_offset * dt_sec)); + set_pos(get_pos() + Vector(0, -m_player_offset * dt_sec)); + } + + const float sector_gravity = Sector::get().get_gravity(); + if (m_last_sector_gravity != sector_gravity) { + if ((sector_gravity < 0.0f && m_last_sector_gravity >= 0.0f) || + (sector_gravity >= 0.0f && m_last_sector_gravity < 0.0f)) { + m_on_ground = false; + m_at_ceiling = false; + } + m_last_sector_gravity = sector_gravity; + } + m_col.set_movement(movement); + +} + +void FloatingPlatform::collision_solid(const CollisionHit& hit) +{ + if (hit.top || hit.bottom) { + m_physic.set_velocity_y(0); + } + + if (hit.left || hit.right) { + float velx = m_physic.get_velocity_x(); + m_physic.set_velocity_x(-0.1f * velx); + } + + if (hit.bottom) { + if (!m_on_ground) { + m_physic.set_velocity_x(0); + } + m_on_ground = true; + } + + if (hit.top) { + m_at_ceiling = true; + } +} + +HitResponse FloatingPlatform::collision(MovingObject& other, const CollisionHit& hit) +{ + auto crusher = dynamic_cast(&other); + if (crusher) { + return FORCE_MOVE; + } + + auto badguy = dynamic_cast(&other); + if (badguy && hit.bottom && m_physic.get_velocity_y() > 200) { + if (badguy->get_group() != COLGROUP_TOUCHABLE) { + badguy->kill_fall(); + m_physic.set_velocity_y(0); + } + } + + Rectf rock_check_zone = get_bbox(); + rock_check_zone.set_bottom(rock_check_zone.get_top()); + rock_check_zone.set_top(rock_check_zone.get_top() - 100.0f); + + auto rock = dynamic_cast(&other); + if (rock && rock_check_zone.overlaps(other.get_bbox())) { + int number_rocks = Sector::get().get_object_count([this](const Rock& r) { + Rectf rock_zone = get_bbox(); + rock_zone.set_bottom(rock_zone.get_top()); + rock_zone.set_top(rock_zone.get_top() - 100.0f); + return rock_zone.overlaps(r.get_bbox()); + }); + const float sink_speed = 40.0f; + const float max_sink_depth = 15.0f * number_rocks; + + m_sink_offset = std::min(m_sink_offset + sink_speed, max_sink_depth); + m_physic.set_velocity_y(sink_speed * number_rocks); + } + + Rectf player_check_zone = get_bbox(); + player_check_zone.set_bottom(player_check_zone.get_top()); + player_check_zone.set_top(player_check_zone.get_top() - 10.0f); + + auto player = dynamic_cast(&other); + if (player && player_check_zone.overlaps(other.get_bbox()) && !m_player_on_platform){ + m_player_on_platform = true; + SoundManager::current()->play(SPLASH_SOUND, get_pos()); + const float sink_speed_player = 40.0f; + const float max_sink_depth_player = 200.0f; + for(int i = 0; i<10; i++){ + Sector::get().add(Vector(static_cast(get_x()- 5.f + (i*8.f)), static_cast(get_y()+11.f)), + true); + } + m_player_offset = std::min(m_player_offset + sink_speed_player, max_sink_depth_player); + m_physic.set_velocity_y(sink_speed_player); + } else if(!player_check_zone.overlaps(other.get_bbox())){ + m_player_on_platform = false; + } + return FORCE_MOVE; +} + +void FloatingPlatform::on_flip(float height) +{ + MovingSprite::on_flip(height); +} + +ObjectSettings FloatingPlatform::get_settings() +{ + ObjectSettings result = MovingSprite::get_settings(); + return result; +} + +/* EOF */ diff --git a/src/object/floating_platform.hpp b/src/object/floating_platform.hpp new file mode 100644 index 00000000000..cbbbe1fe739 --- /dev/null +++ b/src/object/floating_platform.hpp @@ -0,0 +1,59 @@ +// SuperTux +// Copyright (C) 2006 Matthias Braun +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef FLOATING_PLATFORM_HPP +#define FLOATING_PLATFORM_HPP + +#include "object/moving_sprite.hpp" +#include "supertux/physic.hpp" +#include "badguy/badguy.hpp" // Needed for BadGuy definition + +class FloatingPlatform final : public MovingSprite +{ +public: + FloatingPlatform(const ReaderMapping& reader); + + virtual void update(float dt_sec) override; + virtual void collision_solid(const CollisionHit& hit) override; + virtual HitResponse collision(MovingObject& other, const CollisionHit& hit) override; + + static std::string class_name() { return "floating_platform"; } + virtual std::string get_class_name() const override { return class_name(); } + static std::string display_name() { return _("Floating Platform"); } + virtual std::string get_display_name() const override { return display_name(); } + + virtual ObjectSettings get_settings() override; + virtual void on_flip(float height) override; + +private: + Physic m_physic; + bool m_on_ground; + bool m_at_ceiling; + bool m_floating; + float m_last_sector_gravity; + float m_sink_offset; + float m_max_sink_depth; + float m_player_offset; + int number_rocks; + bool m_player_on_platform; + + FloatingPlatform(const FloatingPlatform&) = delete; + FloatingPlatform& operator=(const FloatingPlatform&) = delete; +}; + +#endif + +/* EOF */ diff --git a/src/supertux/flip_level_transformer.hpp b/src/supertux/flip_level_transformer.hpp index 2aa329f9daf..5815da32006 100644 --- a/src/supertux/flip_level_transformer.hpp +++ b/src/supertux/flip_level_transformer.hpp @@ -26,6 +26,7 @@ class SpawnPoint; class MovingObject; class Flower; class Platform; +class FloatingPlatform; class Block; class Path; class Decal; diff --git a/src/supertux/game_object_factory.cpp b/src/supertux/game_object_factory.cpp index d625fe7b49c..dec203a372f 100644 --- a/src/supertux/game_object_factory.cpp +++ b/src/supertux/game_object_factory.cpp @@ -156,6 +156,7 @@ #include "worldmap/special_tile.hpp" #include "worldmap/sprite_change.hpp" #include "worldmap/teleporter.hpp" +#include "object/floating_platform.hpp" GameObjectFactory& GameObjectFactory::instance() @@ -271,6 +272,7 @@ GameObjectFactory::init_factories() add_factory("explosion", OBJ_PARAM_DISPENSABLE); add_factory("fallblock", OBJ_PARAM_DISPENSABLE); add_factory("firefly"); + add_factory("floating_platform"); add_factory("particles-ghosts"); add_factory("gradient"); add_factory("heavy-brick", OBJ_PARAM_DISPENSABLE); @@ -358,6 +360,7 @@ GameObjectFactory::register_objects(ssq::VM& vm) Dispenser::register_class(vm); DisplayEffect::register_class(vm); FloatingImage::register_class(vm); + FloatingPlatform::register_class(vm); Gradient::register_class(vm); LevelTime::register_class(vm); LitObject::register_class(vm); From 1b94302871ea2679ba92b6cff5f592d117c77884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Ferreira?= Date: Sat, 7 Jun 2025 14:14:46 +0100 Subject: [PATCH 2/4] Fix order includes and spaces --- src/object/floating_platform.cpp | 8 ++++---- src/supertux/game_object_factory.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/object/floating_platform.cpp b/src/object/floating_platform.cpp index aab86cabe9b..cc7e5d22030 100644 --- a/src/object/floating_platform.cpp +++ b/src/object/floating_platform.cpp @@ -55,11 +55,11 @@ void FloatingPlatform::update(float dt_sec) Rectf water_check_bbox = get_bbox(); water_check_bbox.set_bottom(water_check_bbox.get_bottom() - 15.0f); // Expand downward bool in_water = !Sector::get().is_free_of_tiles(water_check_bbox, true, Tile::WATER); - if(in_water) + if (in_water) m_floating = true; Vector movement; - if(!m_floating){ + if (!m_floating){ movement = m_physic.get_movement(dt_sec) * Vector(1.f, 1.f); } else{ @@ -157,13 +157,13 @@ HitResponse FloatingPlatform::collision(MovingObject& other, const CollisionHit& SoundManager::current()->play(SPLASH_SOUND, get_pos()); const float sink_speed_player = 40.0f; const float max_sink_depth_player = 200.0f; - for(int i = 0; i<10; i++){ + for (int i = 0; i<10; i++){ Sector::get().add(Vector(static_cast(get_x()- 5.f + (i*8.f)), static_cast(get_y()+11.f)), true); } m_player_offset = std::min(m_player_offset + sink_speed_player, max_sink_depth_player); m_physic.set_velocity_y(sink_speed_player); - } else if(!player_check_zone.overlaps(other.get_bbox())){ + } else if (!player_check_zone.overlaps(other.get_bbox())){ m_player_on_platform = false; } return FORCE_MOVE; diff --git a/src/supertux/game_object_factory.cpp b/src/supertux/game_object_factory.cpp index dec203a372f..5b9ba1b47e3 100644 --- a/src/supertux/game_object_factory.cpp +++ b/src/supertux/game_object_factory.cpp @@ -103,6 +103,7 @@ #include "object/fallblock.hpp" #include "object/firefly.hpp" #include "object/floating_image.hpp" +#include "object/floating_platform.hpp" #include "object/ghost_particle_system.hpp" #include "object/gradient.hpp" #include "object/hurting_platform.hpp" @@ -156,7 +157,6 @@ #include "worldmap/special_tile.hpp" #include "worldmap/sprite_change.hpp" #include "worldmap/teleporter.hpp" -#include "object/floating_platform.hpp" GameObjectFactory& GameObjectFactory::instance() From b577a69916b352e52fd8257d0b2f6ac94e0f0031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Ferreira?= Date: Sun, 8 Jun 2025 16:18:05 +0100 Subject: [PATCH 3/4] Fix spaces --- src/object/floating_platform.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/object/floating_platform.cpp b/src/object/floating_platform.cpp index cc7e5d22030..433b22805d3 100644 --- a/src/object/floating_platform.cpp +++ b/src/object/floating_platform.cpp @@ -59,7 +59,7 @@ void FloatingPlatform::update(float dt_sec) m_floating = true; Vector movement; - if (!m_floating){ + if (!m_floating) { movement = m_physic.get_movement(dt_sec) * Vector(1.f, 1.f); } else{ @@ -157,13 +157,13 @@ HitResponse FloatingPlatform::collision(MovingObject& other, const CollisionHit& SoundManager::current()->play(SPLASH_SOUND, get_pos()); const float sink_speed_player = 40.0f; const float max_sink_depth_player = 200.0f; - for (int i = 0; i<10; i++){ + for (int i = 0; i<10; i++) { Sector::get().add(Vector(static_cast(get_x()- 5.f + (i*8.f)), static_cast(get_y()+11.f)), true); } m_player_offset = std::min(m_player_offset + sink_speed_player, max_sink_depth_player); m_physic.set_velocity_y(sink_speed_player); - } else if (!player_check_zone.overlaps(other.get_bbox())){ + } else if (!player_check_zone.overlaps(other.get_bbox())) { m_player_on_platform = false; } return FORCE_MOVE; From ccc47e1391bb09717d17a657a1c968e12107615a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Ferreira?= Date: Tue, 1 Jul 2025 16:07:33 +0100 Subject: [PATCH 4/4] Fix Sprite and splashes --- data/images/engine/editor/objects.stoi | 2 +- src/object/floating_platform.cpp | 59 ++++++++++++-------------- src/object/floating_platform.hpp | 6 +-- 3 files changed, 32 insertions(+), 35 deletions(-) diff --git a/data/images/engine/editor/objects.stoi b/data/images/engine/editor/objects.stoi index 77d471d9d88..6809bb5df2c 100644 --- a/data/images/engine/editor/objects.stoi +++ b/data/images/engine/editor/objects.stoi @@ -344,7 +344,7 @@ (icon "images/engine/editor/editor-comment.png")) (object (class "floating_platform") - (icon "images/objects/platforms/floating_platform.png")) + (icon "images/objects/platforms/icefloe_small.png")) ) (layers diff --git a/src/object/floating_platform.cpp b/src/object/floating_platform.cpp index 433b22805d3..1cab80db544 100644 --- a/src/object/floating_platform.cpp +++ b/src/object/floating_platform.cpp @@ -24,13 +24,11 @@ #include "object/rainsplash.hpp" #include "audio/sound_manager.hpp" -namespace { -const float GROUND_FRICTION = 0.1f; -const std::string SPLASH_SOUND = "sounds/splash.ogg"; -} - +constexpr float GROUND_FRICTION = 0.1f; +const float sink_speed = 40.0f; +static const std::string SPLASH_SOUND = "sounds/splash.ogg"; FloatingPlatform::FloatingPlatform(const ReaderMapping& reader) : - MovingSprite(reader, "images/objects/platforms/floating_platform.sprite", LAYER_OBJECTS, COLGROUP_MOVING_STATIC), + MovingSprite(reader, "images/objects/platforms/icefloe_small.sprite", LAYER_OBJECTS, COLGROUP_MOVING_STATIC), m_physic(), m_on_ground(false), m_at_ceiling(false), @@ -44,16 +42,14 @@ FloatingPlatform::FloatingPlatform(const ReaderMapping& reader) : SoundManager::current()->preload(SPLASH_SOUND); } -void FloatingPlatform::update(float dt_sec) +void +FloatingPlatform::update(float dt_sec) { - if (get_bbox().get_top() > Sector::get().get_height()) { + if (get_bbox().get_top() > Sector::get().get_height()) remove_me(); - return; - } - Rectf water_check_bbox = get_bbox(); - water_check_bbox.set_bottom(water_check_bbox.get_bottom() - 15.0f); // Expand downward + water_check_bbox.set_bottom(water_check_bbox.get_bottom() - 30.0f); // Expand downward bool in_water = !Sector::get().is_free_of_tiles(water_check_bbox, true, Tile::WATER); if (in_water) m_floating = true; @@ -69,12 +65,6 @@ void FloatingPlatform::update(float dt_sec) if (m_sink_offset > 0) { set_pos(get_pos() + Vector(0, m_sink_offset * dt_sec)); - - } - - if (m_player_offset > 0) { - set_pos(get_pos() + Vector(0, m_player_offset * dt_sec)); - set_pos(get_pos() + Vector(0, -m_player_offset * dt_sec)); } const float sector_gravity = Sector::get().get_gravity(); @@ -87,18 +77,18 @@ void FloatingPlatform::update(float dt_sec) m_last_sector_gravity = sector_gravity; } m_col.set_movement(movement); - } -void FloatingPlatform::collision_solid(const CollisionHit& hit) +void +FloatingPlatform::collision_solid(const CollisionHit& hit) { if (hit.top || hit.bottom) { m_physic.set_velocity_y(0); } if (hit.left || hit.right) { - float velx = m_physic.get_velocity_x(); - m_physic.set_velocity_x(-0.1f * velx); + const float vel_x = m_physic.get_velocity_x(); + m_physic.set_velocity_x(-0.1f * vel_x); } if (hit.bottom) { @@ -113,7 +103,8 @@ void FloatingPlatform::collision_solid(const CollisionHit& hit) } } -HitResponse FloatingPlatform::collision(MovingObject& other, const CollisionHit& hit) +HitResponse +FloatingPlatform::collision(MovingObject& other, const CollisionHit& hit) { auto crusher = dynamic_cast(&other); if (crusher) { @@ -133,18 +124,17 @@ HitResponse FloatingPlatform::collision(MovingObject& other, const CollisionHit& rock_check_zone.set_top(rock_check_zone.get_top() - 100.0f); auto rock = dynamic_cast(&other); - if (rock && rock_check_zone.overlaps(other.get_bbox())) { - int number_rocks = Sector::get().get_object_count([this](const Rock& r) { + if (rock) { + m_number_rocks = Sector::get().get_object_count([this](const Rock& r) { Rectf rock_zone = get_bbox(); rock_zone.set_bottom(rock_zone.get_top()); rock_zone.set_top(rock_zone.get_top() - 100.0f); return rock_zone.overlaps(r.get_bbox()); }); - const float sink_speed = 40.0f; - const float max_sink_depth = 15.0f * number_rocks; + const float max_sink_depth = 15.0f * static_cast(m_number_rocks); m_sink_offset = std::min(m_sink_offset + sink_speed, max_sink_depth); - m_physic.set_velocity_y(sink_speed * number_rocks); + m_physic.set_velocity_y(sink_speed * static_cast(m_number_rocks)); } Rectf player_check_zone = get_bbox(); @@ -157,9 +147,16 @@ HitResponse FloatingPlatform::collision(MovingObject& other, const CollisionHit& SoundManager::current()->play(SPLASH_SOUND, get_pos()); const float sink_speed_player = 40.0f; const float max_sink_depth_player = 200.0f; - for (int i = 0; i<10; i++) { - Sector::get().add(Vector(static_cast(get_x()- 5.f + (i*8.f)), static_cast(get_y()+11.f)), - true); + const int num_splashes = 20; + for (int i = 0; i < num_splashes; i++) { + // Distribute evenly from left to right + float x_pos = get_bbox().get_left() + (get_bbox().get_right() -get_bbox().get_left()) * + (static_cast(i) / (num_splashes - 1)); + + Sector::get().add( + Vector(x_pos, get_bbox().get_bottom()-40.f), + true + ); } m_player_offset = std::min(m_player_offset + sink_speed_player, max_sink_depth_player); m_physic.set_velocity_y(sink_speed_player); diff --git a/src/object/floating_platform.hpp b/src/object/floating_platform.hpp index cbbbe1fe739..be3db90a78b 100644 --- a/src/object/floating_platform.hpp +++ b/src/object/floating_platform.hpp @@ -19,7 +19,7 @@ #include "object/moving_sprite.hpp" #include "supertux/physic.hpp" -#include "badguy/badguy.hpp" // Needed for BadGuy definition +#include "badguy/badguy.hpp" class FloatingPlatform final : public MovingSprite { @@ -45,11 +45,11 @@ class FloatingPlatform final : public MovingSprite bool m_floating; float m_last_sector_gravity; float m_sink_offset; - float m_max_sink_depth; float m_player_offset; - int number_rocks; + float m_number_rocks; bool m_player_on_platform; + FloatingPlatform(const FloatingPlatform&) = delete; FloatingPlatform& operator=(const FloatingPlatform&) = delete; };