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;