From babcd01eaf15602ba32c6aa0354a0fd65f10e0d1 Mon Sep 17 00:00:00 2001 From: biggeryetbetter Date: Fri, 17 Nov 2023 17:43:01 -0600 Subject: [PATCH 01/18] Player no longer is slowed when working with wind Previously players were slowed down when moving in the same direction as wind when its velocity was particularly low. `add_wind_velocity` was ported from `Badguy` to the `Player` class to fix this. --- src/object/player.cpp | 16 ++++++++++++++++ src/object/player.hpp | 3 +++ src/object/wind.cpp | 6 +++--- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/object/player.cpp b/src/object/player.cpp index 751938e4b2a..ae9ebf21bbe 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -2880,4 +2880,20 @@ Player::remove_collected_key(Key* key) m_collected_keys.end()); } +void +Player::add_wind_velocity(const Vector& velocity, const Vector& end_speed) +{ + // Only add velocity in the same direction as the wind. + if (end_speed.x > 0 && m_physic.get_velocity_x() < end_speed.x) + m_physic.set_velocity_x(std::min(m_physic.get_velocity_x() + velocity.x, end_speed.x)); + if (end_speed.x < 0 && m_physic.get_velocity_x() > end_speed.x) + m_physic.set_velocity_x(std::max(m_physic.get_velocity_x() + velocity.x, end_speed.x)); + if (end_speed.y > 0 && m_physic.get_velocity_y() < end_speed.y) + m_physic.set_velocity_y(std::min(m_physic.get_velocity_y() + velocity.y, end_speed.y)); + if (end_speed.y < 0 && m_physic.get_velocity_y() > end_speed.y) + m_physic.set_velocity_y(std::max(m_physic.get_velocity_y() + velocity.y, end_speed.y)); +} + + + /* EOF */ diff --git a/src/object/player.hpp b/src/object/player.hpp index 904eda8c918..3779e8f5985 100644 --- a/src/object/player.hpp +++ b/src/object/player.hpp @@ -164,6 +164,9 @@ class Player final : public MovingObject, /** Adds velocity to the player until given end speed is reached */ void add_velocity(const Vector& velocity, const Vector& end_speed); + /** Version of `add_velocity` with modifications for wind physics */ + void add_wind_velocity(const Vector& velocity, const Vector& end_speed); + /** Returns the current velocity of the player */ Vector get_velocity() const; diff --git a/src/object/wind.cpp b/src/object/wind.cpp index 1a5d5da7ec8..9314fb36f82 100644 --- a/src/object/wind.cpp +++ b/src/object/wind.cpp @@ -136,18 +136,18 @@ Wind::collision(GameObject& other, const CollisionHit& ) player->override_velocity(); if (!player->on_ground()) { - player->add_velocity(speed * acceleration * dt_sec, speed); + player->add_wind_velocity(speed * acceleration * dt_sec, speed); } else { if (player->get_controller().hold(Control::RIGHT) || player->get_controller().hold(Control::LEFT)) { - player->add_velocity(Vector(speed.x, 0) * acceleration * dt_sec, speed); + player->add_wind_velocity(Vector(speed.x, 0) * acceleration * dt_sec, speed); } else { //When on ground, get blown slightly differently, but the max speed is less than it would be otherwise seen as we take "friction" into account - player->add_velocity((Vector(speed.x, 0) * 0.1f) * (acceleration+1), (Vector(speed.x, speed.y) * 0.5f)); + player->add_wind_velocity((Vector(speed.x, 0) * 0.1f) * (acceleration+1), (Vector(speed.x, speed.y) * 0.5f)); } } } From b6c89ce1851c4ef70e55926f18b082379290d61e Mon Sep 17 00:00:00 2001 From: biggeryetbetter Date: Fri, 15 Dec 2023 12:55:40 -0600 Subject: [PATCH 02/18] Most flying enemies interact correctly with wind * Darts, kamikaze snowballs and owls stop moving vertically after exiting wind * Zeeklings abort a dive if they are stopped by strong enough wind. For Flying Snowballs: * Velocity is now calculated based on the previous target height to avoid snapping when pushed away from their start position * They can be pushed upwards or downwards * When pushed sideways, damping keeps them from floating away forever --- src/badguy/dart.cpp | 4 ++++ src/badguy/flyingsnowball.cpp | 24 ++++++++++++++++-------- src/badguy/flyingsnowball.hpp | 1 + src/badguy/kamikazesnowball.cpp | 9 +++++++++ src/badguy/kamikazesnowball.hpp | 1 + src/badguy/owl.cpp | 2 ++ src/badguy/zeekling.cpp | 6 ++++++ 7 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/badguy/dart.cpp b/src/badguy/dart.cpp index c694312dcab..2c06c0b3272 100644 --- a/src/badguy/dart.cpp +++ b/src/badguy/dart.cpp @@ -96,6 +96,10 @@ void Dart::active_update(float dt_sec) { BadGuy::active_update(dt_sec); + + m_physic.set_velocity_y(m_physic.get_velocity_y() * 0.9f); + m_col.set_movement(m_physic.get_movement(dt_sec)); + sound_source->set_position(get_pos()); } diff --git a/src/badguy/flyingsnowball.cpp b/src/badguy/flyingsnowball.cpp index 01ae164b0e1..85302095275 100644 --- a/src/badguy/flyingsnowball.cpp +++ b/src/badguy/flyingsnowball.cpp @@ -32,6 +32,7 @@ const float GLOBAL_SPEED_MULT = 0.8f; /**< The overall movement speed/rate. */ FlyingSnowBall::FlyingSnowBall(const ReaderMapping& reader) : BadGuy(reader, "images/creatures/flying_snowball/flying_snowball.sprite"), total_time_elapsed(), + prev_height(0.f), puff_timer() { m_physic.enable_gravity(false); @@ -77,14 +78,21 @@ FlyingSnowBall::active_update(float dt_sec) // Put that function in a graphing calculator : // sin(x)^3 + sin(3(x - pi/3))/3 - float targetHgt = std::pow(std::sin(delta), 3.f) + - std::sin(3.f * - ((delta - math::PI) / 3.f) - ) / 3.f; - targetHgt = targetHgt * 100.f + m_start_position.y; - m_physic.set_velocity_y(targetHgt - get_pos().y); - - m_col.set_movement(m_physic.get_movement(1.f)); + float targetHgt = ( + std::pow(std::sin(delta), 3.f) + + std::sin(3.f * + ((delta - math::PI) / 3.f) + ) / 3.f + ) * 100.f; + + m_physic.set_velocity_y(m_physic.get_velocity_y() + (targetHgt - prev_height) / dt_sec); + prev_height = targetHgt; + + m_physic.set_velocity_x(m_physic.get_velocity_x() * pow(0.5f, dt_sec)); + + m_col.set_movement(m_physic.get_movement(dt_sec)); + + m_physic.set_velocity_y(0.f); auto player = get_nearest_player(); if (player) { diff --git a/src/badguy/flyingsnowball.hpp b/src/badguy/flyingsnowball.hpp index 6665ce29ab6..d9f84911bd5 100644 --- a/src/badguy/flyingsnowball.hpp +++ b/src/badguy/flyingsnowball.hpp @@ -40,6 +40,7 @@ class FlyingSnowBall final : public BadGuy private: float total_time_elapsed; + float prev_height; Timer puff_timer; /**< time until the next smoke puff is spawned */ private: diff --git a/src/badguy/kamikazesnowball.cpp b/src/badguy/kamikazesnowball.cpp index f2ee43ed622..1b7f60b3c03 100644 --- a/src/badguy/kamikazesnowball.cpp +++ b/src/badguy/kamikazesnowball.cpp @@ -17,6 +17,7 @@ #include "badguy/kamikazesnowball.hpp" #include "audio/sound_manager.hpp" +#include "supertux/direction.hpp" namespace{ static const float KAMIKAZE_SPEED = 200; @@ -39,6 +40,14 @@ KamikazeSnowball::initialize() set_action(m_dir); } +void +KamikazeSnowball::active_update(float dt_sec) { + m_physic.set_velocity_y(m_physic.get_velocity_y() * 0.9f); + m_col.set_movement(m_physic.get_movement(dt_sec)); + + BadGuy::active_update(dt_sec); +} + bool KamikazeSnowball::collision_squished(GameObject& object) { diff --git a/src/badguy/kamikazesnowball.hpp b/src/badguy/kamikazesnowball.hpp index 42bc5555750..2c946229840 100644 --- a/src/badguy/kamikazesnowball.hpp +++ b/src/badguy/kamikazesnowball.hpp @@ -29,6 +29,7 @@ class KamikazeSnowball : public BadGuy virtual void initialize() override; virtual void collision_solid(const CollisionHit& hit) override; + virtual void active_update(float dt_sec) override; static std::string class_name() { return "kamikazesnowball"; } virtual std::string get_class_name() const override { return class_name(); } static std::string display_name() { return _("Snowshot"); } diff --git a/src/badguy/owl.cpp b/src/badguy/owl.cpp index 3a13b80e462..81e46b85409 100644 --- a/src/badguy/owl.cpp +++ b/src/badguy/owl.cpp @@ -102,6 +102,8 @@ Owl::is_above_player() const void Owl::active_update (float dt_sec) { + m_physic.set_velocity_y(m_physic.get_velocity_y() * 0.9f); + BadGuy::active_update (dt_sec); if (m_frozen) diff --git a/src/badguy/zeekling.cpp b/src/badguy/zeekling.cpp index 6b728f10f55..02c34518f78 100644 --- a/src/badguy/zeekling.cpp +++ b/src/badguy/zeekling.cpp @@ -184,6 +184,12 @@ Zeekling::active_update(float dt_sec) { BadGuy::active_update(dt_sec); return; } else if (state == DIVING) { + // Something took away our diving velocity so we should go back up. + if (m_physic.get_velocity_y() <= 0.0f) { + state = CLIMBING; + m_physic.set_velocity_y(-2*fabsf(m_physic.get_velocity_x())); + set_action(m_dir); + } BadGuy::active_update(dt_sec); return; } else if (state == CLIMBING) { From ff25649b7ffd45307d91ff38e9245c9aea8bdc13 Mon Sep 17 00:00:00 2001 From: biggeryetbetter Date: Fri, 23 Feb 2024 13:37:42 -0600 Subject: [PATCH 03/18] Current variant of wind and player fixes - "Current" variant of wind that blows bubbles and does not affect Dive Mines. - Players now have an `m_wind_velocity` variable that is applied only after calculating other player physics. This fixes several unwanted behaviors related to Tux and wind. --- src/object/player.cpp | 13 +++++++++---- src/object/player.hpp | 2 +- src/object/wind.cpp | 41 +++++++++++++++++++++++------------------ src/object/wind.hpp | 7 +++++++ 4 files changed, 40 insertions(+), 23 deletions(-) diff --git a/src/object/player.cpp b/src/object/player.cpp index ae9ebf21bbe..c5fb747cec4 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -24,6 +24,7 @@ #include "editor/editor.hpp" #include "math/util.hpp" #include "math/random.hpp" +#include "math/vector.hpp" #include "object/brick.hpp" #include "object/bullet.hpp" #include "object/camera.hpp" @@ -207,6 +208,7 @@ Player::Player(PlayerStatus& player_status, const std::string& name_, int player m_growing(false), m_backflip_timer(), m_physic(), + m_wind_velocity(), m_visible(true), m_grabbed_object(nullptr), m_grabbed_object_remove_listener(new GrabListener(*this)), @@ -1469,6 +1471,9 @@ Player::handle_input() /* Handle vertical movement: */ if (!m_stone && !m_swimming) handle_vertical_input(); + m_physic.set_velocity(m_physic.get_velocity() + m_wind_velocity); + m_wind_velocity = Vector(0.f, 0.f); + /* grabbing */ bool just_grabbed = try_grab(); @@ -2885,13 +2890,13 @@ Player::add_wind_velocity(const Vector& velocity, const Vector& end_speed) { // Only add velocity in the same direction as the wind. if (end_speed.x > 0 && m_physic.get_velocity_x() < end_speed.x) - m_physic.set_velocity_x(std::min(m_physic.get_velocity_x() + velocity.x, end_speed.x)); + m_wind_velocity.x = std::min(m_wind_velocity.x + velocity.x, end_speed.x); if (end_speed.x < 0 && m_physic.get_velocity_x() > end_speed.x) - m_physic.set_velocity_x(std::max(m_physic.get_velocity_x() + velocity.x, end_speed.x)); + m_wind_velocity.x = std::max(m_wind_velocity.x + velocity.x, end_speed.x); if (end_speed.y > 0 && m_physic.get_velocity_y() < end_speed.y) - m_physic.set_velocity_y(std::min(m_physic.get_velocity_y() + velocity.y, end_speed.y)); + m_wind_velocity.y = std::min(m_wind_velocity.y + velocity.y, end_speed.y); if (end_speed.y < 0 && m_physic.get_velocity_y() > end_speed.y) - m_physic.set_velocity_y(std::max(m_physic.get_velocity_y() + velocity.y, end_speed.y)); + m_wind_velocity.y = std::max(m_wind_velocity.y + velocity.y, end_speed.y); } diff --git a/src/object/player.hpp b/src/object/player.hpp index 3779e8f5985..3fd60444eae 100644 --- a/src/object/player.hpp +++ b/src/object/player.hpp @@ -371,7 +371,7 @@ class Player final : public MovingObject, Timer m_backflip_timer; Physic m_physic; - + Vector m_wind_velocity; bool m_visible; Portable* m_grabbed_object; diff --git a/src/object/wind.cpp b/src/object/wind.cpp index 9314fb36f82..63ba55fe43d 100644 --- a/src/object/wind.cpp +++ b/src/object/wind.cpp @@ -17,6 +17,7 @@ #include "object/wind.hpp" #include "badguy/badguy.hpp" +#include "badguy/dive_mine.hpp" #include "editor/editor.hpp" #include "math/random.hpp" #include "object/particles.hpp" @@ -25,6 +26,7 @@ #include "object/sprite_particle.hpp" #include "sprite/sprite.hpp" #include "sprite/sprite_manager.hpp" +#include "supertux/game_object.hpp" #include "supertux/sector.hpp" #include "util/reader_mapping.hpp" #include "video/drawing_context.hpp" @@ -43,6 +45,7 @@ Wind::Wind(const ReaderMapping& reader) : fancy_wind() { float w,h; + parse_type(reader); reader.get("x", m_col.m_bbox.get_left(), 0.0f); reader.get("y", m_col.m_bbox.get_top(), 0.0f); reader.get("width", w, 32.0f); @@ -89,6 +92,14 @@ Wind::get_settings() return result; } +GameObjectTypes +Wind::get_types() const { + return { + { "wind", _("Wind") }, + { "current", _("Current") } + }; +} + void Wind::update(float dt_sec_) { @@ -107,7 +118,14 @@ Wind::update(float dt_sec_) // emit a particle if (fancy_wind) { - Sector::get().add("images/particles/wind.sprite", (std::abs(speed.x) > std::abs(speed.y)) ? "default" : "flip", ppos, ANCHOR_MIDDLE, pspeed, Vector(0, 0), LAYER_BACKGROUNDTILES + 1); + switch (m_type) { + case WIND: // Normal wind + Sector::get().add("images/particles/wind.sprite", (std::abs(speed.x) > std::abs(speed.y)) ? "default" : "flip", ppos, ANCHOR_MIDDLE, pspeed, Vector(0, 0), LAYER_BACKGROUNDTILES + 1); + break; + case CURRENT: // Current variant + Sector::get().add("images/particles/water_piece1.sprite", (std::abs(speed.x) > std::abs(speed.y)) ? "default" : "flip", ppos, ANCHOR_MIDDLE, pspeed, Vector(0, 0), LAYER_BACKGROUNDTILES + 1); + break; + } } else { @@ -134,28 +152,15 @@ Wind::collision(GameObject& other, const CollisionHit& ) if (player && affects_player) { player->override_velocity(); - if (!player->on_ground()) - { - player->add_wind_velocity(speed * acceleration * dt_sec, speed); - } - else - { - if (player->get_controller().hold(Control::RIGHT) || player->get_controller().hold(Control::LEFT)) - { - player->add_wind_velocity(Vector(speed.x, 0) * acceleration * dt_sec, speed); - } - else - { - //When on ground, get blown slightly differently, but the max speed is less than it would be otherwise seen as we take "friction" into account - player->add_wind_velocity((Vector(speed.x, 0) * 0.1f) * (acceleration+1), (Vector(speed.x, speed.y) * 0.5f)); - } - } + player->add_wind_velocity(speed * acceleration * dt_sec, speed); } auto badguy = dynamic_cast(&other); if (badguy && affects_badguys && badguy->can_be_affected_by_wind()) { - badguy->add_wind_velocity(speed * acceleration * dt_sec, speed); + if (m_type == CURRENT && !dynamic_cast(&other)) { // Dive mines are not affected by currents + badguy->add_wind_velocity(speed * acceleration * dt_sec, speed); + } } auto rock = dynamic_cast(&other); diff --git a/src/object/wind.hpp b/src/object/wind.hpp index f9bdde1df96..d5a2e1bdf3e 100644 --- a/src/object/wind.hpp +++ b/src/object/wind.hpp @@ -44,6 +44,7 @@ class Wind final : virtual std::string get_display_name() const override { return display_name(); } virtual ObjectSettings get_settings() override; + virtual GameObjectTypes get_types() const override; virtual int get_layer() const override { return LAYER_OBJECTS; } @@ -60,6 +61,12 @@ class Wind final : /** @} */ +private: + enum Type { + WIND, + CURRENT, + }; + private: bool blowing; /**< true if wind is currently switched on */ Vector speed; From 5b404428a720cbd8b59be031352498f4c76a201a Mon Sep 17 00:00:00 2001 From: biggeryetbetter Date: Tue, 19 Mar 2024 11:20:57 -0500 Subject: [PATCH 04/18] Swimming physics redone to work better with wind Swimming now works on velocity rather than acceleration, which previously caused odd behavior with regard to swimming through wind. Further tweaking may be needed but should hopefully be easier to do. --- src/object/player.cpp | 77 +++++++++++++++++-------------------------- src/object/player.hpp | 3 +- src/object/wind.cpp | 2 +- 3 files changed, 33 insertions(+), 49 deletions(-) diff --git a/src/object/player.cpp b/src/object/player.cpp index c5fb747cec4..34d9fb69e2d 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -209,6 +209,7 @@ Player::Player(PlayerStatus& player_status, const std::string& name_, int player m_backflip_timer(), m_physic(), m_wind_velocity(), + m_wind_acceleration(), m_visible(true), m_grabbed_object(nullptr), m_grabbed_object_remove_listener(new GrabListener(*this)), @@ -918,68 +919,47 @@ Player::swim(float pointx, float pointy, bool boost) if (m_swimming && !m_water_jump) { + m_swimming_accel_modifier = is_ang_defined ? 1.f : 0.f; - if(is_ang_defined && std::abs(delta) < 0.01f) - m_swimming_angle = pointed_angle; + if (boost) { + m_swimming_accel_modifier = m_swimming_accel_modifier * SWIM_BOOST_SPEED; + m_swimboosting = true; + } + else + { + m_swimming_accel_modifier = m_swimming_accel_modifier * SWIM_SPEED; + if (glm::length(m_physic.get_velocity()) < SWIM_SPEED + 10.f) { + m_swimboosting = false; + } + } - m_swimming_accel_modifier = is_ang_defined ? 600.f : 0.f; - Vector swimming_direction = math::vec2_from_polar(m_swimming_accel_modifier, pointed_angle); + if (is_ang_defined) + { + if (std::abs(delta) < 0.01f) + m_swimming_angle = pointed_angle; - m_physic.set_acceleration_x((swimming_direction.x - 1.0f * vx) * 2.f); - m_physic.set_acceleration_y((swimming_direction.y - 1.0f * vy) * 2.f); + Vector swimming_direction = math::vec2_from_polar(m_swimming_accel_modifier, pointed_angle); + Vector diff = m_physic.get_velocity() - swimming_direction; + float diff_len = glm::length(diff); - // Limit speed, if you go above this speed your acceleration is set to opposite (?) - if (glm::length(m_physic.get_velocity()) > SWIM_SPEED) - { - m_physic.set_acceleration(-vx,-vy); // Was too lazy to set it properly ~~zwatotem + float accel_power = glm::length(m_wind_velocity) > 0.0f ? 1.f / m_wind_acceleration : 0.33f; + + m_physic.set_velocity_x(vx - (diff.x * pow(1.f/std::max(1.f, diff_len), accel_power))); + m_physic.set_velocity_y(vy - (diff.y * pow(1.f/std::max(1.f, diff_len), accel_power))); } // Natural friction if (!is_ang_defined) { - m_physic.set_acceleration(-3.f*vx, -3.f*vy); - } - - //not boosting? let's slow this penguin down!!! - if (!boost && is_ang_defined && glm::length(m_physic.get_velocity()) > (SWIM_SPEED + 10.f)) - { - m_physic.set_acceleration(-5.f*vx, -5.f*vy); + m_physic.set_velocity(vx * 0.95f, vy * 0.95f); } // Snapping to prevent unwanted floating - if (!is_ang_defined && glm::length(Vector(vx,vy)) < 100.f) + if (!is_ang_defined && glm::length(Vector(vx,vy)) < 100.f) { vx = 0; vy = 0; } - - // Turbo, using pointsign - float minboostspeed = 100.f; - if (boost && glm::length(m_physic.get_velocity()) > minboostspeed) - { - if (glm::length(m_physic.get_velocity()) < SWIM_BOOST_SPEED) - { - m_swimboosting = true; - if (is_ang_defined) - { - vx += SWIM_TO_BOOST_ACCEL * pointx; - vy += SWIM_TO_BOOST_ACCEL * pointy; - } - } - else - { - //cap on boosting - m_physic.set_acceleration(-vx, -vy); - } - m_physic.set_velocity(vx, vy); - } - else - { - if (glm::length(m_physic.get_velocity()) < (SWIM_SPEED + 10.f)) - { - m_swimboosting = false; - } - } } if (m_water_jump && !m_swimming) { @@ -1473,6 +1453,7 @@ Player::handle_input() m_physic.set_velocity(m_physic.get_velocity() + m_wind_velocity); m_wind_velocity = Vector(0.f, 0.f); + m_wind_acceleration = 0.0; /* grabbing */ bool just_grabbed = try_grab(); @@ -2886,8 +2867,10 @@ Player::remove_collected_key(Key* key) } void -Player::add_wind_velocity(const Vector& velocity, const Vector& end_speed) +Player::add_wind_velocity(const Vector& speed, const float acceleration, const Vector& end_speed) { + Vector velocity = speed * acceleration; + m_wind_acceleration = acceleration; // Only add velocity in the same direction as the wind. if (end_speed.x > 0 && m_physic.get_velocity_x() < end_speed.x) m_wind_velocity.x = std::min(m_wind_velocity.x + velocity.x, end_speed.x); diff --git a/src/object/player.hpp b/src/object/player.hpp index 3fd60444eae..683b519e308 100644 --- a/src/object/player.hpp +++ b/src/object/player.hpp @@ -165,7 +165,7 @@ class Player final : public MovingObject, void add_velocity(const Vector& velocity, const Vector& end_speed); /** Version of `add_velocity` with modifications for wind physics */ - void add_wind_velocity(const Vector& velocity, const Vector& end_speed); + void add_wind_velocity(const Vector& velocity, const float acceleration, const Vector& end_speed); /** Returns the current velocity of the player */ Vector get_velocity() const; @@ -372,6 +372,7 @@ class Player final : public MovingObject, Physic m_physic; Vector m_wind_velocity; + float m_wind_acceleration; bool m_visible; Portable* m_grabbed_object; diff --git a/src/object/wind.cpp b/src/object/wind.cpp index 63ba55fe43d..57e0554570c 100644 --- a/src/object/wind.cpp +++ b/src/object/wind.cpp @@ -152,7 +152,7 @@ Wind::collision(GameObject& other, const CollisionHit& ) if (player && affects_player) { player->override_velocity(); - player->add_wind_velocity(speed * acceleration * dt_sec, speed); + player->add_wind_velocity(speed * dt_sec, acceleration, speed); } auto badguy = dynamic_cast(&other); From e3f2392eb7d35353d768eebb5a3d5e013bd01cc3 Mon Sep 17 00:00:00 2001 From: biggeryetbetter Date: Tue, 26 Mar 2024 14:30:51 -0500 Subject: [PATCH 05/18] Fix friction causing issues with swimming The `apply_friction` function previously caused tux to swim constantly to one direction due to it adding acceleration under the assumption that tux was walking. Swimming-specific friction logic has also been moved to the function. --- src/object/player.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/object/player.cpp b/src/object/player.cpp index 34d9fb69e2d..4a3d9e3adb2 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -510,6 +510,7 @@ Player::update(float dt_sec) m_water_jump = false; m_swimming = true; m_swimming_angle = math::angle(Vector(m_physic.get_velocity_x(), m_physic.get_velocity_y())); + m_physic.set_acceleration(0.0f, 0.0f); if (is_big()) adjust_height(TUX_WIDTH); m_wants_buttjump = m_does_buttjump = m_backflipping = false; @@ -946,12 +947,8 @@ Player::swim(float pointx, float pointy, bool boost) m_physic.set_velocity_x(vx - (diff.x * pow(1.f/std::max(1.f, diff_len), accel_power))); m_physic.set_velocity_y(vy - (diff.y * pow(1.f/std::max(1.f, diff_len), accel_power))); - } - - // Natural friction - if (!is_ang_defined) - { - m_physic.set_velocity(vx * 0.95f, vy * 0.95f); + } else { + apply_friction(); } // Snapping to prevent unwanted floating @@ -985,7 +982,7 @@ Player::swim(float pointx, float pointy, bool boost) //Force the speed to point in the direction Tux is going unless Tux is being pushed by something else if (m_swimming && !m_water_jump && boost && m_boost == 0.f && !m_velocity_override) { - m_physic.set_velocity(math::at_angle(m_physic.get_velocity(), m_swimming_angle)); + // m_physic.set_velocity(math::at_angle(m_physic.get_velocity(), m_swimming_angle)); } } } @@ -1016,11 +1013,18 @@ Player::apply_friction() { bool is_on_ground = on_ground(); float velx = m_physic.get_velocity_x(); + float vely = m_physic.get_velocity_y(); if (is_on_ground && (fabsf(velx) < (m_stone ? 5.f : WALK_SPEED))) { m_physic.set_velocity_x(0); m_physic.set_acceleration_x(0); return; } + + if (m_swimming) { + m_physic.set_velocity(velx * 0.95f, vely * 0.95f); + return; + } + float friction = WALK_ACCELERATION_X; if (m_on_ice && is_on_ground) //we need this or else sliding on ice will cause Tux to go on for a very long time From 9915c5c9d76a12100182230dca9ee957c45adf64 Mon Sep 17 00:00:00 2001 From: biggeryetbetter Date: Thu, 28 Mar 2024 10:53:29 -0500 Subject: [PATCH 06/18] Add feathering to wind and fix logic error Wind now has a configurable variable that allows for feathering of the strength of wind. This is intended to make the transition into wind smoother. Fixed a logic error where all enemies would only be affected by current, not normal wind. --- src/object/wind.cpp | 31 +++++++++++++++++++++++++++---- src/object/wind.hpp | 4 ++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/object/wind.cpp b/src/object/wind.cpp index 57e0554570c..db2389d21b1 100644 --- a/src/object/wind.cpp +++ b/src/object/wind.cpp @@ -39,6 +39,7 @@ Wind::Wind(const ReaderMapping& reader) : acceleration(), new_size(0.0f, 0.0f), dt_sec(0), + feather_distance(0.f), affects_badguys(), affects_objects(), affects_player(), @@ -54,6 +55,7 @@ Wind::Wind(const ReaderMapping& reader) : reader.get("blowing", blowing, true); + reader.get("feather-distance", feather_distance, 16.f); reader.get("speed-x", speed.x, 0.0f); reader.get("speed-y", speed.y, 0.0f); @@ -81,13 +83,14 @@ Wind::get_settings() result.add_float(_("Speed X"), &speed.x, "speed-x"); result.add_float(_("Speed Y"), &speed.y, "speed-y"); result.add_float(_("Acceleration"), &acceleration, "acceleration"); + result.add_float(_("Feather Distance"), &feather_distance, "feather-distance"); result.add_bool(_("Blowing"), &blowing, "blowing", true); result.add_bool(_("Affects Badguys"), &affects_badguys, "affects-badguys", false); result.add_bool(_("Affects Objects"), &affects_objects, "affects-objects", false); result.add_bool(_("Affects Player"), &affects_player, "affects-player"); result.add_bool(_("Fancy Particles"), &fancy_wind, "fancy-wind", false); - result.reorder({"blowing", "speed-x", "speed-y", "acceleration", "affects-badguys", "affects-objects", "affects-player", "fancy-wind", "region", "name", "x", "y"}); + result.reorder({"blowing", "speed-x", "speed-y", "acceleration", "feather-distance", "affects-badguys", "affects-objects", "affects-player", "fancy-wind", "region", "name", "x", "y"}); return result; } @@ -152,21 +155,22 @@ Wind::collision(GameObject& other, const CollisionHit& ) if (player && affects_player) { player->override_velocity(); - player->add_wind_velocity(speed * dt_sec, acceleration, speed); + player->add_wind_velocity(speed * get_wind_strength(player->get_bbox().get_middle()) * dt_sec, acceleration, speed); } auto badguy = dynamic_cast(&other); if (badguy && affects_badguys && badguy->can_be_affected_by_wind()) { if (m_type == CURRENT && !dynamic_cast(&other)) { // Dive mines are not affected by currents - badguy->add_wind_velocity(speed * acceleration * dt_sec, speed); + return ABORT_MOVE; } + badguy->add_wind_velocity(speed * get_wind_strength(badguy->get_bbox().get_middle()) * acceleration * dt_sec, speed); } auto rock = dynamic_cast(&other); if (rock && affects_objects) { - rock->add_wind_velocity(speed * acceleration * dt_sec, speed); + rock->add_wind_velocity(speed * get_wind_strength(rock->get_bbox().get_middle()) * acceleration * dt_sec, speed); } return ABORT_MOVE; @@ -191,4 +195,23 @@ Wind::on_flip(float height) speed.y = -speed.y; } +float +Wind::get_wind_strength(Vector pos) { + // Point isn't inside the wind + if (!m_col.m_bbox.contains(pos)) + return 0.0; + + float strength = 1.0; + + + float dl = pos.x - m_col.m_bbox.get_left(); + float dr = m_col.m_bbox.get_right() - pos.x; + float dt = pos.y - m_col.m_bbox.get_top(); + float db = m_col.m_bbox.get_bottom() - pos.y; + + strength = std::clamp(std::min({dl, dr, dt, db}) / feather_distance, 0.f, 1.f); + + return strength; +} + /* EOF */ diff --git a/src/object/wind.hpp b/src/object/wind.hpp index d5a2e1bdf3e..42a66cc2eed 100644 --- a/src/object/wind.hpp +++ b/src/object/wind.hpp @@ -60,6 +60,9 @@ class Wind final : void stop(); /** @} */ +private: + /** Get the relative wind strength at a specific location */ + virtual float get_wind_strength(Vector pos); private: enum Type { @@ -74,6 +77,7 @@ class Wind final : Vector new_size; float dt_sec; /**< stores last dt_sec gotten at update() */ + float feather_distance; /**< the distance tux must go into the wind to experience full force */ bool affects_badguys; /**< whether the wind can affect badguys */ bool affects_objects; /**< whether the wind can affect objects */ From a50f5c320ac92eabb4edeb15e641a96d330c5d95 Mon Sep 17 00:00:00 2001 From: biggeryetbetter Date: Sun, 31 Mar 2024 13:26:20 -0500 Subject: [PATCH 07/18] Wind uses its own acceleration and Dive Mine fix Previously, acceleration was calculated completely incorrectly which resulted in excessively high accelerations within wind areas. Dive mines also no longer are pushed by wind. --- src/object/player.cpp | 10 +++++----- src/object/wind.cpp | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/object/player.cpp b/src/object/player.cpp index 4a3d9e3adb2..b80430e8c94 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -669,6 +669,10 @@ Player::update(float dt_sec) m_boost = 0.f; } + m_physic.set_velocity(m_physic.get_velocity() + m_wind_velocity); + m_wind_velocity = Vector(0.f, 0.f); + m_wind_acceleration = 0.0; + // calculate movement for this frame m_col.set_movement(m_physic.get_movement(dt_sec) + Vector(m_boost * dt_sec, 0)); @@ -1455,10 +1459,6 @@ Player::handle_input() /* Handle vertical movement: */ if (!m_stone && !m_swimming) handle_vertical_input(); - m_physic.set_velocity(m_physic.get_velocity() + m_wind_velocity); - m_wind_velocity = Vector(0.f, 0.f); - m_wind_acceleration = 0.0; - /* grabbing */ bool just_grabbed = try_grab(); @@ -2873,7 +2873,7 @@ Player::remove_collected_key(Key* key) void Player::add_wind_velocity(const Vector& speed, const float acceleration, const Vector& end_speed) { - Vector velocity = speed * acceleration; + Vector velocity = glm::normalize(end_speed) * acceleration; m_wind_acceleration = acceleration; // Only add velocity in the same direction as the wind. if (end_speed.x > 0 && m_physic.get_velocity_x() < end_speed.x) diff --git a/src/object/wind.cpp b/src/object/wind.cpp index db2389d21b1..91d30d82488 100644 --- a/src/object/wind.cpp +++ b/src/object/wind.cpp @@ -155,13 +155,13 @@ Wind::collision(GameObject& other, const CollisionHit& ) if (player && affects_player) { player->override_velocity(); - player->add_wind_velocity(speed * get_wind_strength(player->get_bbox().get_middle()) * dt_sec, acceleration, speed); + player->add_wind_velocity(speed, acceleration, speed * get_wind_strength(player->get_bbox().get_middle())); } auto badguy = dynamic_cast(&other); if (badguy && affects_badguys && badguy->can_be_affected_by_wind()) { - if (m_type == CURRENT && !dynamic_cast(&other)) { // Dive mines are not affected by currents + if (m_type == CURRENT && dynamic_cast(badguy)) { // Dive mines are not affected by currents return ABORT_MOVE; } badguy->add_wind_velocity(speed * get_wind_strength(badguy->get_bbox().get_middle()) * acceleration * dt_sec, speed); From 6e471d4c431deb39ada4d3351fdfeeee543b2b16 Mon Sep 17 00:00:00 2001 From: biggeryetbetter Date: Sun, 21 Apr 2024 10:42:26 -0500 Subject: [PATCH 08/18] Fix jittering in wind * `CollisionObject` now keeps track of colliding wind areas each frame * Wind now interpolates its applied velocity 50:50 each frame to prevent Tux from jittering * Tux will not skid constantly in wind * Tux has higher turning acceleration in wind to give him a bit more control --- src/collision/collision_object.cpp | 16 +++++++++++++++ src/collision/collision_object.hpp | 7 +++++++ src/collision/collision_system.cpp | 1 + src/object/player.cpp | 31 +++++++++++++++++++++--------- 4 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/collision/collision_object.cpp b/src/collision/collision_object.cpp index 80a4bac95c8..b75c7f78bc7 100644 --- a/src/collision/collision_object.cpp +++ b/src/collision/collision_object.cpp @@ -19,11 +19,13 @@ #include "collision/collision_listener.hpp" #include "collision/collision_movement_manager.hpp" +#include "object/wind.hpp" #include "supertux/game_object.hpp" CollisionObject::CollisionObject(CollisionGroup group, CollisionListener& listener) : m_listener(listener), m_bbox(), + m_colliding_wind(), m_group(group), m_movement(0.0f, 0.0f), m_dest(), @@ -48,6 +50,9 @@ CollisionObject::collides(CollisionObject& other, const CollisionHit& hit) const HitResponse CollisionObject::collision(CollisionObject& other, const CollisionHit& hit) { + if(dynamic_cast(&other.m_listener)) { + collide_wind(other); + } return m_listener.collision(dynamic_cast(other.m_listener), hit); } @@ -71,6 +76,17 @@ void CollisionObject::notify_object_removal(CollisionObject* other) { m_objects_hit_bottom.erase(other); + m_colliding_wind.erase(other); +} + +void +CollisionObject::collide_wind(CollisionObject& other) { + m_colliding_wind.insert(&other); +} + +void +CollisionObject::clear_wind_collision_list() { + m_colliding_wind.clear(); } void diff --git a/src/collision/collision_object.hpp b/src/collision/collision_object.hpp index 7f3041bd9ac..68dc5446e41 100644 --- a/src/collision/collision_object.hpp +++ b/src/collision/collision_object.hpp @@ -61,6 +61,10 @@ class CollisionObject m_ground_movement_manager = movement_manager; } + void collide_wind(CollisionObject& other); + + void clear_wind_collision_list(); + void clear_bottom_collision_list(); bool is_unisolid() const { return m_unisolid; } @@ -144,6 +148,9 @@ class CollisionObject this isn't necessarily the bounding box for graphics) */ Rectf m_bbox; + /** All wind areas that the player is currently touching */ + std::unordered_set m_colliding_wind; + /** The collision group */ CollisionGroup m_group; diff --git a/src/collision/collision_system.cpp b/src/collision/collision_system.cpp index ca51c89004e..bff5b413c47 100644 --- a/src/collision/collision_system.cpp +++ b/src/collision/collision_system.cpp @@ -558,6 +558,7 @@ CollisionSystem::update() object->m_dest = object->get_bbox(); object->m_dest.move(object->get_movement()); object->clear_bottom_collision_list(); + object->clear_wind_collision_list(); } // Part 1: COLGROUP_MOVING vs COLGROUP_STATIC and tilemap. diff --git a/src/object/player.cpp b/src/object/player.cpp index b80430e8c94..86a1663d0d2 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -372,6 +372,11 @@ Player::trigger_sequence(Sequence seq, const SequenceData* data) void Player::update(float dt_sec) { + if (m_col.m_colliding_wind.empty()) { + m_wind_velocity = Vector(0.f, 0.f); + m_wind_acceleration = 0.0; + } + if (is_dead() || Sector::get().get_object_count() == 1) { m_tag_timer.stop(); @@ -542,6 +547,8 @@ Player::update(float dt_sec) if (!m_dying && !m_deactivated) handle_input(); + if (!m_col.m_colliding_wind.empty()) + m_physic.set_velocity(m_physic.get_velocity() + m_wind_velocity); /* // handle_input() calls apply_friction() when Tux is not walking, so we'll have to do this ourselves if (deactivated) @@ -669,10 +676,6 @@ Player::update(float dt_sec) m_boost = 0.f; } - m_physic.set_velocity(m_physic.get_velocity() + m_wind_velocity); - m_wind_velocity = Vector(0.f, 0.f); - m_wind_acceleration = 0.0; - // calculate movement for this frame m_col.set_movement(m_physic.get_movement(dt_sec) + Vector(m_boost * dt_sec, 0)); @@ -1035,6 +1038,7 @@ Player::apply_friction() friction *= (ICE_FRICTION_MULTIPLIER*(m_sliding ? 4.f : m_stone ? 5.f : 1.f)); else friction *= (NORMAL_FRICTION_MULTIPLIER*(m_sliding ? 0.8f : m_stone ? 0.4f : 1.f)); + if (velx < 0) { m_physic.set_acceleration_x(friction); } else if (velx > 0) { @@ -1122,8 +1126,14 @@ Player::handle_horizontal_input() // changing directions? if ((vx < 0 && dirsign >0) || (vx>0 && dirsign<0)) { if (on_ground()) { + // Better acceleration in wind when we are on the ground + bool wind_control = false; + if (!m_col.m_colliding_wind.empty()) { + ax *= 3.f; + wind_control = true; + } // let's skid! - if (fabsf(vx)>SKID_XM && !m_skidding_timer.started()) { + if (fabsf(vx)>SKID_XM && !m_skidding_timer.started() && !wind_control) { m_skidding_timer.start(SKID_TIME); SoundManager::current()->play("sounds/skid.wav", get_pos()); // dust some particles @@ -2875,15 +2885,18 @@ Player::add_wind_velocity(const Vector& speed, const float acceleration, const V { Vector velocity = glm::normalize(end_speed) * acceleration; m_wind_acceleration = acceleration; + Vector end_velocity = Vector(0.f, 0.f); // Only add velocity in the same direction as the wind. if (end_speed.x > 0 && m_physic.get_velocity_x() < end_speed.x) - m_wind_velocity.x = std::min(m_wind_velocity.x + velocity.x, end_speed.x); + end_velocity.x = std::min(m_wind_velocity.x + velocity.x, end_speed.x); if (end_speed.x < 0 && m_physic.get_velocity_x() > end_speed.x) - m_wind_velocity.x = std::max(m_wind_velocity.x + velocity.x, end_speed.x); + end_velocity.x = std::max(m_wind_velocity.x + velocity.x, end_speed.x); if (end_speed.y > 0 && m_physic.get_velocity_y() < end_speed.y) - m_wind_velocity.y = std::min(m_wind_velocity.y + velocity.y, end_speed.y); + end_velocity.y = std::min(m_wind_velocity.y + velocity.y, end_speed.y); if (end_speed.y < 0 && m_physic.get_velocity_y() > end_speed.y) - m_wind_velocity.y = std::max(m_wind_velocity.y + velocity.y, end_speed.y); + end_velocity.y = std::max(m_wind_velocity.y + velocity.y, end_speed.y); + + m_wind_velocity = glm::lerp(m_wind_velocity, end_velocity, 0.5f); } From e47610f843e1cff718b189ba1bd4256310257995 Mon Sep 17 00:00:00 2001 From: biggeryetbetter Date: Sat, 1 Jun 2024 10:33:20 -0500 Subject: [PATCH 09/18] Improve wind-player interactions * Wind acceleration is now integrated with `dt_sec` * Wind acceleration to the player is now smoother and is more consistent with established accelerations such as gravity. * Snappier movement when swimming in current at the cost of some physical consistency * Friction modified slightly * Tux can skid in wind again but will not make the noise because it was annoying. * Most badguys now should be pushed around by wind like expected. --- src/badguy/badguy.cpp | 37 +++++++++++---- src/badguy/badguy.hpp | 7 ++- src/badguy/mriceblock.cpp | 7 +++ src/badguy/walking_badguy.cpp | 8 ++++ src/object/player.cpp | 89 +++++++++++++++++++++++------------ src/object/player.hpp | 2 +- src/object/wind.cpp | 4 +- 7 files changed, 109 insertions(+), 45 deletions(-) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index 01ab9387301..881d286e3d3 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -52,6 +52,8 @@ BadGuy::BadGuy(const Vector& pos, Direction direction, const std::string& sprite MovingSprite(pos, sprite_name, layer, COLGROUP_DISABLED), ExposedObject(this), m_physic(), + m_wind_velocity(), + m_wind_acceleration(0.f), m_countMe(true), m_is_initialized(false), m_start_position(m_col.m_bbox.p1()), @@ -95,6 +97,8 @@ BadGuy::BadGuy(const ReaderMapping& reader, const std::string& sprite_name, MovingSprite(reader, sprite_name, layer, COLGROUP_DISABLED), ExposedObject(this), m_physic(), + m_wind_velocity(), + m_wind_acceleration(0.f), m_countMe(true), m_is_initialized(false), m_start_position(m_col.m_bbox.p1()), @@ -324,6 +328,11 @@ BadGuy::get_allowed_directions() const void BadGuy::active_update(float dt_sec) { + if (m_col.m_colliding_wind.empty()) { + m_wind_velocity = Vector(0.f, 0.f); + m_wind_acceleration = 0.0; + } + if (!is_grabbed()) m_col.set_movement(m_physic.get_movement(dt_sec)); if (m_frozen) @@ -1111,21 +1120,29 @@ BadGuy::after_editor_set() bool BadGuy::can_be_affected_by_wind() const { - return !on_ground(); + return true; } void -BadGuy::add_wind_velocity(const Vector& velocity, const Vector& end_speed) +BadGuy::add_wind_velocity(const float acceleration, const Vector& end_speed, const float dt_sec) { + Vector adjusted_end_speed = glm::normalize(end_speed) * acceleration; + + Vector vec_acceleration = adjusted_end_speed * dt_sec; + + m_wind_acceleration = acceleration; + Vector end_velocity = Vector(0.f, 0.f); // Only add velocity in the same direction as the wind. - if (end_speed.x > 0 && m_physic.get_velocity_x() < end_speed.x) - m_physic.set_velocity_x(std::min(m_physic.get_velocity_x() + velocity.x, end_speed.x)); - if (end_speed.x < 0 && m_physic.get_velocity_x() > end_speed.x) - m_physic.set_velocity_x(std::max(m_physic.get_velocity_x() + velocity.x, end_speed.x)); - if (end_speed.y > 0 && m_physic.get_velocity_y() < end_speed.y) - m_physic.set_velocity_y(std::min(m_physic.get_velocity_y() + velocity.y, end_speed.y)); - if (end_speed.y < 0 && m_physic.get_velocity_y() > end_speed.y) - m_physic.set_velocity_y(std::max(m_physic.get_velocity_y() + velocity.y, end_speed.y)); + if (adjusted_end_speed.x > 0 && m_physic.get_velocity_x() + m_wind_velocity.x < end_speed.x) + end_velocity.x = std::min(vec_acceleration.x, adjusted_end_speed.x); + if (adjusted_end_speed.x < 0 && m_physic.get_velocity_x() + m_wind_velocity.x > end_speed.x) + end_velocity.x = std::max(vec_acceleration.x, adjusted_end_speed.x); + if (adjusted_end_speed.y > 0 && m_physic.get_velocity_y() + m_wind_velocity.y < end_speed.y) + end_velocity.y = std::min(vec_acceleration.y, adjusted_end_speed.y); + if (adjusted_end_speed.y < 0 && m_physic.get_velocity_y() + m_wind_velocity.y > end_speed.y) + end_velocity.y = std::max(vec_acceleration.y, adjusted_end_speed.y); + + m_wind_velocity = glm::lerp(m_wind_velocity, end_velocity, 0.5f); } /* EOF */ diff --git a/src/badguy/badguy.hpp b/src/badguy/badguy.hpp index 8631803e283..f9856a8ea28 100644 --- a/src/badguy/badguy.hpp +++ b/src/badguy/badguy.hpp @@ -133,8 +133,8 @@ class BadGuy : public MovingSprite, /** Returns true if the badguy can currently be affected by wind */ virtual bool can_be_affected_by_wind() const; - /** Adds velocity from wind */ - virtual void add_wind_velocity(const Vector& velocity, const Vector& end_speed); + /** Version of `add_velocity` with modifications for wind physics */ + void add_wind_velocity(const float acceleration, const Vector& end_speed, const float dt_sec); protected: enum State { @@ -239,6 +239,9 @@ class BadGuy : public MovingSprite, protected: Physic m_physic; + Vector m_wind_velocity; + float m_wind_acceleration; + public: /** Count this badguy to the statistics? This value should not be changed during runtime. */ diff --git a/src/badguy/mriceblock.cpp b/src/badguy/mriceblock.cpp index 41cf220861f..1cfa6e186ef 100644 --- a/src/badguy/mriceblock.cpp +++ b/src/badguy/mriceblock.cpp @@ -138,6 +138,13 @@ MrIceBlock::active_update(float dt_sec) return; } + if (!m_col.m_colliding_wind.empty()) { + if (on_ground() && m_wind_velocity.y > 0.f) + m_wind_velocity.y = 0.f; + + m_physic.set_velocity(m_physic.get_velocity() + m_wind_velocity); + } + BadGuy::active_update(dt_sec); } diff --git a/src/badguy/walking_badguy.cpp b/src/badguy/walking_badguy.cpp index 51b07ccf3fc..1a635e8c9d6 100644 --- a/src/badguy/walking_badguy.cpp +++ b/src/badguy/walking_badguy.cpp @@ -156,6 +156,14 @@ WalkingBadguy::active_update(float dt_sec, float dest_x_velocity, float modifier assert(false); } + if (!m_col.m_colliding_wind.empty()) { + if (on_ground() && m_wind_velocity.y > 0.f) + m_wind_velocity.y = 0.f; + + m_physic.set_velocity(m_physic.get_velocity() + m_wind_velocity); + } + + if (max_drop_height > -1 && on_ground() && might_fall(max_drop_height+1) && !m_stay_on_platform_overridden) turn_around(); m_stay_on_platform_overridden = false; diff --git a/src/object/player.cpp b/src/object/player.cpp index 01587512c44..8cb194fd028 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -17,6 +17,10 @@ #include "object/player.hpp" +#include + +#include + #include "audio/sound_manager.hpp" #include "badguy/badguy.hpp" #include "control/codecontroller.hpp" @@ -37,6 +41,7 @@ #include "object/sprite_particle.hpp" #include "sprite/sprite.hpp" #include "sprite/sprite_manager.hpp" +#include "supertux/direction.hpp" #include "supertux/game_session.hpp" #include "supertux/gameconfig.hpp" #include "supertux/resources.hpp" @@ -138,7 +143,7 @@ const float STONE_UP_ACCELERATION = 400.f; /* Swim variables */ const float SWIM_SPEED = 300.f; const float SWIM_BOOST_SPEED = 600.f; -const float SWIM_TO_BOOST_ACCEL = 15.f; +const float SWIM_ACCEL_POWER = 0.4f; const float TURN_MAGNITUDE = 0.15f; const float TURN_MAGNITUDE_BOOST = 0.2f; @@ -557,8 +562,12 @@ Player::update(float dt_sec) if (!m_dying && !m_deactivated) handle_input(); - if (!m_col.m_colliding_wind.empty()) + if (!m_col.m_colliding_wind.empty()) { + if (on_ground() && m_wind_velocity.y > 0.f) + m_wind_velocity.y = 0.f; + m_physic.set_velocity(m_physic.get_velocity() + m_wind_velocity); + } /* // handle_input() calls apply_friction() when Tux is not walking, so we'll have to do this ourselves if (deactivated) @@ -1015,14 +1024,27 @@ Player::swim(float pointx, float pointy, bool boost) Vector diff = m_physic.get_velocity() - swimming_direction; float diff_len = glm::length(diff); - float accel_power = glm::length(m_wind_velocity) > 0.0f ? 1.f / m_wind_acceleration : 0.33f; + Vector acceleration = Vector( + (-diff.x * pow(1.f/std::max(1.f, diff_len), SWIM_ACCEL_POWER)), + (-diff.y * pow(1.f/std::max(1.f, diff_len), SWIM_ACCEL_POWER)) + ); - m_physic.set_velocity_x(vx - (diff.x * pow(1.f/std::max(1.f, diff_len), accel_power))); - m_physic.set_velocity_y(vy - (diff.y * pow(1.f/std::max(1.f, diff_len), accel_power))); - } else { - apply_friction(); + acceleration.x = std::clamp(acceleration.x, -m_swimming_accel_modifier, m_swimming_accel_modifier); + acceleration.y = std::clamp(acceleration.y, -m_swimming_accel_modifier, m_swimming_accel_modifier); + + // Prevent backwards acceleration, i.e. Tux slowing himself down when he is already going faster + // than his swimming speed. + if (vx * pointx > swimming_direction.x * pointx) + acceleration.x = 0; + if (vy * pointy > swimming_direction.y * pointy) + acceleration.y = 0; + + + m_physic.set_velocity(m_physic.get_velocity() + acceleration); } + apply_friction(); + // Snapping to prevent unwanted floating if (!is_ang_defined && glm::length(Vector(vx,vy)) < 100.f) { @@ -1083,11 +1105,6 @@ Player::apply_friction() return; } - if (m_swimming) { - m_physic.set_velocity(velx * 0.95f, vely * 0.95f); - return; - } - float friction = WALK_ACCELERATION_X; if (m_on_ice && is_on_ground) //we need this or else sliding on ice will cause Tux to go on for a very long time @@ -1095,11 +1112,22 @@ Player::apply_friction() else friction *= (NORMAL_FRICTION_MULTIPLIER*(m_sliding ? 0.8f : m_stone ? 0.4f : 1.f)); + // Air friction does not make sense when the air is moving with you! + if (!is_on_ground && !m_col.m_colliding_wind.empty() && std::abs(m_wind_velocity.x) > 0.f) + friction = 0.f; + if (velx < 0) { m_physic.set_acceleration_x(friction); } else if (velx > 0) { m_physic.set_acceleration_x(-friction); } // no friction for physic.get_velocity_x() == 0 + + if (m_swimming) { + if (vely < 0) + m_physic.set_acceleration_y(friction); + else if (vely > 0) + m_physic.set_acceleration_y(-friction); + } } void @@ -1182,16 +1210,14 @@ Player::handle_horizontal_input() // changing directions? if ((vx < 0 && dirsign >0) || (vx>0 && dirsign<0)) { if (on_ground()) { - // Better acceleration in wind when we are on the ground - bool wind_control = false; - if (!m_col.m_colliding_wind.empty()) { - ax *= 3.f; - wind_control = true; - } // let's skid! - if (fabsf(vx)>SKID_XM && !m_skidding_timer.started() && !wind_control) { + if (fabsf(vx)>SKID_XM && !m_skidding_timer.started()) { m_skidding_timer.start(SKID_TIME); - SoundManager::current()->play("sounds/skid.wav", get_pos()); + + // skidding sound disabled in wind because it becomes too repetitive + if (m_col.m_colliding_wind.empty()) + SoundManager::current()->play("sounds/skid.wav", get_pos()); + // dust some particles Sector::get().add( Vector(m_dir == Direction::LEFT ? m_col.m_bbox.get_right() : m_col.m_bbox.get_left(), m_col.m_bbox.get_bottom()), @@ -2973,20 +2999,23 @@ Player::remove_collected_key(Key* key) } void -Player::add_wind_velocity(const Vector& speed, const float acceleration, const Vector& end_speed) +Player::add_wind_velocity(const float acceleration, const Vector& end_speed, const float dt_sec) { - Vector velocity = glm::normalize(end_speed) * acceleration; + Vector adjusted_end_speed = glm::normalize(end_speed) * acceleration; + + Vector vec_acceleration = adjusted_end_speed * dt_sec; + m_wind_acceleration = acceleration; Vector end_velocity = Vector(0.f, 0.f); // Only add velocity in the same direction as the wind. - if (end_speed.x > 0 && m_physic.get_velocity_x() < end_speed.x) - end_velocity.x = std::min(m_wind_velocity.x + velocity.x, end_speed.x); - if (end_speed.x < 0 && m_physic.get_velocity_x() > end_speed.x) - end_velocity.x = std::max(m_wind_velocity.x + velocity.x, end_speed.x); - if (end_speed.y > 0 && m_physic.get_velocity_y() < end_speed.y) - end_velocity.y = std::min(m_wind_velocity.y + velocity.y, end_speed.y); - if (end_speed.y < 0 && m_physic.get_velocity_y() > end_speed.y) - end_velocity.y = std::max(m_wind_velocity.y + velocity.y, end_speed.y); + if (adjusted_end_speed.x > 0 && m_physic.get_velocity_x() + m_wind_velocity.x < end_speed.x) + end_velocity.x = std::min(vec_acceleration.x, adjusted_end_speed.x); + if (adjusted_end_speed.x < 0 && m_physic.get_velocity_x() + m_wind_velocity.x > end_speed.x) + end_velocity.x = std::max(vec_acceleration.x, adjusted_end_speed.x); + if (adjusted_end_speed.y > 0 && m_physic.get_velocity_y() + m_wind_velocity.y < end_speed.y) + end_velocity.y = std::min(vec_acceleration.y, adjusted_end_speed.y); + if (adjusted_end_speed.y < 0 && m_physic.get_velocity_y() + m_wind_velocity.y > end_speed.y) + end_velocity.y = std::max(vec_acceleration.y, adjusted_end_speed.y); m_wind_velocity = glm::lerp(m_wind_velocity, end_velocity, 0.5f); } diff --git a/src/object/player.hpp b/src/object/player.hpp index 3a19a2e0f12..de4dd4424d2 100644 --- a/src/object/player.hpp +++ b/src/object/player.hpp @@ -168,7 +168,7 @@ class Player final : public MovingObject, void add_velocity(const Vector& velocity, const Vector& end_speed); /** Version of `add_velocity` with modifications for wind physics */ - void add_wind_velocity(const Vector& velocity, const float acceleration, const Vector& end_speed); + void add_wind_velocity(const float acceleration, const Vector& end_speed, const float dt_sec); /** Returns the current velocity of the player */ Vector get_velocity() const; diff --git a/src/object/wind.cpp b/src/object/wind.cpp index 91d30d82488..09e8d627150 100644 --- a/src/object/wind.cpp +++ b/src/object/wind.cpp @@ -155,7 +155,7 @@ Wind::collision(GameObject& other, const CollisionHit& ) if (player && affects_player) { player->override_velocity(); - player->add_wind_velocity(speed, acceleration, speed * get_wind_strength(player->get_bbox().get_middle())); + player->add_wind_velocity(acceleration * get_wind_strength(player->get_bbox().get_middle()), speed, dt_sec); } auto badguy = dynamic_cast(&other); @@ -164,7 +164,7 @@ Wind::collision(GameObject& other, const CollisionHit& ) if (m_type == CURRENT && dynamic_cast(badguy)) { // Dive mines are not affected by currents return ABORT_MOVE; } - badguy->add_wind_velocity(speed * get_wind_strength(badguy->get_bbox().get_middle()) * acceleration * dt_sec, speed); + badguy->add_wind_velocity(acceleration * get_wind_strength(badguy->get_bbox().get_middle()), speed, dt_sec); } auto rock = dynamic_cast(&other); From ba6cee500c976d7d95a867ab7e26b072a7fc948a Mon Sep 17 00:00:00 2001 From: biggeryetbetter Date: Wed, 10 Jul 2024 12:06:50 -0500 Subject: [PATCH 10/18] Code cleaning and enable wind for many badguys * All badguys for which it makes sense can interact and be pushed by wind * Wind interaction logic put in seperate functions * Fixed many member variable names in `src/object/rock.hpp` to conform to the style guide --- src/badguy/badguy.cpp | 21 ++++- src/badguy/badguy.hpp | 4 + src/badguy/fish_harmless.cpp | 7 +- src/badguy/fish_harmless.hpp | 1 + src/badguy/flyingsnowball.cpp | 19 ++-- src/badguy/mriceblock.cpp | 7 -- src/badguy/stalactite.cpp | 1 + src/badguy/walking_badguy.cpp | 8 -- src/object/rock.cpp | 161 +++++++++++++++++++------------- src/object/rock.hpp | 25 +++-- src/object/rusty_trampoline.cpp | 2 +- src/object/wind.cpp | 2 +- 12 files changed, 151 insertions(+), 107 deletions(-) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index 49128cc4646..f04e223bb4d 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -386,10 +386,7 @@ BadGuy::get_allowed_directions() const void BadGuy::active_update(float dt_sec) { - if (m_col.m_colliding_wind.empty()) { - m_wind_velocity = Vector(0.f, 0.f); - m_wind_acceleration = 0.0; - } + handle_wind(); if (!is_grabbed()) { @@ -412,6 +409,22 @@ BadGuy::active_update(float dt_sec) } } +void +BadGuy::handle_wind() +{ + if (!m_col.m_colliding_wind.empty()) + { + if (on_ground() && m_wind_velocity.y > 0.f) + m_wind_velocity.y = 0.f; + + m_physic.set_velocity(m_physic.get_velocity() + m_wind_velocity); + } + else { + m_wind_velocity = Vector(0.f, 0.f); + m_wind_acceleration = 0.0; + } +} + void BadGuy::inactive_update(float ) { diff --git a/src/badguy/badguy.hpp b/src/badguy/badguy.hpp index 0d5e64e8f1c..5350bb6d3db 100644 --- a/src/badguy/badguy.hpp +++ b/src/badguy/badguy.hpp @@ -63,6 +63,10 @@ class BadGuy : public MovingSprite, state and calls active_update and inactive_update */ virtual void update(float dt_sec) override; + /** Called each frame during active_update. Applies velocity from + * wind if the badguy is inside wind and resets it if not. */ + virtual void handle_wind(); + static std::string class_name() { return "badguy"; } virtual std::string get_class_name() const override { return class_name(); } virtual std::string get_exposed_class_name() const override { return "BadGuy"; } diff --git a/src/badguy/fish_harmless.cpp b/src/badguy/fish_harmless.cpp index 2cebf6698d3..31d7dc4eaa6 100644 --- a/src/badguy/fish_harmless.cpp +++ b/src/badguy/fish_harmless.cpp @@ -26,7 +26,12 @@ void FishHarmless::initialize() { FishSwimming::initialize(); - set_colgroup_active(COLGROUP_MOVING_ONLY_STATIC); + set_colgroup_active(COLGROUP_MOVING); +} + +HitResponse +FishHarmless::collision_player(Player& player, const CollisionHit& hit) { + return HitResponse::ABORT_MOVE; } /* EOF */ diff --git a/src/badguy/fish_harmless.hpp b/src/badguy/fish_harmless.hpp index 58895c3954e..bbb5ce308de 100644 --- a/src/badguy/fish_harmless.hpp +++ b/src/badguy/fish_harmless.hpp @@ -35,6 +35,7 @@ class FishHarmless final : public FishSwimming protected: virtual void initialize() override; + virtual HitResponse collision_player(Player& player, const CollisionHit& hit) override; private: FishHarmless(const FishHarmless&) = delete; diff --git a/src/badguy/flyingsnowball.cpp b/src/badguy/flyingsnowball.cpp index 85302095275..eccd5f48629 100644 --- a/src/badguy/flyingsnowball.cpp +++ b/src/badguy/flyingsnowball.cpp @@ -76,23 +76,24 @@ FlyingSnowBall::active_update(float dt_sec) float delta = total_time_elapsed * GLOBAL_SPEED_MULT; - // Put that function in a graphing calculator : + // Derivative of the following function (put it in a graphing calculator): // sin(x)^3 + sin(3(x - pi/3))/3 float targetHgt = ( - std::pow(std::sin(delta), 3.f) + - std::sin(3.f * - ((delta - math::PI) / 3.f) - ) / 3.f - ) * 100.f; + std::cos(3.f * (delta - math::PI/3.f)) + + std::pow(std::sin(delta), 2.f) + * std::cos(delta) * 3.f + ); - m_physic.set_velocity_y(m_physic.get_velocity_y() + (targetHgt - prev_height) / dt_sec); - prev_height = targetHgt; + // Simple damping and then movement + m_physic.set_velocity_y(m_physic.get_velocity_y() * pow(0.5f, dt_sec)); + m_physic.set_velocity_y(m_physic.get_velocity_y() + targetHgt); m_physic.set_velocity_x(m_physic.get_velocity_x() * pow(0.5f, dt_sec)); + BadGuy::handle_wind(); + m_col.set_movement(m_physic.get_movement(dt_sec)); - m_physic.set_velocity_y(0.f); auto player = get_nearest_player(); if (player) { diff --git a/src/badguy/mriceblock.cpp b/src/badguy/mriceblock.cpp index 1cfa6e186ef..41cf220861f 100644 --- a/src/badguy/mriceblock.cpp +++ b/src/badguy/mriceblock.cpp @@ -138,13 +138,6 @@ MrIceBlock::active_update(float dt_sec) return; } - if (!m_col.m_colliding_wind.empty()) { - if (on_ground() && m_wind_velocity.y > 0.f) - m_wind_velocity.y = 0.f; - - m_physic.set_velocity(m_physic.get_velocity() + m_wind_velocity); - } - BadGuy::active_update(dt_sec); } diff --git a/src/badguy/stalactite.cpp b/src/badguy/stalactite.cpp index 80c94ab98cd..281747d56ed 100644 --- a/src/badguy/stalactite.cpp +++ b/src/badguy/stalactite.cpp @@ -74,6 +74,7 @@ Stalactite::active_update(float dt_sec) set_colgroup_active(COLGROUP_MOVING); } } else if (state == STALACTITE_FALLING) { + BadGuy::handle_wind(); m_col.set_movement(m_physic.get_movement(dt_sec)); } diff --git a/src/badguy/walking_badguy.cpp b/src/badguy/walking_badguy.cpp index 1a635e8c9d6..51b07ccf3fc 100644 --- a/src/badguy/walking_badguy.cpp +++ b/src/badguy/walking_badguy.cpp @@ -156,14 +156,6 @@ WalkingBadguy::active_update(float dt_sec, float dest_x_velocity, float modifier assert(false); } - if (!m_col.m_colliding_wind.empty()) { - if (on_ground() && m_wind_velocity.y > 0.f) - m_wind_velocity.y = 0.f; - - m_physic.set_velocity(m_physic.get_velocity() + m_wind_velocity); - } - - if (max_drop_height > -1 && on_ground() && might_fall(max_drop_height+1) && !m_stay_on_platform_overridden) turn_around(); m_stay_on_platform_overridden = false; diff --git a/src/object/rock.cpp b/src/object/rock.cpp index 2e200d4c91c..26c126f16e9 100644 --- a/src/object/rock.cpp +++ b/src/object/rock.cpp @@ -37,18 +37,20 @@ namespace { Rock::Rock(const ReaderMapping& reader, const std::string& spritename) : MovingSprite(reader, spritename), - physic(), - on_ground(false), - on_ice(false), - last_movement(0.0f, 0.0f), - on_grab_script(), - on_ungrab_script(), - running_grab_script(), - running_ungrab_script() + m_physic(), + m_on_ground(false), + m_on_ice(false), + m_last_movement(0.0f, 0.0f), + m_wind_velocity(), + m_wind_acceleration(0.f), + m_on_grab_script(), + m_on_ungrab_script(), + m_running_grab_script(), + m_running_ungrab_script() { parse_type(reader); - reader.get("on-grab-script", on_grab_script, ""); - reader.get("on-ungrab-script", on_ungrab_script, ""); + reader.get("on-grab-script", m_on_grab_script, ""); + reader.get("on-ungrab-script", m_on_ungrab_script, ""); SoundManager::current()->preload(ROCK_SOUND); set_group(COLGROUP_MOVING_STATIC); @@ -56,14 +58,14 @@ Rock::Rock(const ReaderMapping& reader, const std::string& spritename) : Rock::Rock(const Vector& pos, const std::string& spritename) : MovingSprite(pos, spritename), - physic(), - on_ground(false), - on_ice(false), - last_movement(0.0f, 0.0f), - on_grab_script(), - on_ungrab_script(), - running_grab_script(), - running_ungrab_script() + m_physic(), + m_on_ground(false), + m_on_ice(false), + m_last_movement(0.0f, 0.0f), + m_on_grab_script(), + m_on_ungrab_script(), + m_running_grab_script(), + m_running_ungrab_script() { SoundManager::current()->preload(ROCK_SOUND); set_group(COLGROUP_MOVING_STATIC); @@ -101,10 +103,10 @@ Rock::update(float dt_sec) Rectf icebox = get_bbox().grown(-1.f); icebox.set_bottom(get_bbox().get_bottom() + 8.f); - on_ice = !Sector::get().is_free_of_tiles(icebox, true, Tile::ICE); + m_on_ice = !Sector::get().is_free_of_tiles(icebox, true, Tile::ICE); bool in_water = !Sector::get().is_free_of_tiles(get_bbox(), true, Tile::WATER); - physic.set_gravity_modifier(in_water ? 0.2f : 1.f); + m_physic.set_gravity_modifier(in_water ? 0.2f : 1.f); Rectf trampolinebox = get_bbox().grown(-1.f); trampolinebox.set_bottom(get_bbox().get_bottom() + 8.f); @@ -114,23 +116,41 @@ Rock::update(float dt_sec) (glm::length((get_bbox().get_middle() - trampoline.get_bbox().get_middle())) >= 10.f) && is_portable()) { trampoline.bounce(); - physic.set_velocity_y(-500.f); + m_physic.set_velocity_y(-500.f); } } Rectf playerbox = get_bbox().grown(-2.f); playerbox.set_bottom(get_bbox().get_bottom() + 7.f); for (auto& player : Sector::get().get_objects_by_type()) { - if (playerbox.overlaps(player.get_bbox()) && physic.get_velocity_y() > 0.f && is_portable()) { - physic.set_velocity_y(-250.f); + if (playerbox.overlaps(player.get_bbox()) && m_physic.get_velocity_y() > 0.f && is_portable()) { + m_physic.set_velocity_y(-250.f); } } - m_col.set_movement(physic.get_movement(dt_sec) * + handle_wind(); + + m_col.set_movement(m_physic.get_movement(dt_sec) * Vector(in_water ? 0.4f : 1.f, in_water ? 0.6f : 1.f)); } } +void +Rock::handle_wind() +{ + if (!m_col.m_colliding_wind.empty()) + { + if (m_on_ground && m_wind_velocity.y > 0.f) + m_wind_velocity.y = 0.f; + + m_physic.set_velocity(m_physic.get_velocity() + m_wind_velocity); + } + else { + m_wind_velocity = Vector(0.f, 0.f); + m_wind_acceleration = 0.0; + } +} + void Rock::collision_solid(const CollisionHit& hit) { @@ -138,24 +158,24 @@ Rock::collision_solid(const CollisionHit& hit) return; } if (hit.top || hit.bottom) - physic.set_velocity_y(0); + m_physic.set_velocity_y(0); if (hit.left || hit.right) { // Bounce back slightly when hitting a wall - float velx = physic.get_velocity_x(); - physic.set_velocity_x(-0.1f * velx); + float velx = m_physic.get_velocity_x(); + m_physic.set_velocity_x(-0.1f * velx); } if (hit.crush) - physic.set_velocity(0, 0); + m_physic.set_velocity(0, 0); - if (hit.bottom && !on_ground && !is_grabbed() && !on_ice) { + if (hit.bottom && !m_on_ground && !is_grabbed() && !m_on_ice) { SoundManager::current()->play(ROCK_SOUND, get_pos()); - physic.set_velocity_x(0); - on_ground = true; + m_physic.set_velocity_x(0); + m_on_ground = true; } - if (on_ground || (hit.bottom && on_ice)) { + if (m_on_ground || (hit.bottom && m_on_ice)) { // Full friction! - physic.set_velocity_x(physic.get_velocity_x() * (1.f - (GROUND_FRICTION * (on_ice ? 0.5f : 1.f)))); + m_physic.set_velocity_x(m_physic.get_velocity_x() * (1.f - (GROUND_FRICTION * (m_on_ice ? 0.5f : 1.f)))); } } @@ -196,25 +216,25 @@ Rock::collision(GameObject& other, const CollisionHit& hit) if (hit.bottom) { auto player = dynamic_cast (&other); if (player) { - physic.set_velocity_y(-250.f); + m_physic.set_velocity_y(-250.f); } } // Don't fall further if we are on a rock which is on the ground. // This is to avoid jittering. auto rock = dynamic_cast (&other); - if (rock && rock->on_ground && hit.bottom) { - physic.set_velocity_y(rock->get_physic().get_velocity_y()); + if (rock && rock->m_on_ground && hit.bottom) { + m_physic.set_velocity_y(rock->get_physic().get_velocity_y()); return CONTINUE; } - if (!on_ground) { - if (hit.bottom && physic.get_velocity_y() > 200) { + if (!m_on_ground) { + if (hit.bottom && m_physic.get_velocity_y() > 200) { auto badguy = dynamic_cast (&other); if (badguy && badguy->get_group() != COLGROUP_TOUCHABLE) { //Getting a rock on the head hurts. A lot. badguy->kill_fall(); - physic.set_velocity_y(0); + m_physic.set_velocity_y(0); } } return FORCE_MOVE; @@ -229,15 +249,15 @@ Rock::grab(MovingObject& object, const Vector& pos, Direction dir_) Portable::grab(object, pos, dir_); Vector movement = pos - get_pos(); m_col.set_movement(movement); - last_movement = movement; + m_last_movement = movement; set_group(COLGROUP_TOUCHABLE); //needed for lanterns catching willowisps - on_ground = false; + m_on_ground = false; - running_ungrab_script = false; - if (!on_grab_script.empty() && !running_grab_script) + m_running_ungrab_script = false; + if (!m_on_grab_script.empty() && !m_running_grab_script) { - running_grab_script = true; - Sector::get().run_script(on_grab_script, "Rock::on_grab"); + m_running_grab_script = true; + Sector::get().run_script(m_on_grab_script, "Rock::on_grab"); } } @@ -246,28 +266,28 @@ Rock::ungrab(MovingObject& object, Direction dir) { auto player = dynamic_cast (&object); set_group(COLGROUP_MOVING_STATIC); - on_ground = false; + m_on_ground = false; if (player) { if (player->is_swimming() || player->is_water_jumping()) { float swimangle = player->get_swimming_angle(); - physic.set_velocity(player->get_velocity() + Vector(std::cos(swimangle), std::sin(swimangle))); + m_physic.set_velocity(player->get_velocity() + Vector(std::cos(swimangle), std::sin(swimangle))); } else { - physic.set_velocity_x(fabsf(player->get_physic().get_velocity_x()) < 1.f ? 0.f : + m_physic.set_velocity_x(fabsf(player->get_physic().get_velocity_x()) < 1.f ? 0.f : player->m_dir == Direction::LEFT ? -200.f : 200.f); - physic.set_velocity_y((dir == Direction::UP) ? -500.f : (dir == Direction::DOWN) ? 500.f : - (glm::length(last_movement) > 1) ? -200.f : 0.f); + m_physic.set_velocity_y((dir == Direction::UP) ? -500.f : (dir == Direction::DOWN) ? 500.f : + (glm::length(m_last_movement) > 1) ? -200.f : 0.f); } } - running_grab_script = false; - if (!on_ungrab_script.empty() && !running_ungrab_script) + m_running_grab_script = false; + if (!m_on_ungrab_script.empty() && !m_running_ungrab_script) { - running_ungrab_script = true; - Sector::get().run_script(on_ungrab_script, "Rock::on_ungrab"); + m_running_ungrab_script = true; + Sector::get().run_script(m_on_ungrab_script, "Rock::on_ungrab"); } Portable::ungrab(object, dir); } @@ -276,23 +296,32 @@ ObjectSettings Rock::get_settings() { auto result = MovingSprite::get_settings(); - result.add_script(_("On-grab script"), &on_grab_script, "on-grab-script"); - result.add_script(_("On-ungrab script"), &on_ungrab_script, "on-ungrab-script"); + result.add_script(_("On-grab script"), &m_on_grab_script, "on-grab-script"); + result.add_script(_("On-ungrab script"), &m_on_ungrab_script, "on-ungrab-script"); return result; } void -Rock::add_wind_velocity(const Vector& velocity, const Vector& end_speed) +Rock::add_wind_velocity(const float acceleration, const Vector& end_speed, const float dt_sec) { - // only add velocity in the same direction as the wind - if (end_speed.x > 0 && physic.get_velocity_x() < end_speed.x) - physic.set_velocity_x(std::min(physic.get_velocity_x() + velocity.x, end_speed.x)); - if (end_speed.x < 0 && physic.get_velocity_x() > end_speed.x) - physic.set_velocity_x(std::max(physic.get_velocity_x() + velocity.x, end_speed.x)); - if (end_speed.y > 0 && physic.get_velocity_y() < end_speed.y) - physic.set_velocity_y(std::min(physic.get_velocity_y() + velocity.y, end_speed.y)); - if (end_speed.y < 0 && physic.get_velocity_y() > end_speed.y) - physic.set_velocity_y(std::max(physic.get_velocity_y() + velocity.y, end_speed.y)); + Vector adjusted_end_speed = glm::normalize(end_speed) * acceleration; + + Vector vec_acceleration = adjusted_end_speed * dt_sec; + + m_wind_acceleration = acceleration; + Vector end_velocity = Vector(0.f, 0.f); + // Only add velocity in the same direction as the wind. + if (adjusted_end_speed.x > 0 && m_physic.get_velocity_x() + m_wind_velocity.x < end_speed.x) + end_velocity.x = std::min(vec_acceleration.x, adjusted_end_speed.x); + if (adjusted_end_speed.x < 0 && m_physic.get_velocity_x() + m_wind_velocity.x > end_speed.x) + end_velocity.x = std::max(vec_acceleration.x, adjusted_end_speed.x); + if (adjusted_end_speed.y > 0 && m_physic.get_velocity_y() + m_wind_velocity.y < end_speed.y) + end_velocity.y = std::min(vec_acceleration.y, adjusted_end_speed.y); + if (adjusted_end_speed.y < 0 && m_physic.get_velocity_y() + m_wind_velocity.y > end_speed.y) + end_velocity.y = std::max(vec_acceleration.y, adjusted_end_speed.y); + + m_wind_velocity = glm::lerp(m_wind_velocity, end_velocity, 0.5f); } + /* EOF */ diff --git a/src/object/rock.hpp b/src/object/rock.hpp index c50f8ff45fb..334ef0396bf 100644 --- a/src/object/rock.hpp +++ b/src/object/rock.hpp @@ -45,8 +45,11 @@ class Rock : public MovingSprite, std::string get_default_sprite_name() const override; /** Adds velocity from wind */ - virtual void add_wind_velocity(const Vector& velocity, const Vector& end_speed); - Physic& get_physic() { return physic; } + virtual void add_wind_velocity(const float acceleration, const Vector& end_speed, const float dt_sec); + Physic& get_physic() { return m_physic; } + +protected: + virtual void handle_wind(); private: enum Type { @@ -55,14 +58,16 @@ class Rock : public MovingSprite, }; protected: - Physic physic; - bool on_ground; - bool on_ice; - Vector last_movement; - std::string on_grab_script; - std::string on_ungrab_script; - bool running_grab_script; - bool running_ungrab_script; + Physic m_physic; + bool m_on_ground; + bool m_on_ice; + Vector m_last_movement; + Vector m_wind_velocity; + float m_wind_acceleration; + std::string m_on_grab_script; + std::string m_on_ungrab_script; + bool m_running_grab_script; + bool m_running_ungrab_script; private: Rock(const Rock&) = delete; diff --git a/src/object/rusty_trampoline.cpp b/src/object/rusty_trampoline.cpp index 9b3ce246bb5..347f6d33236 100644 --- a/src/object/rusty_trampoline.cpp +++ b/src/object/rusty_trampoline.cpp @@ -74,7 +74,7 @@ HitResponse RustyTrampoline::collision(GameObject& other, const CollisionHit& hit) { //Trampoline has to be on ground to work. - if (on_ground) { + if (m_on_ground) { auto player = dynamic_cast (&other); //Trampoline works for player if (player) { diff --git a/src/object/wind.cpp b/src/object/wind.cpp index 9a50222e45c..1772d33127c 100644 --- a/src/object/wind.cpp +++ b/src/object/wind.cpp @@ -172,7 +172,7 @@ Wind::collision(GameObject& other, const CollisionHit& ) auto rock = dynamic_cast(&other); if (rock && affects_objects) { - rock->add_wind_velocity(speed * get_wind_strength(rock->get_bbox().get_middle()) * acceleration * dt_sec, speed); + rock->add_wind_velocity(acceleration * get_wind_strength(rock->get_bbox().get_middle()), speed, dt_sec); } return ABORT_MOVE; From 32ac6d69808c6d77babf5eda277c049a04b241e2 Mon Sep 17 00:00:00 2001 From: biggeryetbetter Date: Wed, 7 Aug 2024 17:59:57 -0500 Subject: [PATCH 11/18] Swimming behaves more like the original swimming * Tux's acceleration is not as aggressive. * Tux will not plow through wind when swimming regardless of its power. * Tux experiences more friction when he is not pointing where he is going. --- src/object/player.cpp | 54 +++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/src/object/player.cpp b/src/object/player.cpp index b66a3b66e14..b188108facb 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -146,7 +146,6 @@ const float STONE_UP_ACCELERATION = 400.f; /* Swim variables */ const float SWIM_SPEED = 300.f; const float SWIM_BOOST_SPEED = 600.f; -const float SWIM_ACCEL_POWER = 0.4f; const float TURN_MAGNITUDE = 0.15f; const float TURN_MAGNITUDE_BOOST = 0.2f; @@ -1030,27 +1029,18 @@ Player::swim(float pointx, float pointy, bool boost) if (std::abs(delta) < 0.01f) m_swimming_angle = pointed_angle; - Vector swimming_direction = math::vec2_from_polar(m_swimming_accel_modifier, pointed_angle); - Vector diff = m_physic.get_velocity() - swimming_direction; - float diff_len = glm::length(diff); - - Vector acceleration = Vector( - (-diff.x * pow(1.f/std::max(1.f, diff_len), SWIM_ACCEL_POWER)), - (-diff.y * pow(1.f/std::max(1.f, diff_len), SWIM_ACCEL_POWER)) - ); - - acceleration.x = std::clamp(acceleration.x, -m_swimming_accel_modifier, m_swimming_accel_modifier); - acceleration.y = std::clamp(acceleration.y, -m_swimming_accel_modifier, m_swimming_accel_modifier); - + Vector acceleration = math::vec2_from_polar(m_swimming_accel_modifier, pointed_angle); + // Prevent backwards acceleration, i.e. Tux slowing himself down when he is already going faster // than his swimming speed. - if (vx * pointx > swimming_direction.x * pointx) + if (vx * pointx > acceleration.x * pointx) acceleration.x = 0; - if (vy * pointy > swimming_direction.y * pointy) + if (vy * pointy > acceleration.y * pointy) acceleration.y = 0; - - m_physic.set_velocity(m_physic.get_velocity() + acceleration); + m_physic.set_acceleration(acceleration); + } else { + m_physic.set_acceleration(Vector(0.f)); } apply_friction(); @@ -1108,7 +1098,7 @@ Player::apply_friction() { bool is_on_ground = on_ground(); float velx = m_physic.get_velocity_x(); - float vely = m_physic.get_velocity_y(); + if (is_on_ground && (fabsf(velx) < (m_stone ? 5.f : WALK_SPEED))) { m_physic.set_velocity_x(0); m_physic.set_acceleration_x(0); @@ -1126,17 +1116,25 @@ Player::apply_friction() if (!is_on_ground && !m_col.m_colliding_wind.empty() && std::abs(m_wind_velocity.x) > 0.f) friction = 0.f; - if (velx < 0) { - m_physic.set_acceleration_x(friction); - } else if (velx > 0) { - m_physic.set_acceleration_x(-friction); - } // no friction for physic.get_velocity_x() == 0 + if (m_swimming) + { + if (glm::length(m_wind_velocity) == 0.f) { + // Friction factor in water is how similar Tux's swimming direction is to his actual direction, + // mapped between 0.95 and 0.99. Tux is more aerodynamic going forwards than backwards. + Vector swimming_direction = math::vec2_from_polar(1.f, m_swimming_angle); + Vector fac = swimming_direction - glm::normalize(m_physic.get_velocity()); - if (m_swimming) { - if (vely < 0) - m_physic.set_acceleration_y(friction); - else if (vely > 0) - m_physic.set_acceleration_y(-friction); + fac = Vector(0.99f) - glm::abs(fac) / 2.0f * 0.04; + + m_physic.set_velocity(m_physic.get_velocity() * fac); + } + } else + { + if (velx < 0) { + m_physic.set_acceleration_x(friction); + } else if (velx > 0) { + m_physic.set_acceleration_x(-friction); + } // no friction for physic.get_velocity_x() == 0 } } From 5d1bc5d8fe3a76efef6351ba2877150986b47205 Mon Sep 17 00:00:00 2001 From: biggeryetbetter Date: Thu, 24 Oct 2024 12:59:02 -0500 Subject: [PATCH 12/18] Refactor wind logic Wind was integrated into the `Physic` class, meaning it can be accessed in the same manner as object velocity and acceleration. Signed-off-by: biggeryetbetter --- src/badguy/badguy.cpp | 37 ++++------------------------- src/badguy/badguy.hpp | 6 ----- src/math/vector.hpp | 27 +++++++++++++++++++++ src/object/player.cpp | 52 +++++++---------------------------------- src/object/player.hpp | 5 ---- src/object/rock.cpp | 35 ++++----------------------- src/object/rock.hpp | 4 ---- src/object/wind.cpp | 15 +++++++++--- src/supertux/physic.cpp | 25 +++++++++++++++++++- src/supertux/physic.hpp | 27 +++++++++++++++++++++ 10 files changed, 106 insertions(+), 127 deletions(-) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index 85cbe3b5589..6ca3c29e690 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -54,8 +54,6 @@ BadGuy::BadGuy(const Vector& pos, Direction direction, const std::string& sprite const std::string& light_sprite_name, const std::string& ice_sprite_name) : MovingSprite(pos, sprite_name, layer, COLGROUP_DISABLED), m_physic(), - m_wind_velocity(), - m_wind_acceleration(0.f), m_countMe(true), m_is_initialized(false), m_start_position(m_col.m_bbox.p1()), @@ -99,8 +97,6 @@ BadGuy::BadGuy(const ReaderMapping& reader, const std::string& sprite_name, const std::string& light_sprite_name, const std::string& ice_sprite_name) : MovingSprite(reader, sprite_name, layer, COLGROUP_DISABLED), m_physic(), - m_wind_velocity(), - m_wind_acceleration(0.f), m_countMe(true), m_is_initialized(false), m_start_position(m_col.m_bbox.p1()), @@ -414,14 +410,12 @@ BadGuy::handle_wind() { if (!m_col.m_colliding_wind.empty()) { - if (on_ground() && m_wind_velocity.y > 0.f) - m_wind_velocity.y = 0.f; - - m_physic.set_velocity(m_physic.get_velocity() + m_wind_velocity); + if (on_ground() && m_physic.get_wind_velocity_y() > 0.f) + m_physic.set_wind_velocity_y(0.f); } else { - m_wind_velocity = Vector(0.f, 0.f); - m_wind_acceleration = 0.0; + m_physic.set_wind_velocity(Vector(0.f)); + m_physic.set_wind_acceleration(0.0); } } @@ -1209,29 +1203,6 @@ BadGuy::can_be_affected_by_wind() const return true; } -void -BadGuy::add_wind_velocity(const float acceleration, const Vector& end_speed, const float dt_sec) -{ - Vector adjusted_end_speed = glm::normalize(end_speed) * acceleration; - - Vector vec_acceleration = adjusted_end_speed * dt_sec; - - m_wind_acceleration = acceleration; - Vector end_velocity = Vector(0.f, 0.f); - // Only add velocity in the same direction as the wind. - if (adjusted_end_speed.x > 0 && m_physic.get_velocity_x() + m_wind_velocity.x < end_speed.x) - end_velocity.x = std::min(vec_acceleration.x, adjusted_end_speed.x); - if (adjusted_end_speed.x < 0 && m_physic.get_velocity_x() + m_wind_velocity.x > end_speed.x) - end_velocity.x = std::max(vec_acceleration.x, adjusted_end_speed.x); - if (adjusted_end_speed.y > 0 && m_physic.get_velocity_y() + m_wind_velocity.y < end_speed.y) - end_velocity.y = std::min(vec_acceleration.y, adjusted_end_speed.y); - if (adjusted_end_speed.y < 0 && m_physic.get_velocity_y() + m_wind_velocity.y > end_speed.y) - end_velocity.y = std::max(vec_acceleration.y, adjusted_end_speed.y); - - m_wind_velocity = glm::lerp(m_wind_velocity, end_velocity, 0.5f); -} - - void BadGuy::register_class(ssq::VM& vm) { diff --git a/src/badguy/badguy.hpp b/src/badguy/badguy.hpp index 0976ad01bc4..a9c38358df8 100644 --- a/src/badguy/badguy.hpp +++ b/src/badguy/badguy.hpp @@ -158,9 +158,6 @@ class BadGuy : public MovingSprite, /** Returns true if the badguy can currently be affected by wind */ virtual bool can_be_affected_by_wind() const; - /** Version of `add_velocity` with modifications for wind physics */ - void add_wind_velocity(const float acceleration, const Vector& end_speed, const float dt_sec); - Physic& get_physic() { return m_physic; } protected: @@ -266,9 +263,6 @@ class BadGuy : public MovingSprite, protected: Physic m_physic; - Vector m_wind_velocity; - float m_wind_acceleration; - public: /** Count this badguy to the statistics? This value should not be changed during runtime. */ diff --git a/src/math/vector.hpp b/src/math/vector.hpp index e84c2f1a589..c90862b3121 100644 --- a/src/math/vector.hpp +++ b/src/math/vector.hpp @@ -42,6 +42,33 @@ inline Vector at_angle(Vector const& v, float angle) return vec2_from_polar(glm::length(v), angle); } +// Move vector towards a new vector by a scalar delta. +inline Vector move_towards(Vector const& from, Vector const& to, float d) { + // Based on Godot's implementation + Vector vd = to - from; + float len = vd.length(); + return len <= d ? to : from + vd / len * d; +} + +// Change a velocity vector towards another, but do not change a component towards zero unless their signs are opposite. +inline Vector push_to_velocity(Vector const& from, Vector const& to, float d) { + if (d == 0.f) return from; + + Vector diff = glm::normalize(to - from) * d; + Vector result = from; + + if (to.x > 0 && from.x < to.x) + result.x = std::min(from.x + diff.x, to.x); + if (to.x < 0 && from.x > to.x) + result.x = std::max(from.x + diff.x, to.x); + if (to.y > 0 && from.y < to.y) + result.y = std::min(from.y + diff.y, to.y); + if (to.y < 0 && from.y > to.y) + result.y = std::max(from.y + diff.y, to.y); + + return result; +} + } // namespace math #endif diff --git a/src/object/player.cpp b/src/object/player.cpp index b188108facb..3af26045b88 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -218,8 +218,6 @@ Player::Player(PlayerStatus& player_status, const std::string& name_, int player m_growing(false), m_backflip_timer(), m_physic(), - m_wind_velocity(), - m_wind_acceleration(), m_visible(true), m_grabbed_object(nullptr), m_grabbed_object_remove_listener(new GrabListener(*this)), @@ -396,8 +394,8 @@ void Player::update(float dt_sec) { if (m_col.m_colliding_wind.empty()) { - m_wind_velocity = Vector(0.f, 0.f); - m_wind_acceleration = 0.0; + m_physic.set_wind_acceleration(0); + m_physic.set_wind_velocity(0, 0); } if (is_dead() || Sector::get().get_object_count() == 1) @@ -571,12 +569,6 @@ Player::update(float dt_sec) if (!m_dying && !m_deactivated) handle_input(); - if (!m_col.m_colliding_wind.empty()) { - if (on_ground() && m_wind_velocity.y > 0.f) - m_wind_velocity.y = 0.f; - - m_physic.set_velocity(m_physic.get_velocity() + m_wind_velocity); - } /* // handle_input() calls apply_friction() when Tux is not walking, so we'll have to do this ourselves if (deactivated) @@ -1112,22 +1104,16 @@ Player::apply_friction() else friction *= (NORMAL_FRICTION_MULTIPLIER*(m_sliding ? 0.8f : m_stone ? 0.4f : 1.f)); - // Air friction does not make sense when the air is moving with you! - if (!is_on_ground && !m_col.m_colliding_wind.empty() && std::abs(m_wind_velocity.x) > 0.f) - friction = 0.f; - if (m_swimming) { - if (glm::length(m_wind_velocity) == 0.f) { - // Friction factor in water is how similar Tux's swimming direction is to his actual direction, - // mapped between 0.95 and 0.99. Tux is more aerodynamic going forwards than backwards. - Vector swimming_direction = math::vec2_from_polar(1.f, m_swimming_angle); - Vector fac = swimming_direction - glm::normalize(m_physic.get_velocity()); + // Friction factor in water is how similar Tux's swimming direction is to his actual direction, + // mapped between 0.95 and 0.99. Tux is more aerodynamic going forwards than backwards. + Vector swimming_direction = math::vec2_from_polar(1.f, m_swimming_angle); + Vector fac = swimming_direction - glm::normalize(m_physic.get_velocity()); - fac = Vector(0.99f) - glm::abs(fac) / 2.0f * 0.04; + fac = Vector(0.99f) - glm::abs(fac) / 2.0f * 0.04; - m_physic.set_velocity(m_physic.get_velocity() * fac); - } + m_physic.set_velocity(m_physic.get_velocity() * fac); } else { if (velx < 0) { @@ -3083,28 +3069,6 @@ Player::remove_collected_key(Key* key) m_collected_keys.end()); } -void -Player::add_wind_velocity(const float acceleration, const Vector& end_speed, const float dt_sec) -{ - Vector adjusted_end_speed = glm::normalize(end_speed) * acceleration; - - Vector vec_acceleration = adjusted_end_speed * dt_sec; - - m_wind_acceleration = acceleration; - Vector end_velocity = Vector(0.f, 0.f); - // Only add velocity in the same direction as the wind. - if (adjusted_end_speed.x > 0 && m_physic.get_velocity_x() + m_wind_velocity.x < end_speed.x) - end_velocity.x = std::min(vec_acceleration.x, adjusted_end_speed.x); - if (adjusted_end_speed.x < 0 && m_physic.get_velocity_x() + m_wind_velocity.x > end_speed.x) - end_velocity.x = std::max(vec_acceleration.x, adjusted_end_speed.x); - if (adjusted_end_speed.y > 0 && m_physic.get_velocity_y() + m_wind_velocity.y < end_speed.y) - end_velocity.y = std::min(vec_acceleration.y, adjusted_end_speed.y); - if (adjusted_end_speed.y < 0 && m_physic.get_velocity_y() + m_wind_velocity.y > end_speed.y) - end_velocity.y = std::max(vec_acceleration.y, adjusted_end_speed.y); - - m_wind_velocity = glm::lerp(m_wind_velocity, end_velocity, 0.5f); -} - void Player::register_class(ssq::VM& vm) { diff --git a/src/object/player.hpp b/src/object/player.hpp index aabb89d1341..3b6bddab79c 100644 --- a/src/object/player.hpp +++ b/src/object/player.hpp @@ -251,9 +251,6 @@ class Player final : public MovingObject /** Adds velocity to the player until given end speed is reached */ void add_velocity(const Vector& velocity, const Vector& end_speed); - /** Version of `add_velocity` with modifications for wind physics */ - void add_wind_velocity(const float acceleration, const Vector& end_speed, const float dt_sec); - /** Returns the current velocity of the player */ Vector get_velocity() const; /** @@ -541,8 +538,6 @@ class Player final : public MovingObject Timer m_backflip_timer; Physic m_physic; - Vector m_wind_velocity; - float m_wind_acceleration; bool m_visible; Portable* m_grabbed_object; diff --git a/src/object/rock.cpp b/src/object/rock.cpp index 26c126f16e9..7c5030ad36e 100644 --- a/src/object/rock.cpp +++ b/src/object/rock.cpp @@ -41,8 +41,6 @@ Rock::Rock(const ReaderMapping& reader, const std::string& spritename) : m_on_ground(false), m_on_ice(false), m_last_movement(0.0f, 0.0f), - m_wind_velocity(), - m_wind_acceleration(0.f), m_on_grab_script(), m_on_ungrab_script(), m_running_grab_script(), @@ -140,14 +138,12 @@ Rock::handle_wind() { if (!m_col.m_colliding_wind.empty()) { - if (m_on_ground && m_wind_velocity.y > 0.f) - m_wind_velocity.y = 0.f; - - m_physic.set_velocity(m_physic.get_velocity() + m_wind_velocity); + if (m_on_ground && m_physic.get_wind_velocity_y() > 0.f) + m_physic.set_wind_velocity_y(0.f); } else { - m_wind_velocity = Vector(0.f, 0.f); - m_wind_acceleration = 0.0; + m_physic.set_wind_velocity(Vector(0.f)); + m_physic.set_wind_acceleration(0.0); } } @@ -301,27 +297,4 @@ Rock::get_settings() return result; } -void -Rock::add_wind_velocity(const float acceleration, const Vector& end_speed, const float dt_sec) -{ - Vector adjusted_end_speed = glm::normalize(end_speed) * acceleration; - - Vector vec_acceleration = adjusted_end_speed * dt_sec; - - m_wind_acceleration = acceleration; - Vector end_velocity = Vector(0.f, 0.f); - // Only add velocity in the same direction as the wind. - if (adjusted_end_speed.x > 0 && m_physic.get_velocity_x() + m_wind_velocity.x < end_speed.x) - end_velocity.x = std::min(vec_acceleration.x, adjusted_end_speed.x); - if (adjusted_end_speed.x < 0 && m_physic.get_velocity_x() + m_wind_velocity.x > end_speed.x) - end_velocity.x = std::max(vec_acceleration.x, adjusted_end_speed.x); - if (adjusted_end_speed.y > 0 && m_physic.get_velocity_y() + m_wind_velocity.y < end_speed.y) - end_velocity.y = std::min(vec_acceleration.y, adjusted_end_speed.y); - if (adjusted_end_speed.y < 0 && m_physic.get_velocity_y() + m_wind_velocity.y > end_speed.y) - end_velocity.y = std::max(vec_acceleration.y, adjusted_end_speed.y); - - m_wind_velocity = glm::lerp(m_wind_velocity, end_velocity, 0.5f); -} - - /* EOF */ diff --git a/src/object/rock.hpp b/src/object/rock.hpp index 24459fe6463..5fdbec915e7 100644 --- a/src/object/rock.hpp +++ b/src/object/rock.hpp @@ -45,8 +45,6 @@ class Rock : public MovingSprite, virtual GameObjectTypes get_types() const override; std::string get_default_sprite_name() const override; - /** Adds velocity from wind */ - virtual void add_wind_velocity(const float acceleration, const Vector& end_speed, const float dt_sec); Physic& get_physic() { return m_physic; } protected: @@ -63,8 +61,6 @@ class Rock : public MovingSprite, bool m_on_ground; bool m_on_ice; Vector m_last_movement; - Vector m_wind_velocity; - float m_wind_acceleration; std::string m_on_grab_script; std::string m_on_ungrab_script; bool m_running_grab_script; diff --git a/src/object/wind.cpp b/src/object/wind.cpp index abc1563e5d3..eed3f3409b1 100644 --- a/src/object/wind.cpp +++ b/src/object/wind.cpp @@ -158,7 +158,10 @@ Wind::collision(GameObject& other, const CollisionHit& ) if (player && affects_player) { player->override_velocity(); - player->add_wind_velocity(acceleration * get_wind_strength(player->get_bbox().get_middle()), speed, dt_sec); + player->get_physic().set_wind_acceleration( + this->acceleration * get_wind_strength(player->get_bbox().get_middle()) + ); + player->get_physic().set_wind_velocity(this->speed); } auto badguy = dynamic_cast(&other); @@ -167,13 +170,19 @@ Wind::collision(GameObject& other, const CollisionHit& ) if (m_type == CURRENT && dynamic_cast(badguy)) { // Dive mines are not affected by currents return ABORT_MOVE; } - badguy->add_wind_velocity(acceleration * get_wind_strength(badguy->get_bbox().get_middle()), speed, dt_sec); + badguy->get_physic().set_wind_acceleration( + this->acceleration * get_wind_strength(badguy->get_bbox().get_middle()) + ); + badguy->get_physic().set_wind_velocity(this->speed); } auto rock = dynamic_cast(&other); if (rock && affects_objects) { - rock->add_wind_velocity(acceleration * get_wind_strength(rock->get_bbox().get_middle()), speed, dt_sec); + rock->get_physic().set_wind_acceleration( + this->acceleration * get_wind_strength(rock->get_bbox().get_middle()) + ); + rock->get_physic().set_wind_velocity(this->speed); } return ABORT_MOVE; diff --git a/src/supertux/physic.cpp b/src/supertux/physic.cpp index b84b409c860..e271b711211 100644 --- a/src/supertux/physic.cpp +++ b/src/supertux/physic.cpp @@ -22,6 +22,9 @@ Physic::Physic() : ax(0), ay(0), vx(0), vy(0), + wvx(0), wvy(0), + wa(0), + wind_enabled_flag(true), gravity_enabled_flag(true), gravity_modifier(1.0f) { @@ -30,7 +33,8 @@ Physic::Physic() : void Physic::reset() { - ax = ay = vx = vy = 0; + ax = ay = vx = vy = wvx = wvy = wa = 0; + wind_enabled_flag = true; gravity_enabled_flag = true; } @@ -48,6 +52,18 @@ Physic::set_velocity(const Vector& vector) vy = vector.y; } +void +Physic::set_wind_velocity(float nvx, float nvy) { + wvx = nvx; + wvy = nvy; +} + +void +Physic::set_wind_velocity(const Vector& vector) { + wvx = vector.x; + wvy = vector.y; +} + void Physic::set_acceleration(float nax, float nay) { @@ -72,6 +88,13 @@ Physic::get_movement(float dt_sec) // v t + .5 a t (t+dt_sec) at total time t vx += ax * dt_sec; vy += (ay + grav) * dt_sec; + + if (wind_enabled_flag) { + this->set_velocity( + math::push_to_velocity(this->get_velocity(), this->get_wind_velocity(), wa * dt_sec) + ); + } + Vector result(vx * dt_sec, vy * dt_sec); return result; diff --git a/src/supertux/physic.hpp b/src/supertux/physic.hpp index 77ad3f7fe97..8f1ddb7d367 100644 --- a/src/supertux/physic.hpp +++ b/src/supertux/physic.hpp @@ -47,6 +47,24 @@ class Physic final float get_velocity_x() const { return vx; } float get_velocity_y() const { return vy; } + /// Set both components of the wind velocity + void set_wind_velocity(float nvx, float nvy); + void set_wind_velocity(const Vector& vector); + + /// Set one component of the wind velocity + void set_wind_velocity_x(float nvx) { wvx = nvx; } + void set_wind_velocity_y(float nvy) { wvy = nvy; } + + /// Get one or both components of the wind velocity + Vector get_wind_velocity() const { return Vector(wvx, wvy); } + float get_wind_velocity_x() const { return wvx; } + float get_wind_velocity_y() const { return wvy; } + + /// Set wind acceleration + void set_wind_acceleration(float nwa) { wa = nwa; } + /// Get wind acceleration + float get_wind_acceleration() const { return wa; } + /// Set acceleration. /** Sets acceleration applied to the object. (Note that gravity is * eventually added to the vertical acceleration) @@ -79,6 +97,15 @@ class Physic final /** horizontal and vertical velocity */ float vx, vy; + /** horizontal and vertical wind velocity */ + float wvx, wvy; + + /** wind acceleration */ + float wa; + + /** should wind velocity be included in the calculations? */ + bool wind_enabled_flag; + /** should we respect gravity in our calculations? */ bool gravity_enabled_flag; From 07ee4ef267812b78d106daf6b6d1cf8f187827bb Mon Sep 17 00:00:00 2001 From: biggeryetbetter Date: Thu, 24 Oct 2024 13:26:19 -0500 Subject: [PATCH 13/18] Make wind accelerate bigger --- src/supertux/physic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/supertux/physic.cpp b/src/supertux/physic.cpp index e271b711211..e07261da8b7 100644 --- a/src/supertux/physic.cpp +++ b/src/supertux/physic.cpp @@ -91,7 +91,7 @@ Physic::get_movement(float dt_sec) if (wind_enabled_flag) { this->set_velocity( - math::push_to_velocity(this->get_velocity(), this->get_wind_velocity(), wa * dt_sec) + math::push_to_velocity(this->get_velocity(), this->get_wind_velocity(), wa * 100.0f * dt_sec) ); } From 7bc161516a472bcd292d5170c8b0864e022d29dc Mon Sep 17 00:00:00 2001 From: biggeryetbetter Date: Mon, 28 Oct 2024 09:08:03 -0500 Subject: [PATCH 14/18] Make swimming less sluggish Slightly higher acceleration for normal swimming and much higher acceleration for boost swimming. Turning is a bit more sharp. --- src/object/player.cpp | 25 ++++++++++++------------- src/object/player.hpp | 1 - 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/object/player.cpp b/src/object/player.cpp index 03de3e31108..719e82beba6 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -146,6 +146,8 @@ const float STONE_UP_ACCELERATION = 400.f; /* Swim variables */ const float SWIM_SPEED = 300.f; const float SWIM_BOOST_SPEED = 600.f; +const float SWIM_ACCEL = 600.f; +const float SWIM_BOOST_ACCEL = 2400.f; const float TURN_MAGNITUDE = 0.15f; const float TURN_MAGNITUDE_BOOST = 0.2f; const std::array BUBBLE_ACTIONS = { "normal", "small" }; @@ -228,7 +230,6 @@ Player::Player(PlayerStatus& player_status, const std::string& name_, int player // constructor m_sprite(SpriteManager::current()->create("images/creatures/tux/tux.sprite")), m_swimming_angle(0), - m_swimming_accel_modifier(100.f), m_water_jump(false), m_airarrow(Surface::from_file("images/engine/hud/airarrow.png")), m_bubbles_sprite(SpriteManager::current()->create("images/particles/air_bubble.sprite")), @@ -1089,15 +1090,13 @@ Player::swim(float pointx, float pointy, bool boost) if (m_swimming && !m_water_jump) { - m_swimming_accel_modifier = is_ang_defined ? 1.f : 0.f; + float speed = is_ang_defined ? 1.f : 0.f; + speed *= boost ? SWIM_BOOST_SPEED : SWIM_SPEED; + float accel_mag = boost ? SWIM_BOOST_ACCEL : SWIM_ACCEL; if (boost) { - m_swimming_accel_modifier = m_swimming_accel_modifier * SWIM_BOOST_SPEED; m_swimboosting = true; - } - else - { - m_swimming_accel_modifier = m_swimming_accel_modifier * SWIM_SPEED; + } else { if (glm::length(m_physic.get_velocity()) < SWIM_SPEED + 10.f) { m_swimboosting = false; } @@ -1108,13 +1107,12 @@ Player::swim(float pointx, float pointy, bool boost) if (std::abs(delta) < 0.01f) m_swimming_angle = pointed_angle; - Vector acceleration = math::vec2_from_polar(m_swimming_accel_modifier, pointed_angle); + Vector acceleration = math::vec2_from_polar(accel_mag, pointed_angle); - // Prevent backwards acceleration, i.e. Tux slowing himself down when he is already going faster - // than his swimming speed. - if (vx * pointx > acceleration.x * pointx) + // Don't let Tux go too fast. + if (vx * pointx > speed) acceleration.x = 0; - if (vy * pointy > acceleration.y * pointy) + if (vy * pointy > speed) acceleration.y = 0; m_physic.set_acceleration(acceleration); @@ -1197,8 +1195,9 @@ Player::apply_friction() // mapped between 0.95 and 0.99. Tux is more aerodynamic going forwards than backwards. Vector swimming_direction = math::vec2_from_polar(1.f, m_swimming_angle); Vector fac = swimming_direction - glm::normalize(m_physic.get_velocity()); + float modifier = m_swimboosting ? 0.5f : 2.0f; - fac = Vector(0.99f) - glm::abs(fac) / 2.0f * 0.04; + fac = Vector(0.99f) - glm::abs(fac) / modifier * 0.04; m_physic.set_velocity(m_physic.get_velocity() * fac); } else diff --git a/src/object/player.hpp b/src/object/player.hpp index 0c834ee2367..0a53ed2ed97 100644 --- a/src/object/player.hpp +++ b/src/object/player.hpp @@ -565,7 +565,6 @@ class Player final : public MovingObject SpritePtr m_sprite; /**< The main sprite representing Tux */ float m_swimming_angle; - float m_swimming_accel_modifier; bool m_water_jump; SurfacePtr m_airarrow; /**< arrow indicating Tux' position when he's above the camera */ From cbf24a540306aa2b9a4a4c391c44ea8a5589809a Mon Sep 17 00:00:00 2001 From: biggeryetbetter Date: Thu, 14 Nov 2024 10:42:02 -0600 Subject: [PATCH 15/18] Remove unused variable --- src/badguy/flyingsnowball.cpp | 1 - src/badguy/flyingsnowball.hpp | 1 - 2 files changed, 2 deletions(-) diff --git a/src/badguy/flyingsnowball.cpp b/src/badguy/flyingsnowball.cpp index eccd5f48629..bf3c5e02a5d 100644 --- a/src/badguy/flyingsnowball.cpp +++ b/src/badguy/flyingsnowball.cpp @@ -32,7 +32,6 @@ const float GLOBAL_SPEED_MULT = 0.8f; /**< The overall movement speed/rate. */ FlyingSnowBall::FlyingSnowBall(const ReaderMapping& reader) : BadGuy(reader, "images/creatures/flying_snowball/flying_snowball.sprite"), total_time_elapsed(), - prev_height(0.f), puff_timer() { m_physic.enable_gravity(false); diff --git a/src/badguy/flyingsnowball.hpp b/src/badguy/flyingsnowball.hpp index 3bdc74b29ca..206b9084f73 100644 --- a/src/badguy/flyingsnowball.hpp +++ b/src/badguy/flyingsnowball.hpp @@ -41,7 +41,6 @@ class FlyingSnowBall final : public BadGuy private: float total_time_elapsed; - float prev_height; Timer puff_timer; /**< time until the next smoke puff is spawned */ private: From 9a8cff1a71dc3a9816af88b6bc217f8511e2b376 Mon Sep 17 00:00:00 2001 From: biggeryetbetter Date: Fri, 15 Nov 2024 18:02:47 -0600 Subject: [PATCH 16/18] Reintroduce dive jumping --- src/object/player.cpp | 17 ++++++++++++++++- src/object/player.hpp | 1 + 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/object/player.cpp b/src/object/player.cpp index 719e82beba6..aa219ada4ab 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -185,6 +185,7 @@ Player::Player(PlayerStatus& player_status, const std::string& name_, int player m_on_right_wall(false), m_in_walljump_tile(false), m_can_walljump(false), + m_dive_speed(0.f), m_boost(0.f), m_speedlimit(0), //no special limit m_velocity_override(), @@ -623,6 +624,7 @@ Player::update(float dt_sec) m_no_water = false; m_water_jump = false; m_swimming = true; + m_dive_speed = glm::length(m_physic.get_velocity()); m_swimming_angle = math::angle(Vector(m_physic.get_velocity_x(), m_physic.get_velocity_y())); m_physic.set_acceleration(0.0f, 0.0f); if (is_big()) @@ -1063,6 +1065,12 @@ Player::swim(float pointx, float pointy, bool boost) if (m_swimming) m_physic.set_gravity_modifier(.0f); + if (pointy != -1) { + m_dive_speed = 0.f; + } + + std::cout << m_dive_speed << "\n"; + // Angle bool is_ang_defined = (pointx != 0) || (pointy != 0); float pointed_angle = math::angle(Vector(pointx, pointy)); @@ -1108,12 +1116,18 @@ Player::swim(float pointx, float pointy, bool boost) m_swimming_angle = pointed_angle; Vector acceleration = math::vec2_from_polar(accel_mag, pointed_angle); + acceleration += Vector(0, -m_dive_speed*2.f); // Don't let Tux go too fast. if (vx * pointx > speed) acceleration.x = 0; - if (vy * pointy > speed) + if (m_dive_speed != 0.f) { + if (vy * pointy > m_dive_speed) + acceleration.y = 0; + } + else if (vy * pointy > speed) acceleration.y = 0; + m_physic.set_acceleration(acceleration); } else { @@ -1131,6 +1145,7 @@ Player::swim(float pointx, float pointy, bool boost) } if (m_water_jump && !m_swimming) { + m_dive_speed = 0.f; m_swimming_angle = math::angle(Vector(vx, vy)); } diff --git a/src/object/player.hpp b/src/object/player.hpp index 0a53ed2ed97..b91cfe90e11 100644 --- a/src/object/player.hpp +++ b/src/object/player.hpp @@ -496,6 +496,7 @@ class Player final : public MovingObject bool m_on_right_wall; bool m_in_walljump_tile; bool m_can_walljump; + float m_dive_speed; // Speed at which Tux entered water. float m_boost; float m_speedlimit; bool m_velocity_override; From 7bda0ef8783317b4557d8fc92177896bcf812f46 Mon Sep 17 00:00:00 2001 From: biggeryetbetter Date: Sun, 1 Dec 2024 10:12:51 -0600 Subject: [PATCH 17/18] Fixed floating point errors --- src/math/vector.hpp | 1 + src/object/player.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/math/vector.hpp b/src/math/vector.hpp index c90862b3121..50ac3c28acc 100644 --- a/src/math/vector.hpp +++ b/src/math/vector.hpp @@ -53,6 +53,7 @@ inline Vector move_towards(Vector const& from, Vector const& to, float d) { // Change a velocity vector towards another, but do not change a component towards zero unless their signs are opposite. inline Vector push_to_velocity(Vector const& from, Vector const& to, float d) { if (d == 0.f) return from; + if (from == to) return from; Vector diff = glm::normalize(to - from) * d; Vector result = from; diff --git a/src/object/player.cpp b/src/object/player.cpp index aa219ada4ab..23fe885e4cd 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -1204,7 +1204,7 @@ Player::apply_friction() else friction *= (NORMAL_FRICTION_MULTIPLIER*(m_sliding ? 0.8f : m_stone ? 0.4f : 1.f)); - if (m_swimming) + if (m_swimming && glm::length(m_physic.get_velocity()) != 0.f) { // Friction factor in water is how similar Tux's swimming direction is to his actual direction, // mapped between 0.95 and 0.99. Tux is more aerodynamic going forwards than backwards. From fccd5a364028317893cce7d15feac9108d090ac5 Mon Sep 17 00:00:00 2001 From: biggeryetbetter Date: Sun, 1 Dec 2024 10:22:33 -0600 Subject: [PATCH 18/18] Reduce swimming speed and remove debugging leftovers --- src/object/player.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/object/player.cpp b/src/object/player.cpp index 23fe885e4cd..4db26b2e225 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -144,8 +144,8 @@ const float STONE_DOWN_ACCELERATION = 300.f; const float STONE_UP_ACCELERATION = 400.f; /* Swim variables */ -const float SWIM_SPEED = 300.f; -const float SWIM_BOOST_SPEED = 600.f; +const float SWIM_SPEED = 200.f; +const float SWIM_BOOST_SPEED = 400.f; const float SWIM_ACCEL = 600.f; const float SWIM_BOOST_ACCEL = 2400.f; const float TURN_MAGNITUDE = 0.15f; @@ -1069,8 +1069,6 @@ Player::swim(float pointx, float pointy, bool boost) m_dive_speed = 0.f; } - std::cout << m_dive_speed << "\n"; - // Angle bool is_ang_defined = (pointx != 0) || (pointy != 0); float pointed_angle = math::angle(Vector(pointx, pointy));