seminar13 - arkanoid, even more to do

master
nihonium 2 years ago
parent a8bfa80d23
commit a6b1bccd37
No known key found for this signature in database
GPG Key ID: 0251623741027CFC

@ -2,6 +2,7 @@
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include <list> #include <list>
#include <cmath> #include <cmath>
#include <iostream>
#include "arkanoid.hpp" #include "arkanoid.hpp"
#include "bonus.hpp" #include "bonus.hpp"
@ -15,7 +16,19 @@ void Arkanoid::addRandomBonus(sf::Vector2f position)
int max_rand = 10000; int max_rand = 10000;
if ((rand() % max_rand) * 1.0f / max_rand < m_bonusProbability) 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) void Arkanoid::draw(sf::RenderWindow& window)

@ -5,10 +5,11 @@
#include "brick_grid.hpp" #include "brick_grid.hpp"
#include "paddle.hpp" #include "paddle.hpp"
class Bonus; class Bonus;
class Effect;
class Arkanoid class Arkanoid
{ {
private: protected:
// Константы: // Константы:
// Цвет задника // Цвет задника
const sf::Color kBackgroundColor {12, 31, 47}; const sf::Color kBackgroundColor {12, 31, 47};
@ -40,6 +41,7 @@ private:
// Почему указатели - для реализации полиформизма // Почему указатели - для реализации полиформизма
// Так как в будущем мы хотим сделать несколько вариантов бонусов // Так как в будущем мы хотим сделать несколько вариантов бонусов
std::list<Bonus*> m_bonuses; std::list<Bonus*> m_bonuses;
std::list<Effect*> m_effects;
// Вероятность того, что при разрушении блока выпадет бонус // Вероятность того, что при разрушении блока выпадет бонус
float m_bonusProbability; float m_bonusProbability;
@ -75,4 +77,10 @@ public:
// Класс бонус должен быть дружественным, так как он может менять внутреннее состояние игры // Класс бонус должен быть дружественным, так как он может менять внутреннее состояние игры
friend class Bonus; 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 position;
sf::Vector2f velocity; 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); Ball(float radius, sf::Vector2f position, sf::Vector2f velocity);
void update(float dt); void update(float dt);

@ -1,28 +1,33 @@
#include <cmath> #include <cmath>
#include <iostream>
#include "bonus.hpp" #include "bonus.hpp"
#include "arkanoid.hpp" #include "arkanoid.hpp"
#include "ball.hpp" #include "ball.hpp"
#include "paddle.hpp" #include "paddle.hpp"
const double pi = 3.14159265358979323846;
Bonus::Bonus(sf::Vector2f position): m_position(position) Bonus::Bonus(sf::Vector2f position): m_position(position)
{ {
m_time = 0; m_time = 0;
} }
// Двигаем бонус
void Bonus::update(float dt) void Bonus::update(float dt)
{ {
m_time += dt; m_time += dt;
m_position.y += speed * dt; m_position.y += speed * dt;
} }
// Рисуем бонус bool Bonus::isColiding(const Paddle& paddle) const
void Bonus::draw(sf::RenderWindow& window) 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); static sf::CircleShape shape(radius);
shape.setOrigin(radius, radius); shape.setOrigin(radius, radius);
shape.setFillColor(sf::Color{100, 200, 100}); shape.setFillColor(sf::Color{100, 200, 100});
@ -30,49 +35,32 @@ void Bonus::draw(sf::RenderWindow& window) const
window.draw(shape); window.draw(shape);
float angle = 0; float angle = 0;
// Рисуем 3 шарика на этом круге
static Ball ball {5, {0, 0}, {0, 0}}; static Ball ball {5, {0, 0}, {0, 0}};
float ballRotationRadius = 7; float ballRotationRadius = 7;
ball.position = m_position + ballRotationRadius * sf::Vector2f(std::cos(angle), std::sin(angle)); ball.position = m_position + ballRotationRadius * sf::Vector2f(std::cos(angle), std::sin(angle));
ball.draw(window); 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.position = m_position + ballRotationRadius * sf::Vector2f(std::cos(angle), std::sin(angle));
ball.draw(window); 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.position = m_position + ballRotationRadius * sf::Vector2f(std::cos(angle), std::sin(angle));
ball.draw(window); ball.draw(window);
} }
void TripleBallBonus::activate(Arkanoid& game)
/*
Функция Bonus::activate
Применяем эффект бонуса (в данном случае - утроение шариков)
numBalls - Количество шариков до утроения
Шарики хранятся в связном списке m_balls
Так как мы работаем со связным списком, то придётся использовать итератор it
Проходим итератором по изначальным элементам списка и добавляем новые шарики в список
В данном случае простой цикл через итераторы не сработает, так как массив game.m_balls увеличивается в процессе выполнения цикла.
Внутри цикла выбираем случайный вектор скорости и добавляем шарик в список game.m_balls
Делаем то же самое для ещё одного шарика
В конце цикла переходим ко следующему шарику в списке, т.е. увеличивем итератор it
*/
void Bonus::activate(Arkanoid& game)
{ {
int numBalls = game.m_balls.size(); int numBalls = game.m_balls.size();
std::list<Ball>::iterator it = game.m_balls.begin(); std::list<Ball>::iterator it = game.m_balls.begin();
for (int i = 0; i < numBalls; i++) 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 vx = Ball::initialVelocity * sin(angle);
float vy = Ball::initialVelocity * cos(angle); float vy = Ball::initialVelocity * cos(angle);
game.addBall({game.m_initialBall.radius, (*it).position, {vx, vy}}); 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); vx = Ball::initialVelocity * sin(angle);
vy = Ball::initialVelocity * cos(angle); vy = Ball::initialVelocity * cos(angle);
game.addBall({game.m_initialBall.radius, (*it).position, {vx, vy}}); 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}); static sf::CircleShape shape(radius);
return result; 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 class Bonus
{ {
private: protected:
inline static const float speed = 120; inline static const float speed = 120;
inline static const float radius = 15; inline static const float radius = 15;
@ -17,11 +17,69 @@ private:
public: public:
Bonus(sf::Vector2f position); Bonus(sf::Vector2f position);
void update(float dt); void update(float dt);
void draw(sf::RenderWindow& window) const; virtual void draw(sf::RenderWindow& window) const {};
void activate(Arkanoid& game); virtual void activate(Arkanoid& game){};
virtual ~Bonus(){};
bool isColiding(const Paddle& paddle) const; bool isColiding(const Paddle& paddle) const;
// Класс Arkanoid должен быть дружественным, так как он может менять внутреннее объекта-бонуса // Класс Arkanoid должен быть дружественным, так как он может менять внутреннее объекта-бонуса
friend class 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()) while (window.isOpen())
{ {
float dt = clock.restart().asSeconds(); 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; sf::Event event;