From a6b1bccd37c1baf48a2f743e9d464f628d39e615 Mon Sep 17 00:00:00 2001 From: nihonium Date: Fri, 6 Jan 2023 00:44:44 +0300 Subject: [PATCH] seminar13 - arkanoid, even more to do --- seminar13_polymorphism/arkanoid/arkanoid.cpp | 29 +++- seminar13_polymorphism/arkanoid/arkanoid.hpp | 10 +- seminar13_polymorphism/arkanoid/ball.hpp | 3 + seminar13_polymorphism/arkanoid/bonus.cpp | 154 +++++++++++++++---- seminar13_polymorphism/arkanoid/bonus.hpp | 64 +++++++- seminar13_polymorphism/arkanoid/main.cpp | 2 +- 6 files changed, 224 insertions(+), 38 deletions(-) diff --git a/seminar13_polymorphism/arkanoid/arkanoid.cpp b/seminar13_polymorphism/arkanoid/arkanoid.cpp index c7be89f..55e8b73 100644 --- a/seminar13_polymorphism/arkanoid/arkanoid.cpp +++ b/seminar13_polymorphism/arkanoid/arkanoid.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "arkanoid.hpp" #include "bonus.hpp" @@ -15,7 +16,19 @@ void Arkanoid::addRandomBonus(sf::Vector2f position) int max_rand = 10000; if ((rand() % max_rand) * 1.0f / max_rand < m_bonusProbability) { - m_bonuses.push_back(new Bonus(position)); + m_bonuses.push_back(new TripleBallBonus(position)); + } + if ((rand() % max_rand) * 1.0f / max_rand < m_bonusProbability) + { + m_bonuses.push_back(new EnlargePaddleBonus(position)); + } + if ((rand() % max_rand) * 1.0f / max_rand < m_bonusProbability) + { + m_bonuses.push_back(new ShrinkPaddleBonus(position)); + } + if ((rand() % max_rand) * 1.0f / max_rand < m_bonusProbability) + { + m_bonuses.push_back(new SlowingBonus(position)); } } @@ -138,6 +151,20 @@ void Arkanoid::update(const sf::RenderWindow& window, float dt) } } + /* Обработка эффектов */ + for (auto it = m_effects.begin(); it != m_effects.end();) + { + std::cout << "meow1" << std::endl; + if ((*it)->isExpired(m_time)) + { + (*it)->deactivate(*this); + delete *it; + it = m_effects.erase(it); + } + else { + it++; + } + } } void Arkanoid::draw(sf::RenderWindow& window) diff --git a/seminar13_polymorphism/arkanoid/arkanoid.hpp b/seminar13_polymorphism/arkanoid/arkanoid.hpp index 8ba2996..5a1e68f 100644 --- a/seminar13_polymorphism/arkanoid/arkanoid.hpp +++ b/seminar13_polymorphism/arkanoid/arkanoid.hpp @@ -5,10 +5,11 @@ #include "brick_grid.hpp" #include "paddle.hpp" class Bonus; +class Effect; class Arkanoid { -private: +protected: // Константы: // Цвет задника const sf::Color kBackgroundColor {12, 31, 47}; @@ -40,6 +41,7 @@ private: // Почему указатели - для реализации полиформизма // Так как в будущем мы хотим сделать несколько вариантов бонусов std::list m_bonuses; + std::list m_effects; // Вероятность того, что при разрушении блока выпадет бонус float m_bonusProbability; @@ -75,4 +77,10 @@ public: // Класс бонус должен быть дружественным, так как он может менять внутреннее состояние игры friend class Bonus; + friend class TripleBallBonus; + friend class EnlargePaddleBonus; + friend class ShrinkPaddleBonus; + friend class SlowingBonus; + + friend class SlowingEffect; }; diff --git a/seminar13_polymorphism/arkanoid/ball.hpp b/seminar13_polymorphism/arkanoid/ball.hpp index 2bca550..115313e 100644 --- a/seminar13_polymorphism/arkanoid/ball.hpp +++ b/seminar13_polymorphism/arkanoid/ball.hpp @@ -13,6 +13,9 @@ struct Ball sf::Vector2f position; sf::Vector2f velocity; + /* Every bit is responsible for ball being affected by some effect */ + char affectedBy = 0; + Ball(float radius, sf::Vector2f position, sf::Vector2f velocity); void update(float dt); diff --git a/seminar13_polymorphism/arkanoid/bonus.cpp b/seminar13_polymorphism/arkanoid/bonus.cpp index d6cc064..641af55 100644 --- a/seminar13_polymorphism/arkanoid/bonus.cpp +++ b/seminar13_polymorphism/arkanoid/bonus.cpp @@ -1,28 +1,33 @@ #include +#include #include "bonus.hpp" #include "arkanoid.hpp" #include "ball.hpp" #include "paddle.hpp" -const double pi = 3.14159265358979323846; - Bonus::Bonus(sf::Vector2f position): m_position(position) { m_time = 0; } -// Двигаем бонус void Bonus::update(float dt) { m_time += dt; m_position.y += speed * dt; } -// Рисуем бонус -void Bonus::draw(sf::RenderWindow& window) const +bool Bonus::isColiding(const Paddle& paddle) const +{ + bool result = paddle.getBorder().intersects({m_position.x - radius, m_position.y - radius, 2 * radius, 2 * radius}); + return result; +} + +/* + * TripleBallBonus + * */ +void TripleBallBonus::draw(sf::RenderWindow& window) const { - // Рисуем белый круг static sf::CircleShape shape(radius); shape.setOrigin(radius, radius); shape.setFillColor(sf::Color{100, 200, 100}); @@ -30,49 +35,32 @@ void Bonus::draw(sf::RenderWindow& window) const window.draw(shape); float angle = 0; - // Рисуем 3 шарика на этом круге + static Ball ball {5, {0, 0}, {0, 0}}; float ballRotationRadius = 7; ball.position = m_position + ballRotationRadius * sf::Vector2f(std::cos(angle), std::sin(angle)); ball.draw(window); - angle += 2.0 * pi / 3.0; + angle += 2.0 * M_PI / 3.0; ball.position = m_position + ballRotationRadius * sf::Vector2f(std::cos(angle), std::sin(angle)); ball.draw(window); - angle += 2.0 * pi / 3.0; + angle += 2.0 * M_PI / 3.0; ball.position = m_position + ballRotationRadius * sf::Vector2f(std::cos(angle), std::sin(angle)); ball.draw(window); } - -/* - Функция Bonus::activate - - Применяем эффект бонуса (в данном случае - утроение шариков) - numBalls - Количество шариков до утроения - Шарики хранятся в связном списке m_balls - Так как мы работаем со связным списком, то придётся использовать итератор it - - Проходим итератором по изначальным элементам списка и добавляем новые шарики в список - В данном случае простой цикл через итераторы не сработает, так как массив game.m_balls увеличивается в процессе выполнения цикла. - - Внутри цикла выбираем случайный вектор скорости и добавляем шарик в список game.m_balls - Делаем то же самое для ещё одного шарика - В конце цикла переходим ко следующему шарику в списке, т.е. увеличивем итератор it - -*/ -void Bonus::activate(Arkanoid& game) +void TripleBallBonus::activate(Arkanoid& game) { int numBalls = game.m_balls.size(); std::list::iterator it = game.m_balls.begin(); for (int i = 0; i < numBalls; i++) { - float angle = rand() % 1000 * (2 * pi / 1000); + float angle = rand() % 1000 * (2 * M_PI / 1000); float vx = Ball::initialVelocity * sin(angle); float vy = Ball::initialVelocity * cos(angle); game.addBall({game.m_initialBall.radius, (*it).position, {vx, vy}}); - angle = rand() % 1000 * (2 * pi / 1000); + angle = rand() % 1000 * (2 * M_PI / 1000); vx = Ball::initialVelocity * sin(angle); vy = Ball::initialVelocity * cos(angle); game.addBall({game.m_initialBall.radius, (*it).position, {vx, vy}}); @@ -81,11 +69,113 @@ void Bonus::activate(Arkanoid& game) } } -bool Bonus::isColiding(const Paddle& paddle) const +TripleBallBonus::~TripleBallBonus() {} + +/* + * EnlargePaddleBonus + * */ +void EnlargePaddleBonus::draw(sf::RenderWindow& window) const { - bool result = paddle.getBorder().intersects({m_position.x - radius, m_position.y - radius, 2 * radius, 2 * radius}); - return result; + static sf::CircleShape shape(radius); + shape.setOrigin(radius, radius); + shape.setFillColor(sf::Color{100, 200, 100}); + shape.setPosition(m_position); + window.draw(shape); + + static sf::RectangleShape rect(sf::Vector2f{radius, radius / 2}); + rect.setFillColor(sf::Color::Green); + rect.setPosition(m_position - sf::Vector2f{radius /2, radius / 4}); + window.draw(rect); +} + +void EnlargePaddleBonus::activate(Arkanoid& game) +{ + game.m_paddle.size.x *= 1.5; } +EnlargePaddleBonus::~EnlargePaddleBonus() {} +/* + * ShrinkPaddleBonus + * */ +void ShrinkPaddleBonus::draw(sf::RenderWindow& window) const +{ + static sf::CircleShape shape(radius); + shape.setOrigin(radius, radius); + shape.setFillColor(sf::Color{100, 200, 100}); + shape.setPosition(m_position); + window.draw(shape); + + static sf::RectangleShape rect(sf::Vector2f{radius, radius / 2}); + rect.setFillColor(sf::Color::Red); + rect.setPosition(m_position - sf::Vector2f{radius /2, radius / 4}); + window.draw(rect); +} +void ShrinkPaddleBonus::activate(Arkanoid& game) +{ + game.m_paddle.size.x *= 0.8; +} + +ShrinkPaddleBonus::~ShrinkPaddleBonus() {} + +/* + * SlowingBonus + * */ + +void SlowingBonus::draw(sf::RenderWindow& window) const +{ + static sf::CircleShape shape(radius); + shape.setOrigin(radius, radius); + shape.setFillColor(sf::Color{100, 200, 100}); + shape.setPosition(m_position); + window.draw(shape); + + /*static sf::RectangleShape rect(sf::Vector2f{radius, radius / 2}); + rect.setFillColor(sf::Color::Red); + rect.setPosition(m_position - sf::Vector2f{radius /2, radius / 4}); + window.draw(rect);*/ +} +void SlowingBonus::activate(Arkanoid& game) +{ + game.m_effects.push_back(new SlowingEffect(game.m_time, 10)); + game.m_effects.back()->activate(game); +} + +SlowingBonus::~SlowingBonus() {} + +/* + * Effects + * */ + +Effect::Effect(double start_time, double duration) : mStartTime(start_time), mDuration(duration) {}; + +bool Effect::isExpired(double time) { + if (mStartTime + mDuration > time) + return false; + return true; +} + +SlowingEffect::SlowingEffect(double start_time, double duration) : Effect(start_time, duration) {}; + +void SlowingEffect::activate(Arkanoid& game) { + std::cout << "Activated slow motion" << std::endl; + for (Ball& ball : game.m_balls) + { + //std::cout << "meow" << std::endl; + if (!(ball.affectedBy & 0b00000001)) { + ball.affectedBy |= 0b00000001; + ball.velocity = sf::Vector2f{ball.velocity.x * mSlowingFactor, ball.velocity.y * mSlowingFactor}; + } + } +} +void SlowingEffect::deactivate(Arkanoid& game) { + std::cout << "Deactivated slow motion" << std::endl; + for (Ball& ball : game.m_balls) + { + if (ball.affectedBy & 0b00000001) { + ball.velocity = sf::Vector2f{ball.velocity.x / mSlowingFactor, ball.velocity.y / mSlowingFactor}; + ball.affectedBy &= 0b11111110; + } + } +} diff --git a/seminar13_polymorphism/arkanoid/bonus.hpp b/seminar13_polymorphism/arkanoid/bonus.hpp index 221e4c5..3333330 100644 --- a/seminar13_polymorphism/arkanoid/bonus.hpp +++ b/seminar13_polymorphism/arkanoid/bonus.hpp @@ -7,7 +7,7 @@ class Arkanoid; class Bonus { -private: +protected: inline static const float speed = 120; inline static const float radius = 15; @@ -17,11 +17,69 @@ private: public: Bonus(sf::Vector2f position); void update(float dt); - void draw(sf::RenderWindow& window) const; - void activate(Arkanoid& game); + virtual void draw(sf::RenderWindow& window) const {}; + virtual void activate(Arkanoid& game){}; + virtual ~Bonus(){}; bool isColiding(const Paddle& paddle) const; // Класс Arkanoid должен быть дружественным, так как он может менять внутреннее объекта-бонуса friend class Arkanoid; }; +class TripleBallBonus : public Bonus { +public: + TripleBallBonus(sf::Vector2f position): Bonus(position) {}; + void draw(sf::RenderWindow& window) const; + void activate(Arkanoid& game); + ~TripleBallBonus(); +}; + +class EnlargePaddleBonus : public Bonus { +public: + EnlargePaddleBonus(sf::Vector2f position): Bonus(position) {}; + void draw(sf::RenderWindow& window) const; + void activate(Arkanoid& game); + ~EnlargePaddleBonus(); +}; + +class ShrinkPaddleBonus : public Bonus { +public: + ShrinkPaddleBonus(sf::Vector2f position): Bonus(position) {}; + void draw(sf::RenderWindow& window) const; + void activate(Arkanoid& game); + ~ShrinkPaddleBonus(); +}; + +class SlowingBonus : public Bonus { +private: + double mDuration = 10; +public: + SlowingBonus(sf::Vector2f position): Bonus(position) {}; + void draw(sf::RenderWindow& window) const; + void activate(Arkanoid& game); + ~SlowingBonus(); +}; + +/* + * Effects + * */ + +class Effect { +private: + double mStartTime; + double mDuration; +public: + Effect(double start_time, double duration); + virtual void activate(Arkanoid& game) {}; + virtual void deactivate(Arkanoid& game) {}; + bool isExpired(double time); +}; + +class SlowingEffect : public Effect { +private: + double mSlowingFactor = 0.1; +public: + SlowingEffect(double start_time, double duration); + void activate(Arkanoid& game); + void deactivate(Arkanoid& game); +}; diff --git a/seminar13_polymorphism/arkanoid/main.cpp b/seminar13_polymorphism/arkanoid/main.cpp index 4b41495..705383f 100644 --- a/seminar13_polymorphism/arkanoid/main.cpp +++ b/seminar13_polymorphism/arkanoid/main.cpp @@ -46,7 +46,7 @@ int main () while (window.isOpen()) { float dt = clock.restart().asSeconds(); - std::cout << "FPS=" << static_cast(1.0 / dt) << "\n"; + //std::cout << "FPS=" << static_cast(1.0 / dt) << "\n"; // Обработка событий sf::Event event;