seminar13 - arkanoid, even more to do
This commit is contained in:
		
							parent
							
								
									a8bfa80d23
								
							
						
					
					
						commit
						a6b1bccd37
					
				
					 6 changed files with 257 additions and 71 deletions
				
			
		|  | @ -2,6 +2,7 @@ | |||
| #include <SFML/Graphics.hpp> | ||||
| #include <list> | ||||
| #include <cmath> | ||||
| #include <iostream> | ||||
| 
 | ||||
| #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) | ||||
|  |  | |||
|  | @ -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<Bonus*> m_bonuses; | ||||
|     std::list<Effect*> 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; | ||||
| }; | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -1,91 +1,181 @@ | |||
| #include <cmath> | ||||
| #include <iostream> | ||||
| 
 | ||||
| #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 | ||||
| { | ||||
|     // Рисуем белый круг
 | ||||
|     static sf::CircleShape shape(radius); | ||||
|     shape.setOrigin(radius, radius); | ||||
|     shape.setFillColor(sf::Color{100, 200, 100}); | ||||
|     shape.setPosition(m_position); | ||||
|     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; | ||||
|     ball.position = m_position + ballRotationRadius * sf::Vector2f(std::cos(angle), std::sin(angle)); | ||||
|     ball.draw(window); | ||||
|     angle += 2.0 * 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) | ||||
| { | ||||
|     int numBalls = game.m_balls.size(); | ||||
|     std::list<Ball>::iterator it = game.m_balls.begin(); | ||||
| 
 | ||||
|     for (int i = 0; i < numBalls; i++) | ||||
|     { | ||||
|         float angle = rand() % 1000 * (2 * 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); | ||||
|         vx = Ball::initialVelocity * sin(angle); | ||||
|         vy = Ball::initialVelocity * cos(angle); | ||||
|         game.addBall({game.m_initialBall.radius, (*it).position, {vx, vy}}); | ||||
| 
 | ||||
|         it++; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 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}); | ||||
|     shape.setPosition(m_position); | ||||
|     window.draw(shape); | ||||
| 
 | ||||
|     float angle = 0; | ||||
| 
 | ||||
|     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 * M_PI / 3.0; | ||||
|     ball.position = m_position + ballRotationRadius * sf::Vector2f(std::cos(angle), std::sin(angle)); | ||||
|     ball.draw(window); | ||||
|     angle += 2.0 * M_PI / 3.0; | ||||
|     ball.position = m_position + ballRotationRadius * sf::Vector2f(std::cos(angle), std::sin(angle)); | ||||
|     ball.draw(window); | ||||
| } | ||||
| 
 | ||||
| void TripleBallBonus::activate(Arkanoid& game) | ||||
| { | ||||
|     int numBalls = game.m_balls.size(); | ||||
|     std::list<Ball>::iterator it = game.m_balls.begin(); | ||||
| 
 | ||||
|     for (int i = 0; i < numBalls; i++) | ||||
|     { | ||||
|         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 * M_PI / 1000); | ||||
|         vx = Ball::initialVelocity * sin(angle); | ||||
|         vy = Ball::initialVelocity * cos(angle); | ||||
|         game.addBall({game.m_initialBall.radius, (*it).position, {vx, vy}}); | ||||
| 
 | ||||
|         it++; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| TripleBallBonus::~TripleBallBonus() {} | ||||
| 
 | ||||
| /* 
 | ||||
|  * EnlargePaddleBonus  | ||||
|  * */ | ||||
| void EnlargePaddleBonus::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::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; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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);  | ||||
| }; | ||||
|  |  | |||
|  | @ -46,7 +46,7 @@ int main () | |||
|     while (window.isOpen())  | ||||
|     { | ||||
|         float dt = clock.restart().asSeconds(); | ||||
|         std::cout << "FPS=" << static_cast<int>(1.0 / dt) << "\n";  | ||||
|         //std::cout << "FPS=" << static_cast<int>(1.0 / dt) << "\n"; 
 | ||||
| 
 | ||||
|         // Обработка событий
 | ||||
|         sf::Event event; | ||||
|  |  | |||
		Reference in a new issue