diff --git a/src/Ball.cpp b/src/Ball.cpp index fee78c2..eb9c311 100644 --- a/src/Ball.cpp +++ b/src/Ball.cpp @@ -5,7 +5,10 @@ #include "Constants.hpp" Ball::Ball(float radius, const sf::Vector2f& pos, const sf::Vector2f& vel) - : m_radius(radius), m_velocity(vel) { + : m_radius(radius), + m_velocity(vel), + m_lastPosition(pos), + m_pixelVelocity(vel) { m_shape.setRadius(radius); m_shape.setOrigin(sf::Vector2f(radius, radius)); m_shape.setPosition(pos); @@ -13,17 +16,30 @@ Ball::Ball(float radius, const sf::Vector2f& pos, const sf::Vector2f& vel) } void Ball::update(float dt) { + if (m_atRest) return; m_velocity.y += Constants::GRAVITY * dt; m_shape.move(m_velocity * dt); + + sf::Vector2f currentPosition = m_shape.getPosition(); + m_pixelVelocity = (currentPosition - m_lastPosition) / dt; + m_lastPosition = currentPosition; + handleWallCollision(); } void Ball::draw(sf::RenderWindow& window) { window.draw(m_shape); } -void Ball::applyImpulse(const sf::Vector2f& impulse) { m_velocity += impulse; } +void Ball::applyImpulse(const sf::Vector2f& impulse) { + m_velocity += impulse; + m_atRest = false; +} sf::Vector2f Ball::getPosition() const { return m_shape.getPosition(); } +sf::Vector2f Ball::getVelocity() const { return m_velocity; } + +bool Ball::isAtRest() const { return m_atRest; } + void Ball::handleWallCollision() { sf::Vector2f pos = m_shape.getPosition(); @@ -51,6 +67,13 @@ void Ball::handleWallCollision() { if (pos.y + m_radius >= Constants::HEIGHT - 1.0f) { m_velocity.x *= Constants::FRICTION; if (std::abs(m_velocity.x) < 5.f) m_velocity.x = 0.f; + if (std::abs(m_pixelVelocity.x) < Constants::REST_PIXEL_VELOCITY && + std::abs(m_pixelVelocity.y) < Constants::REST_PIXEL_VELOCITY) { + m_velocity = {0.f, 0.f}; + m_atRest = true; + } + } else { + m_atRest = false; } m_shape.setPosition(pos); diff --git a/src/Ball.hpp b/src/Ball.hpp index cc1705d..e835fc1 100644 --- a/src/Ball.hpp +++ b/src/Ball.hpp @@ -8,6 +8,9 @@ class Ball : public PhysicalObject { sf::CircleShape m_shape; sf::Vector2f m_velocity; float m_radius; + bool m_atRest = false; + sf::Vector2f m_lastPosition; + sf::Vector2f m_pixelVelocity; void handleWallCollision(); @@ -19,4 +22,7 @@ class Ball : public PhysicalObject { void applyImpulse(const sf::Vector2f& impulse) override; sf::Vector2f getPosition() const; + sf::Vector2f getVelocity() const; + bool isAtRest() const; + sf::Vector2f getPixelVelocity() const { return m_pixelVelocity; } }; diff --git a/src/Constants.hpp b/src/Constants.hpp index 21a3c4e..ae0124b 100644 --- a/src/Constants.hpp +++ b/src/Constants.hpp @@ -8,4 +8,5 @@ constexpr float RESTITUTION = 0.8f; constexpr float FRICTION = 0.9f; constexpr float BALL_RADIUS = 20.f; constexpr float IMPULSE = 3000.f; +constexpr float REST_PIXEL_VELOCITY = 2.0f; } // namespace Constants diff --git a/src/Game.cpp b/src/Game.cpp index 3efe85f..d524d5f 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -1,8 +1,8 @@ #include "Game.hpp" #include +#include -#include "Ball.hpp" #include "Constants.hpp" #include "VectorMath.hpp" @@ -61,9 +61,47 @@ void Game::update() { for (auto& object : m_objects) object->update(dt); } +void Game::drawLine(const sf::Vector2f& start, const sf::Vector2f& direction, + float length, const sf::Color& color) { + float dirLength = + std::sqrt(direction.x * direction.x + direction.y * direction.y); + sf::Vector2f dirNorm = + (dirLength != 0.f) ? direction / dirLength : sf::Vector2f(1.f, 0.f); + sf::Vector2f endPoint = start + dirNorm * length; + + sf::Vertex line[] = {{start, color}, {endPoint, color}}; + m_window.draw(line, 2, sf::PrimitiveType::Lines); +} + +void Game::drawDirectionLine(const Ball* ball) { + sf::Vector2f ballCenter = ball->getPosition(); + sf::Vector2i mousePixel = sf::Mouse::getPosition(m_window); + sf::Vector2f mouseWorld(static_cast(mousePixel.x), + static_cast(mousePixel.y)); + sf::Vector2f dir = mouseWorld - ballCenter; + drawLine(ballCenter, dir, 100.f, sf::Color::Green); +} + +void Game::drawVelocityLine(const Ball* ball) { + if (ball->isAtRest()) return; + sf::Vector2f ballCenter = ball->getPosition(); + sf::Vector2f velocity = ball->getVelocity(); + float velLength = + std::sqrt(velocity.x * velocity.x + velocity.y * velocity.y); + float clampedLength = std::min(100.f, std::max(0.f, velLength)); + drawLine(ballCenter, velocity, clampedLength, sf::Color::Blue); +} + void Game::render() { m_window.clear(sf::Color::Black); for (auto& object : m_objects) object->draw(m_window); + + auto* ball = dynamic_cast(m_objects[0].get()); + if (ball) { + drawDirectionLine(ball); + drawVelocityLine(ball); + } + m_window.display(); } diff --git a/src/Game.hpp b/src/Game.hpp index 063c3f1..0dc93a3 100644 --- a/src/Game.hpp +++ b/src/Game.hpp @@ -6,8 +6,10 @@ #include #include +#include "Ball.hpp" #include "PhysicalObject.hpp" +class Ball; class PhysicalObject; class Game { @@ -24,6 +26,11 @@ class Game { void update(); void render(); + void drawLine(const sf::Vector2f& start, const sf::Vector2f& direction, + float length, const sf::Color& color); + void drawDirectionLine(const Ball* ball); + void drawVelocityLine(const Ball* ball); + public: Game(); void run();