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