diff --git a/assets/background.png b/assets/background.png new file mode 100644 index 0000000000000000000000000000000000000000..293c583a364b338c632c542ac4fd7f5cc2574333 Binary files /dev/null and b/assets/background.png differ diff --git a/assets/enemy.png b/assets/enemy.png new file mode 100644 index 0000000000000000000000000000000000000000..ca29ac8f827e0414a9c13c7770ab74ab931f0f76 Binary files /dev/null and b/assets/enemy.png differ diff --git a/assets/grusha.png b/assets/grusha.png new file mode 100644 index 0000000000000000000000000000000000000000..803b81e1713fd23d1932abb069dadbb7ec3bea53 Binary files /dev/null and b/assets/grusha.png differ diff --git a/assets/pacman.png b/assets/pacman.png deleted file mode 100644 index 707389317bfe6573ce3529699370fc9efb33f929..0000000000000000000000000000000000000000 Binary files a/assets/pacman.png and /dev/null differ diff --git a/assets/pacmanDown.png b/assets/pacmanDown.png index 18d63290bb82e97f70b629c745b29e4f8f443d5b..6c3a8fe058f819e640bf475bcaed641a1a37615f 100644 Binary files a/assets/pacmanDown.png and b/assets/pacmanDown.png differ diff --git a/assets/pacmanDown2.png b/assets/pacmanDown2.png new file mode 100644 index 0000000000000000000000000000000000000000..9aca1583555f659045c63dc78c0a15ca514a3f34 Binary files /dev/null and b/assets/pacmanDown2.png differ diff --git a/assets/pacmanLeft.png b/assets/pacmanLeft.png index cfad9cd3a0718cf3fe8a89621fe84d0254911c10..09d1c808f0d430262c58ccaafd5abcc256625f52 100644 Binary files a/assets/pacmanLeft.png and b/assets/pacmanLeft.png differ diff --git a/assets/pacmanLeft2.png b/assets/pacmanLeft2.png new file mode 100644 index 0000000000000000000000000000000000000000..e0c1e59108ce3c4431884b0ba9e6d84b4e20c809 Binary files /dev/null and b/assets/pacmanLeft2.png differ diff --git a/assets/pacmanRight.png b/assets/pacmanRight.png index 9613050a23c47f95d5e51ed3bcf44514e85e68ad..3128093327d4f6ab3c7a6c9ecb2ba9c0077b3c72 100644 Binary files a/assets/pacmanRight.png and b/assets/pacmanRight.png differ diff --git a/assets/pacmanRight2.png b/assets/pacmanRight2.png new file mode 100644 index 0000000000000000000000000000000000000000..cb0b059c58a5bec23990d9e3d7ef0a14318d79a7 Binary files /dev/null and b/assets/pacmanRight2.png differ diff --git a/assets/pacmanUp.png b/assets/pacmanUp.png index 62ba3dcdcaed1efe5e18561316b57dd2f7b39b95..cd3d7349be3bf7f6eae99ab5719518c4fa9b0cc3 100644 Binary files a/assets/pacmanUp.png and b/assets/pacmanUp.png differ diff --git a/assets/pacmanUp2.png b/assets/pacmanUp2.png new file mode 100644 index 0000000000000000000000000000000000000000..da4847a0cff9c2059ae5e01dd633571760811b3c Binary files /dev/null and b/assets/pacmanUp2.png differ diff --git a/config.h b/config.h index b366881ca7f21e585e61b8e166d4eb07b812ef4d..4c90126b2ff5d8788cddea1eb366777b141940d2 100644 --- a/config.h +++ b/config.h @@ -8,16 +8,27 @@ namespace config { const sf::Vector2f BUTTON_SIZE = { 250, 100 }; const size_t BUTTON_FONT_SIZE = static_cast<size_t>(BUTTON_SIZE.y / 1.5f); const float BUTTON_FRAME_THICKNESS = 2.0f; const char FONT_FILE[] = "Calibri.ttf"; - const char SELECT_LEVEL_TITLE[] = "Select Level"; - const sf::VideoMode SELECT_LEVEL_VIDEO_MODE{ 400, 600 }; + const char SELECT_LEVEL_TITLE_WINDOW[] = "Settings"; + const char SELECT_LEVEL_TITLE[] = "Select Level:"; + const char SELECT_LEVEL_TITLE_PLAYER[] = "Select Player:"; + const char SELECT_THEME[] = "Select Theme:"; + const char BUTTON_THEME_WHITE[] = "Theme: White"; + const char BUTTON_THEME_BLACK[] = "Theme: Black"; + const sf::VideoMode SELECT_LEVEL_VIDEO_MODE{ 1138, 620 }; const std::vector<std::string> BUTTON_TEXT = {"Easy","Medium", "Hard", "Exit"}; const char BUTTON_TEXT_EASY[] = "Easy"; const char BUTTON_TEXT_MEDIUM[] = "Medium"; const char BUTTON_TEXT_HARD[] = "Hard"; const char BUTTON_TEXT_EXIT[] = "Exit"; // РРіСЂР°: - const sf::VideoMode GAME_VIDEO_MODE{ 880, 620 }; + const sf::VideoMode GAME_VIDEO_MODE{ 1138, 620 }; + const float MENU_WIDTH = GAME_VIDEO_MODE.width / 4; + const float SCREEN_HEIGHT = GAME_VIDEO_MODE.height; + const float GAME_WIDTH = GAME_VIDEO_MODE.width - MENU_WIDTH; + const char BUTTON_START_GAME[] = "Start Game"; const char EASY_GAME_TITLE[] = "Level: Easy"; + const char ONE_PLAYER_GAME_TITLE[] = "Player: One"; + const char TWO_PLAYER_GAME_TITLE[] = "Player: Two"; const char MEDIUM_GAME_TITLE[] = "Level: Medium"; const char HARD_GAME_TITLE[] = "Level: Hard"; const float EASY_GAME_ENEMY_RATIO = 0.0f; diff --git a/source/application/BobBuilder/BobBuilderDirector.cpp b/source/application/BobBuilder/BobBuilderDirector.cpp index 09d49f1591d56ffe9f4e455a9e2560f1b49524e8..9f1d9eae701d7f381df697c67d419d5b51bc38c1 100644 --- a/source/application/BobBuilder/BobBuilderDirector.cpp +++ b/source/application/BobBuilder/BobBuilderDirector.cpp @@ -12,11 +12,11 @@ GameBuilderDirector::GameBuilderDirector(std::unique_ptr<IGameBuilder> &&ptr_bui m_ptr_builder(std::move(ptr_builder)) { } -std::unique_ptr<GameState> GameBuilderDirector::build(IStateManager &state_manager) { +std::unique_ptr<GameState> GameBuilderDirector::build(IStateManager &state_manager, int players) { m_ptr_builder->create_rooms(); m_ptr_builder->set_rooms_sides(); - m_ptr_builder->create_context(m_dynamic_object_ratio); + m_ptr_builder->create_context(m_dynamic_object_ratio, players); m_ptr_builder->create_state(state_manager, m_mode, m_window_title); m_ptr_builder->set_all_to_state(); return m_ptr_builder->get_game(); -} \ No newline at end of file +} diff --git a/source/application/BobBuilder/BobBuilderDirector.h b/source/application/BobBuilder/BobBuilderDirector.h index f52a9998652240fa41c20cf149c4deacd930e2c1..6a963898658e84242ec93f9ecd606502431a8228 100644 --- a/source/application/BobBuilder/BobBuilderDirector.h +++ b/source/application/BobBuilder/BobBuilderDirector.h @@ -4,7 +4,7 @@ class GameBuilderDirector { public: GameBuilderDirector(std::unique_ptr<IGameBuilder>&& ptr_builder, sf::VideoMode mode, std::string window_title, float dynamic_objects_ratio); - std::unique_ptr<GameState> build(IStateManager& state_manager); + std::unique_ptr<GameState> build(IStateManager& state_manager, int players); private: std::string m_window_title; diff --git a/source/application/BobBuilder/GameBuilders.cpp b/source/application/BobBuilder/GameBuilders.cpp index 9961971cb71888c60b52e7eab78e3dfbcdbf56b2..e38d03cb56a274d630111cdf924450e47f4739c5 100644 --- a/source/application/BobBuilder/GameBuilders.cpp +++ b/source/application/BobBuilder/GameBuilders.cpp @@ -4,22 +4,23 @@ CommonBuilder::CommonBuilder(float width, float height, float room_size) : m_width(width), m_height(height), m_room_size(room_size){ } -void CommonBuilder::create_context(float dynamic_objects_ratio) { +void CommonBuilder::create_context(float dynamic_objects_ratio, int players) { std::vector<Room*> empty_rooms_buffer; for (auto& row : m_rooms) for (auto& room : row) if (room != nullptr) empty_rooms_buffer.emplace_back(room); - - float id = std::rand() % empty_rooms_buffer.size(); //РІ рандомное место располагаем пакмана + float id = std::rand() % empty_rooms_buffer.size(); m_context.pacman.set_location(empty_rooms_buffer[id]); auto it = std::next(empty_rooms_buffer.begin(), id); empty_rooms_buffer.erase(it); - float id2 = std::rand() % empty_rooms_buffer.size(); - m_context.pacman2.set_location(empty_rooms_buffer[id2]); - auto it2 = std::next(empty_rooms_buffer.begin(), id2); - empty_rooms_buffer.erase(it2); + if (players == 2) { + float id2 = std::rand() % empty_rooms_buffer.size(); + m_context.pacman2.set_location(empty_rooms_buffer[id2]); + auto it2 = std::next(empty_rooms_buffer.begin(), id2); + empty_rooms_buffer.erase(it2); + } //располагаем врагов size_t rooms_row = static_cast<size_t>(m_width / m_room_size); @@ -62,14 +63,14 @@ std::unique_ptr<GameState> CommonBuilder::get_game() { void SimpleBuilder::create_rooms() { size_t rows = m_height / m_room_size; - size_t cols = m_width / m_room_size; + size_t cols = config::GAME_WIDTH / m_room_size; int room_size = static_cast<int>(m_room_size); - sf::Vector2f left_pos = sf::Vector2f{ (m_width - m_room_size * cols + m_room_size)/2, (m_height - m_room_size * rows + m_room_size)/2}; + sf::Vector2f left_pos = sf::Vector2f{ config::MENU_WIDTH, (m_height - m_room_size * rows + m_room_size)/2}; for (int row = 0; row < rows * room_size; row += room_size) { std::vector<Room*> row_vec; for (size_t col = 0; col < cols * room_size; col += room_size) { Room* room = new Room(m_room_size); - room->set_position({col + left_pos.x, row + left_pos.y}); + room->set_position({config::MENU_WIDTH + col, row + left_pos.y}); row_vec.emplace_back(room); } m_rooms.emplace_back(std::move(row_vec)); @@ -78,7 +79,7 @@ void SimpleBuilder::create_rooms() { void SimpleBuilder::set_rooms_sides() { for (size_t i = 0; i < m_rooms.size(); i++) { - for (size_t j = 0; j < m_rooms.begin()->size(); j++) { + for (size_t j = 0; j < m_rooms[i].size(); j++) { if (i == 0) { auto up_wall = std::make_shared<Wall>(*m_rooms[i][j]); m_rooms[i][j]->set_side(Room::UP, std::move(up_wall)); @@ -112,10 +113,10 @@ void SimpleBuilder::set_rooms_sides() { void ComplexBuilder::create_rooms() { size_t room_quantity_row = (m_height / m_room_size); - size_t room_quantity_col = (m_width / m_room_size); + size_t room_quantity_col = config::GAME_WIDTH / m_room_size; int room_size = static_cast<int>(m_room_size); - auto starting_point = sf::Vector2f{(m_width - m_room_size*room_quantity_col)/2 + m_room_size/2, (m_height - m_room_size*room_quantity_row)/2 + + m_room_size/2}; + auto starting_point = sf::Vector2f{config::MENU_WIDTH, (m_height - m_room_size*room_quantity_row)/2 + + m_room_size/2}; for (int row = 0; row < room_quantity_row * room_size; row += room_size) { std::vector<Room*> vector_row; diff --git a/source/application/BobBuilder/GameBuilders.h b/source/application/BobBuilder/GameBuilders.h index cb4bdeffa7e9237f20aae888c3ce3bc07addeb62..fea5da2576c67322d23d5c4a96032b3c3d003c4b 100644 --- a/source/application/BobBuilder/GameBuilders.h +++ b/source/application/BobBuilder/GameBuilders.h @@ -6,7 +6,7 @@ class CommonBuilder : public IGameBuilder { public: CommonBuilder(float width, float height, float room_size); - void create_context(float dynamic_objects_ratio) override; + void create_context(float dynamic_objects_ratio, int players) override; void create_state(IStateManager& state_manager, const sf::VideoMode& mode, const std::string& window_title) override; void set_all_to_state() override; std::unique_ptr<GameState> get_game() override; diff --git a/source/application/BobBuilder/IGameBuilder.h b/source/application/BobBuilder/IGameBuilder.h index 4f7b9d6b3fd027d83f3bc22ade5e6dcfeea4f965..84ac8ca9a968ea0ae22a4a7d032190946a95852f 100644 --- a/source/application/BobBuilder/IGameBuilder.h +++ b/source/application/BobBuilder/IGameBuilder.h @@ -6,7 +6,7 @@ class IGameBuilder { public: virtual void create_rooms() = 0; virtual void set_rooms_sides() = 0; - virtual void create_context(float dynamic_objects_ratio) = 0; + virtual void create_context(float dynamic_objects_ratio, int players) = 0; virtual void create_state(IStateManager& state_manager, const sf::VideoMode& mode, const std::string& window_title) = 0; virtual void set_all_to_state() = 0; virtual std::unique_ptr<GameState> get_game() = 0; diff --git a/source/application/Context/Context.cpp b/source/application/Context/Context.cpp index a1c3ab6078e4489df3c1ebb98fd52c4e4afe6e09..585b52c618d44546323375bfc6bb203f890c6e34 100644 --- a/source/application/Context/Context.cpp +++ b/source/application/Context/Context.cpp @@ -1,5 +1,12 @@ #include "Context.h" +GameContext::GameContext() + : pacman(&PacmanTexture::instance()), + pacman2(&PacmanTexture2::instance()), + static_objects(), + dynamic_objects() +{} + GameContext GameContext::clone() { GameContext context; context.pacman = pacman; diff --git a/source/application/Context/Context.h b/source/application/Context/Context.h index b6269d8d1a668a346b98c53f85b9f394565d1a66..a9a024f4143c6d4fce4155a52e5bd4b355c90d02 100644 --- a/source/application/Context/Context.h +++ b/source/application/Context/Context.h @@ -5,9 +5,11 @@ #include <list> struct GameContext { + GameContext(); enum State { INGAME, WIN, LOST } state = INGAME; std::list<std::unique_ptr<IDynamicEntity>> dynamic_objects; std::list<std::unique_ptr<IStaticEntity>> static_objects; + Pacman pacman; Pacman pacman2; GameContext clone(); diff --git a/source/application/Drawable/DrawMenu/Button/Button.cpp b/source/application/Drawable/DrawMenu/Button/Button.cpp index 1f3c0b05b46b5f30e05a6a5668922f1b2fd688d5..d7d5c76206dfb68609de62987a1e3b95a6e3c00c 100644 --- a/source/application/Drawable/DrawMenu/Button/Button.cpp +++ b/source/application/Drawable/DrawMenu/Button/Button.cpp @@ -1,27 +1,33 @@ #include "Button.h" #include "../../../../../config.h" #include "../Font/Font.h" +#include "../../../State/ThemeManager.h" Button::Button(sf::Vector2f pos, sf::Vector2f button_size, - const std::string& text, size_t font_size, - std::unique_ptr<ISelectCommand> ptr_command) { + const std::string& text, size_t font_size, + std::unique_ptr<ISelectCommand> ptr_command) { + m_rectangle.setSize(button_size); m_rectangle.setPosition(pos); - m_rectangle.setFillColor(config::BUTTON_COLOR_FILL); - m_rectangle.setOutlineColor(config::BUTTON_COLOR_FRAME); - m_rectangle.setOutlineThickness(config::BUTTON_FRAME_THICKNESS); + m_rectangle.setOutlineColor(ThemeManager::Instance().getButtonOutlineColor()); + m_rectangle.setOutlineThickness(2.f); + m_text = sf::Text(text, MyFont::Instance(), font_size); - m_text.setFillColor(config::BUTTON_COLOR_TEXT); - m_text.setPosition(pos); + m_text.setFillColor(ThemeManager::Instance().getButtonTextColor()); + sf::FloatRect textRect = m_text.getLocalBounds(); + m_text.setPosition(pos.x + (button_size.x - textRect.width) / 2.0f - textRect.left, pos.y + (button_size.y - textRect.height) / 2.0f - textRect.top); + m_rectangle.setFillColor(ThemeManager::Instance().getButtonFillColor()); m_ptr_command = std::move(ptr_command); } void Button::select() { - m_rectangle.setFillColor(config::BUTTON_COLOR_SELECTION); + m_rectangle.setFillColor(ThemeManager::Instance().getButtonSelectionColor()); } + void Button::unselect() { - m_rectangle.setFillColor(config::BUTTON_COLOR_FILL); + m_rectangle.setFillColor(ThemeManager::Instance().getButtonFillColor()); } + bool Button::is_selected() const noexcept { return m_is_selected; } @@ -35,4 +41,32 @@ void Button::push() { void Button::draw_into(sf::RenderWindow& window) { window.draw(m_rectangle); window.draw(m_text); +} + +void ChooseButton::draw_into(sf::RenderWindow &window) { + window.draw(m_out_circle); + if (m_is_selected) window.draw(m_in_circle); + window.draw(m_text); +} + +bool ChooseButton::contains(sf::Vector2f point) const { + return m_out_circle.getGlobalBounds().contains(point) || m_text.getGlobalBounds().contains(point); +} + +ChooseButton::ChooseButton(sf::Vector2f pos, const std::string &text, size_t font_size) { + + m_out_circle.setRadius(10.f); + m_out_circle.setOutlineThickness(1.f); + m_out_circle.setOutlineColor(ThemeManager::Instance().getButtonOutlineColor()); + m_out_circle.setFillColor(sf::Color::Transparent); + m_out_circle.setPosition(pos); + + m_in_circle.setRadius(6.f); + m_in_circle.setFillColor(sf::Color::Blue); + m_in_circle.setPosition(pos.x + 4.f, pos.y + 4.f); + m_in_circle.setOutlineThickness(0); + + m_text = sf::Text(text, MyFont::Instance(), font_size); + m_text.setFillColor(ThemeManager::Instance().getButtonTextColor()); + m_text.setPosition(pos.x + 40.f, pos.y - 5.f); } \ No newline at end of file diff --git a/source/application/Drawable/DrawMenu/Button/Button.h b/source/application/Drawable/DrawMenu/Button/Button.h index eb39b81802f95bb3e16aa4443b5b3b60dc24394a..a580dd8ee1738d65e9b626c5079412a8bebe1d9d 100644 --- a/source/application/Drawable/DrawMenu/Button/Button.h +++ b/source/application/Drawable/DrawMenu/Button/Button.h @@ -23,4 +23,19 @@ private: bool m_is_selected = false; sf::RectangleShape m_rectangle; std::unique_ptr<ISelectCommand> m_ptr_command; +}; + +class ChooseButton : public IDrawable { +public: + ChooseButton(sf::Vector2f pos, const std::string& text, size_t font_size); + void select() { m_is_selected = true; } + void unselect() { m_is_selected = false; } + bool is_selected() const noexcept { return m_is_selected; } + bool contains(sf::Vector2f point) const; + void draw_into(sf::RenderWindow& window) override; +private: + sf::Text m_text; + bool m_is_selected = false; + sf::CircleShape m_out_circle; + sf::CircleShape m_in_circle; }; \ No newline at end of file diff --git a/source/application/Drawable/DrawMenu/Menu/Menu.cpp b/source/application/Drawable/DrawMenu/Menu/Menu.cpp index 931444dc56f3cd1ceb19d2e28c166268b74d9e38..34cdbf24b11428b9a21cb5602f64403daab10067 100644 --- a/source/application/Drawable/DrawMenu/Menu/Menu.cpp +++ b/source/application/Drawable/DrawMenu/Menu/Menu.cpp @@ -1,56 +1,167 @@ #include "Menu.h" #include "../../../../../config.h" #include "../../../BobBuilder/GameBuilders.h" +#include "../../../State/ThemeManager.h" +#include "../Font/Font.h" #include <memory> -Menu::Menu(IStateManager& state_manager) { - float delta = 20; - sf::Vector2f starting_position(80,5); - auto easy_director = std::make_unique<GameBuilderDirector>( +Menu::Menu(IStateManager& state_manager) : m_state_manager(state_manager) { + m_directors.push_back(std::make_unique<GameBuilderDirector>( std::make_unique<SimpleBuilder>( config::GAME_VIDEO_MODE.width, config::GAME_VIDEO_MODE.height, config::ROOM_SIZE), config::GAME_VIDEO_MODE, config::EASY_GAME_TITLE, - config::EASY_GAME_ENEMY_RATIO); - auto medium_director = std::make_unique<GameBuilderDirector>( + config::EASY_GAME_ENEMY_RATIO)); + m_directors.push_back(std::make_unique<GameBuilderDirector>( std::make_unique<SimpleBuilder>( config::GAME_VIDEO_MODE.width, config::GAME_VIDEO_MODE.height, config::ROOM_SIZE), config::GAME_VIDEO_MODE, config::MEDIUM_GAME_TITLE, - config::MEDIUM_GAME_ENEMY_RATIO); - auto hard_director = std::make_unique<GameBuilderDirector>( + config::MEDIUM_GAME_ENEMY_RATIO)); + m_directors.push_back(std::make_unique<GameBuilderDirector>( std::make_unique<ComplexBuilder>( config::GAME_VIDEO_MODE.width, config::GAME_VIDEO_MODE.height, config::ROOM_SIZE), config::GAME_VIDEO_MODE, config::HARD_GAME_TITLE, - config::HARD_GAME_ENEMY_RATIO); + config::HARD_GAME_ENEMY_RATIO)); - auto easy_command = std::make_unique<GameCommand>(state_manager, std::move(easy_director)); - auto medium_command = std::make_unique<GameCommand>(state_manager, std::move(medium_director)); - auto hard_command = std::make_unique<GameCommand>(state_manager, std::move(hard_director)); - auto exit_command = std::make_unique<ExitCommand>(state_manager); + m_choose_button.push_back(std::make_unique<ChooseButton>(sf::Vector2f(400.f, 130.f), config::EASY_GAME_TITLE, 24)); + m_choose_button.push_back(std::make_unique<ChooseButton>(sf::Vector2f(400.f, 170.f), config::MEDIUM_GAME_TITLE, 24)); + m_choose_button.push_back(std::make_unique<ChooseButton>(sf::Vector2f(400.f, 210.f), config::HARD_GAME_TITLE, 24)); - m_buttons.emplace_back(std::make_unique<Button>(sf::Vector2f{starting_position.x, starting_position.y + 1 * config::BUTTON_SIZE.y + 0 * delta}, config::BUTTON_SIZE, config::BUTTON_TEXT_EASY, config::BUTTON_FONT_SIZE , std::move(easy_command))); - m_buttons.emplace_back(std::make_unique<Button>(sf::Vector2f{starting_position.x, starting_position.y + 2 * config::BUTTON_SIZE.y + 1 * delta}, config::BUTTON_SIZE, config::BUTTON_TEXT_MEDIUM, config::BUTTON_FONT_SIZE , std::move(medium_command))); - m_buttons.emplace_back(std::make_unique<Button>(sf::Vector2f{starting_position.x, starting_position.y + 3 * config::BUTTON_SIZE.y + 2 * delta}, config::BUTTON_SIZE, config::BUTTON_TEXT_HARD, config::BUTTON_FONT_SIZE , std::move(hard_command))); - m_buttons.emplace_back(std::make_unique<Button>(sf::Vector2f{starting_position.x, starting_position.y + 4 * config::BUTTON_SIZE.y + 3 * delta}, config::BUTTON_SIZE, config::BUTTON_TEXT_EXIT, config::BUTTON_FONT_SIZE, std::move(exit_command))); -} + m_choose_button_players.push_back(std::make_unique<ChooseButton>(sf::Vector2f(400.f, 255.f), config::ONE_PLAYER_GAME_TITLE, 24)); + m_choose_button_players.push_back(std::make_unique<ChooseButton>(sf::Vector2f(400.f, 295.f), config::TWO_PLAYER_GAME_TITLE, 24)); -void Menu::draw_into(sf::RenderWindow &window) { - //@todo change to const Button& - for (auto& ptr_button : m_buttons) - ptr_button->draw_into(window); + m_choose_button_theme.push_back(std::make_unique<ChooseButton>(sf::Vector2f(400.f, 343.f), config::BUTTON_THEME_WHITE, 24)); + m_choose_button_theme.push_back(std::make_unique<ChooseButton>(sf::Vector2f(400.f, 383.f), config::BUTTON_THEME_BLACK, 24)); + m_choose_button_theme[m_selected_theme]->select(); + m_exit_button = std::make_unique<Button>(sf::Vector2f(900.f, 500.f), sf::Vector2f(150.f, 50.f), config::BUTTON_TEXT_EXIT, 24, std::make_unique<ExitCommand>(state_manager)); + m_proceed_button = std::make_unique<Button>(sf::Vector2f(450.f, 500.f), sf::Vector2f(150.f, 50.f), config::BUTTON_START_GAME, 24,nullptr); } -void Menu::process_mouse(const sf::Vector2f pos, bool is_pressed) { - for (auto& ptr_button : m_buttons) { - if (ptr_button->is_position_in(pos)) { - ptr_button->select(); - if (is_pressed) ptr_button->push(); +void Menu::process_mouse(sf::Vector2f pos, bool is_pressed) { + if (is_pressed) { + ///> выбор СѓСЂРѕРІРЅСЏ + for (size_t i = 0; i < m_choose_button.size(); i++) { + if (m_choose_button[i]->contains(pos)) { + for (auto& button : m_choose_button) + button->unselect(); + m_choose_button[i]->select(); + m_selected_level = i; + } + } + ///> exit + if (m_exit_button->is_position_in(pos)) + m_exit_button->push(); + ///> выбор количества РёРіСЂРѕРєРѕРІ + for (int i = 0; i < m_choose_button_players.size(); i++) { + if (m_choose_button_players[i]->contains(pos)) { + for (auto& button : m_choose_button_players) + button->unselect(); + m_choose_button_players[i]->select(); + m_selected_players = i; + } + } + ///> выбор темы приложения + for (int i = 0; i < m_choose_button_theme.size(); i++) { + if (m_choose_button_theme[i]->contains(pos)) { + for (auto& button : m_choose_button_theme) + button->unselect(); + m_choose_button_theme[i]->select(); + m_selected_theme = i; + if (i == 0) + ThemeManager::Instance().set_theme(ThemeManager::Theme::LIGHT); + else + ThemeManager::Instance().set_theme(ThemeManager::Theme::DARK); + break; + } + } + ///> создание команды РїСЂРё нажатии РЅР° go to game + if (m_selected_level >= 0 && m_proceed_button->is_position_in(pos)) { + auto command = std::make_unique<GameCommand>(m_state_manager, m_directors[m_selected_level], m_selected_players +1); + command->execute(); } - else ptr_button->unselect(); } -} \ No newline at end of file +} + +void Menu::draw_into(sf::RenderWindow &window) { + sf::Text title(config::SELECT_LEVEL_TITLE_WINDOW, MyFont::Instance(), 40); + title.setPosition(window.getSize().x/2.f-100.f, 50.f); + title.setFillColor(ThemeManager::Instance().getTitleTextColor()); + window.draw(title); + sf::Text title2(config::SELECT_LEVEL_TITLE, MyFont::Instance(), 30); + title2.setPosition(window.getSize().x/2.f-350.f, 120.f); + title2.setFillColor(ThemeManager::Instance().getTitleTextColor()); + window.draw(title2); + for (auto& button : m_choose_button) + button->draw_into(window); + sf::Text title3(config::SELECT_LEVEL_TITLE_PLAYER, MyFont::Instance(), 30); + title3.setPosition(window.getSize().x/2.f-350.f, 240.f); + title3.setFillColor(ThemeManager::Instance().getTitleTextColor()); + window.draw(title3); + for (auto& button : m_choose_button_players) + button->draw_into(window); + sf::Text title4(config::SELECT_THEME, MyFont::Instance(), 30); + title4.setPosition(window.getSize().x/2.f-350.f, 330.f); + title4.setFillColor(ThemeManager::Instance().getTitleTextColor()); + window.draw(title4); + for (auto& button : m_choose_button_theme) + button->draw_into(window); + m_proceed_button->draw_into(window); + m_exit_button->draw_into(window); +} + +//Menu::Menu(IStateManager& state_manager) { +// float delta = 20; +// sf::Vector2f starting_position(80,5); +// auto easy_director = std::make_unique<GameBuilderDirector>( +// std::make_unique<SimpleBuilder>( +// config::GAME_VIDEO_MODE.width, config::GAME_VIDEO_MODE.height, +// config::ROOM_SIZE), +// config::GAME_VIDEO_MODE, +// config::EASY_GAME_TITLE, +// config::EASY_GAME_ENEMY_RATIO); +// auto medium_director = std::make_unique<GameBuilderDirector>( +// std::make_unique<SimpleBuilder>( +// config::GAME_VIDEO_MODE.width, config::GAME_VIDEO_MODE.height, +// config::ROOM_SIZE), +// config::GAME_VIDEO_MODE, +// config::MEDIUM_GAME_TITLE, +// config::MEDIUM_GAME_ENEMY_RATIO); +// auto hard_director = std::make_unique<GameBuilderDirector>( +// std::make_unique<ComplexBuilder>( +// config::GAME_VIDEO_MODE.width, config::GAME_VIDEO_MODE.height, +// config::ROOM_SIZE), +// config::GAME_VIDEO_MODE, +// config::HARD_GAME_TITLE, +// config::HARD_GAME_ENEMY_RATIO); +// +// auto easy_command = std::make_unique<GameCommand>(state_manager, std::move(easy_director)); +// auto medium_command = std::make_unique<GameCommand>(state_manager, std::move(medium_director)); +// auto hard_command = std::make_unique<GameCommand>(state_manager, std::move(hard_director)); +// auto exit_command = std::make_unique<ExitCommand>(state_manager); +// +// m_buttons.emplace_back(std::make_unique<Button>(sf::Vector2f{starting_position.x, starting_position.y + 1 * config::BUTTON_SIZE.y + 0 * delta}, config::BUTTON_SIZE, config::BUTTON_TEXT_EASY, config::BUTTON_FONT_SIZE , std::move(easy_command))); +// m_buttons.emplace_back(std::make_unique<Button>(sf::Vector2f{starting_position.x, starting_position.y + 2 * config::BUTTON_SIZE.y + 1 * delta}, config::BUTTON_SIZE, config::BUTTON_TEXT_MEDIUM, config::BUTTON_FONT_SIZE , std::move(medium_command))); +// m_buttons.emplace_back(std::make_unique<Button>(sf::Vector2f{starting_position.x, starting_position.y + 3 * config::BUTTON_SIZE.y + 2 * delta}, config::BUTTON_SIZE, config::BUTTON_TEXT_HARD, config::BUTTON_FONT_SIZE , std::move(hard_command))); +// m_buttons.emplace_back(std::make_unique<Button>(sf::Vector2f{starting_position.x, starting_position.y + 4 * config::BUTTON_SIZE.y + 3 * delta}, config::BUTTON_SIZE, config::BUTTON_TEXT_EXIT, config::BUTTON_FONT_SIZE, std::move(exit_command))); +//} + +//void Menu::draw_into(sf::RenderWindow &window) { +// //@todo change to const Button& +// for (auto& ptr_button : m_buttons) +// ptr_button->draw_into(window); +//} + +//void Menu::process_mouse(sf::Vector2f pos, bool is_pressed) { +// for (auto& ptr_button : m_buttons) { +// if (ptr_button->is_position_in(pos)) { +// ptr_button->select(); +// if (is_pressed) ptr_button->push(); +// } +// else ptr_button->unselect(); +// } +//} \ No newline at end of file diff --git a/source/application/Drawable/DrawMenu/Menu/Menu.h b/source/application/Drawable/DrawMenu/Menu/Menu.h index 9cf8ced9c80f6ba38bc0a87f38898f970bf6cddc..8053a54dadc0b43206d8fecbcf65c3e71484bc42 100644 --- a/source/application/Drawable/DrawMenu/Menu/Menu.h +++ b/source/application/Drawable/DrawMenu/Menu/Menu.h @@ -8,9 +8,20 @@ class Menu : public IDrawable { public: Menu(IStateManager& state_manager); void draw_into(sf::RenderWindow& window) override; - void process_mouse(const sf::Vector2f pos, bool is_pressed); + void process_mouse(sf::Vector2f pos, bool is_pressed); private: sf::RectangleShape m_shape; + std::vector<std::unique_ptr<ChooseButton>> m_choose_button; + std::vector<std::unique_ptr<ChooseButton>> m_choose_button_players; + std::vector<std::unique_ptr<ChooseButton>> m_choose_button_theme; + std::unique_ptr<Button> m_proceed_button; + std::unique_ptr<Button> m_exit_button; + std::vector<std::unique_ptr<GameBuilderDirector>> m_directors; + int m_selected_level = -1; + int m_selected_players = -1; + int m_selected_theme = 0; + IStateManager& m_state_manager; std::vector<std::unique_ptr<Button>> m_buttons; //@todo vector changes to array<Button, 4> + }; \ No newline at end of file diff --git a/source/application/Drawable/Entity/MyTexture.cpp b/source/application/Drawable/Entity/MyTexture.cpp index 991d4a3229da6d03763eb1072781e6c83b21c7c1..5872eec0669ffa8e9b45c23cda6248d38ac475b3 100644 --- a/source/application/Drawable/Entity/MyTexture.cpp +++ b/source/application/Drawable/Entity/MyTexture.cpp @@ -1,5 +1,4 @@ #include "MyTexture.h" - PacmanTexture::PacmanTexture() { if (!m_texture_up.loadFromFile(std::string(ASSETS_PATH) + "pacmanUp.png")) throw std::runtime_error("Can't added Texture for Pacman"); @@ -11,6 +10,16 @@ PacmanTexture::PacmanTexture() { throw std::runtime_error("Can't added Texture for Pacman"); } +PacmanTexture2::PacmanTexture2() { + if (!m_texture_up.loadFromFile(std::string(ASSETS_PATH) + "pacmanUp2.png")) + throw std::runtime_error("Can't added Texture for Pacman"); + if (!m_texture_down.loadFromFile(std::string(ASSETS_PATH) + "pacmanDown2.png")) + throw std::runtime_error("Can't added Texture for Pacman"); + if (!m_texture_right.loadFromFile(std::string(ASSETS_PATH) + "pacmanRight2.png")) + throw std::runtime_error("Can't added Texture for Pacman"); + if (!m_texture_left.loadFromFile(std::string(ASSETS_PATH) + "pacmanLeft2.png")) + throw std::runtime_error("Can't added Texture for Pacman"); +} //РІ зависимости РѕС‚ направления - разные текстуры sf::Texture& PacmanTexture::get_texture() { switch (m_direction) { @@ -25,6 +34,19 @@ sf::Texture& PacmanTexture::get_texture() { } } +sf::Texture& PacmanTexture2::get_texture() { + switch (m_direction) { + case Direction::UP: + return m_texture_left; + case Direction::DOWN: + return m_texture_right; + case Direction::RIGHT: + return m_texture_up; + case Direction::LEFT: + return m_texture_down; + } +} + FoodTexture::FoodTexture() { if (!m_texture_food.loadFromFile(std::string(ASSETS_PATH) + "grusha.png")) throw std::runtime_error("Can't added Texture for food"); @@ -33,3 +55,7 @@ FoodTexture::FoodTexture() { EnemyTexture::EnemyTexture() { m_texture_enemy.loadFromFile(std::string(ASSETS_PATH) + "enemy.png"); } + +BackgroundTexture::BackgroundTexture() { + m_texture_background.loadFromFile(std::string(ASSETS_PATH) + "background.png"); +} \ No newline at end of file diff --git a/source/application/Drawable/Entity/MyTexture.h b/source/application/Drawable/Entity/MyTexture.h index 185e0cb92c1ce0d9558142be60991195f0f88b55..d1f9f5364599bd8142b0b030f63428b2f9c2af1f 100644 --- a/source/application/Drawable/Entity/MyTexture.h +++ b/source/application/Drawable/Entity/MyTexture.h @@ -24,6 +24,15 @@ private: sf::Texture m_texture_up, m_texture_down, m_texture_right, m_texture_left; }; +class PacmanTexture2 : public MyTexture { +public: + static PacmanTexture2& instance() { static PacmanTexture2 instance; return instance; } + sf::Texture& get_texture() override; +private: + PacmanTexture2(); + sf::Texture m_texture_up, m_texture_down, m_texture_right, m_texture_left; +}; + //texture for Food class FoodTexture : public MyTexture { public: @@ -43,3 +52,12 @@ private: EnemyTexture(); sf::Texture m_texture_enemy; }; + +class BackgroundTexture : public MyTexture { +public: + static BackgroundTexture& instance() { static BackgroundTexture instance; return instance; } + sf::Texture& get_texture() override { return m_texture_background; } +private: + BackgroundTexture(); + sf::Texture m_texture_background; +}; diff --git a/source/application/Drawable/Entity/Pacman.cpp b/source/application/Drawable/Entity/Pacman.cpp index 4a85c71c4cd1f1d45f6f2b37ac2637cc1c57062d..7bf09edbe16729d89f712a502210f51b9bea9d2a 100644 --- a/source/application/Drawable/Entity/Pacman.cpp +++ b/source/application/Drawable/Entity/Pacman.cpp @@ -1,9 +1,7 @@ #include "Pacman.h" #include "../../../../config.h" -Pacman::Pacman() { - set_texture(&PacmanTexture::instance()); -} +Pacman::Pacman(MyTexture* texture) : m_ptr_texture(texture) {} void Pacman::move(Room::Direction direction) { m_ptr_room->get_side(direction)->enter(this); diff --git a/source/application/Drawable/Entity/Pacman.h b/source/application/Drawable/Entity/Pacman.h index 1b041ffc472d7d188eb8b3db363ce33303361f89..9e06084a82719a64451a40a569f68ab8f3bc387e 100644 --- a/source/application/Drawable/Entity/Pacman.h +++ b/source/application/Drawable/Entity/Pacman.h @@ -6,7 +6,7 @@ class Pacman : public IEntity, public IVisitor { public: - Pacman(); + Pacman(MyTexture* texture); void move(Room::Direction direction); void prepare_for_drawing() override; void set_texture(MyTexture* ptr_texture) { m_ptr_texture = ptr_texture; } diff --git a/source/application/Drawable/Maze/IObserver.cpp b/source/application/Drawable/Maze/IObserver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bcc8581149d9e31e5dbc5bff62d1f2385aabf151 --- /dev/null +++ b/source/application/Drawable/Maze/IObserver.cpp @@ -0,0 +1,12 @@ + +#include "../../Event/IGameEvent.h" +#include "IObserver.h" + +void ScoreCount::on_notify(const IGameEvent& event) { + if (const auto* food_event = dynamic_cast<const DeleteStaticEntity*>(&event)) { + if (m_player == 1) + ++m_player_one_food; + else + ++m_player_two_food; + } +} \ No newline at end of file diff --git a/source/application/Drawable/Maze/IObserver.h b/source/application/Drawable/Maze/IObserver.h new file mode 100644 index 0000000000000000000000000000000000000000..a9102da8dcffa86b60042b008ab0f412982c97c4 --- /dev/null +++ b/source/application/Drawable/Maze/IObserver.h @@ -0,0 +1,23 @@ +#pragma once + +class IGameEvent; + +class IObserver { +public: + virtual ~IObserver() = default; + virtual void on_notify(const IGameEvent& event) = 0; +}; + + +class ScoreCount : public IObserver { +public: + ScoreCount(int player) : m_player(player) {} + void on_notify(const IGameEvent& event) override; + int get_player_one() const {return m_player_one_food; } + int get_player_two() const {return m_player_two_food; } + +private: + int m_player; + int m_player_one_food{0}; + int m_player_two_food{0}; +}; \ No newline at end of file diff --git a/source/application/Drawable/Maze/Maze.cpp b/source/application/Drawable/Maze/Maze.cpp index 37e9b98e126c56b9173f03e2246344b7a5c92265..7da8a48e15a5add932eed11517beaedc25e671e5 100644 --- a/source/application/Drawable/Maze/Maze.cpp +++ b/source/application/Drawable/Maze/Maze.cpp @@ -1,9 +1,10 @@ #include "Maze.h" #include "../../../../config.h" +#include "../../State/ThemeManager.h" Room::Room(float size) : m_rectangle({size, size}){ m_rectangle.setOrigin(m_rectangle.getSize().x/2,m_rectangle.getSize().y/2 ); - m_rectangle.setFillColor(config::GAME_COLOR_ROOM); + m_rectangle.setFillColor(ThemeManager::Instance().getRoomColor()); } void Room::set_side(Direction side, std::shared_ptr<IRoomSide> ptr_side) { @@ -44,20 +45,20 @@ void Wall::prepare_for_drawing() { switch (direct) { case Room::LEFT: - m_line[0] = sf::Vertex(corners[0], config::GAME_COLOR_WALL); - m_line[1] = sf::Vertex(corners[3], config::GAME_COLOR_WALL); + m_line[0] = sf::Vertex(corners[0], ThemeManager::Instance().getWallColor()); + m_line[1] = sf::Vertex(corners[3], ThemeManager::Instance().getWallColor()); break; case Room::RIGHT: - m_line[0] = sf::Vertex(corners[1], config::GAME_COLOR_WALL); - m_line[1] = sf::Vertex(corners[2], config::GAME_COLOR_WALL); + m_line[0] = sf::Vertex(corners[1], ThemeManager::Instance().getWallColor()); + m_line[1] = sf::Vertex(corners[2], ThemeManager::Instance().getWallColor()); break; case Room::UP: - m_line[0] = sf::Vertex(corners[0], config::GAME_COLOR_WALL); - m_line[1] = sf::Vertex(corners[1], config::GAME_COLOR_WALL); + m_line[0] = sf::Vertex(corners[0], ThemeManager::Instance().getWallColor()); + m_line[1] = sf::Vertex(corners[1], ThemeManager::Instance().getWallColor()); break; case Room::DOWN: - m_line[0] = sf::Vertex(corners[2], config::GAME_COLOR_WALL); - m_line[1] = sf::Vertex(corners[3], config::GAME_COLOR_WALL); + m_line[0] = sf::Vertex(corners[2], ThemeManager::Instance().getWallColor()); + m_line[1] = sf::Vertex(corners[3], ThemeManager::Instance().getWallColor()); break; case Room::INVALID: throw std::runtime_error("Invalid side"); diff --git a/source/application/Drawable/Maze/MenuGame.cpp b/source/application/Drawable/Maze/MenuGame.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8d4cbc388871868d19f6bac9f7037a3f99d9856e --- /dev/null +++ b/source/application/Drawable/Maze/MenuGame.cpp @@ -0,0 +1,25 @@ +#include "MenuGame.h" +#include "../../../../config.h" +#include "../../State/ThemeManager.h" +#include "../../State/GameState.h" +#include "../DrawMenu/Font/Font.h" + +MenuGame::MenuGame() { +} + +void MenuGame::draw_into(sf::RenderWindow &window, const ScoreCount& scores_one, const ScoreCount& scores_two) { + sf::Text m_title(config::SELECT_LEVEL_TITLE_WINDOW, MyFont::Instance(), 40); + m_title.setFillColor(ThemeManager::Instance().getButtonScoreColor()); + m_title.setPosition(10.f, 55.f); + window.draw(m_title); + + sf::Text player_one("Player 1: " + std::to_string(scores_one.get_player_one()), MyFont::Instance(), 30); + player_one.setFillColor(ThemeManager::Instance().getButtonScoreColor()); + player_one.setPosition(10.f, 95.f); + window.draw(player_one); + + sf::Text player_two("Player 2: " + std::to_string(scores_two.get_player_two()), MyFont::Instance(), 30); + player_two.setFillColor(ThemeManager::Instance().getButtonScoreColor()); + player_two.setPosition(10.f, 125.f); + window.draw(player_two); +} \ No newline at end of file diff --git a/source/application/Drawable/Maze/MenuGame.h b/source/application/Drawable/Maze/MenuGame.h new file mode 100644 index 0000000000000000000000000000000000000000..b60dee6287829c3214834070be1cbc87c4772e21 --- /dev/null +++ b/source/application/Drawable/Maze/MenuGame.h @@ -0,0 +1,16 @@ +#pragma once +#include <SFML/Graphics.hpp> +#include "IObserver.h" + +class MenuGame { +public: + MenuGame(); + void draw_into(sf::RenderWindow &window, const ScoreCount& scores_one, const ScoreCount& scores_two); + +private: + sf::RenderWindow m_window; + sf::RectangleShape m_background; + sf::RectangleShape m_button; + sf::Text m_player_one_score; + sf::Text m_player_two_score; +}; \ No newline at end of file diff --git a/source/application/Event/IGameEvent.cpp b/source/application/Event/IGameEvent.cpp index afb393c4a5ea138acab4eca81bc24191d072dcaa..bba248c261e9dda0ec24d3a4de4222b791f17a3b 100644 --- a/source/application/Event/IGameEvent.cpp +++ b/source/application/Event/IGameEvent.cpp @@ -9,6 +9,7 @@ void DeleteStaticEntity::handle(GameContext* context) { auto it = std::find_if(context->static_objects.begin(), context->static_objects.end(), [this](const std::unique_ptr<IStaticEntity>& ptr) { return ptr.get() == m_ptr_entity; }); context->static_objects.erase(it); + notify(); } DeleteStaticEntity::DeleteStaticEntity(IStaticEntity* ptr_entity) : @@ -17,4 +18,13 @@ DeleteStaticEntity::DeleteStaticEntity(IStaticEntity* ptr_entity) : void WinGame::handle(GameContext* context) { context->state = GameContext::WIN; -} \ No newline at end of file +} + +void IGameEvent::add_observer(IObserver *observer) { + m_observers.push_back(observer); +} + +void IGameEvent::notify() const { + for (auto observer : m_observers) + observer->on_notify(*this); +} diff --git a/source/application/Event/IGameEvent.h b/source/application/Event/IGameEvent.h index 1e8b9fc7a4b8b980e6b94074268c8bf53219c393..4157d10aca8a954f3176b3e455ba5698ce4b3b3c 100644 --- a/source/application/Event/IGameEvent.h +++ b/source/application/Event/IGameEvent.h @@ -2,6 +2,7 @@ #include <iostream> #include <list> +#include "../Drawable/Maze/IObserver.h" class GameContext; class IStaticEntity; @@ -10,6 +11,11 @@ class IGameEvent { public: virtual void handle(GameContext* context) = 0; virtual ~IGameEvent() = default; + void add_observer(IObserver* observer); +protected: + void notify() const; +private: + std::vector<IObserver*> m_observers; }; class WinGame : public IGameEvent { @@ -26,6 +32,8 @@ class DeleteStaticEntity : public IGameEvent { public: DeleteStaticEntity(IStaticEntity* ptr_entity); void handle(GameContext* context) override; + int get_player_id() const {return m_player_id; } private: IStaticEntity* m_ptr_entity; + int m_player_id; }; diff --git a/source/application/SelectCommand/ISelectCommand.h b/source/application/SelectCommand/ISelectCommand.h index 844b111eda10dafea5a70156ec487e1ade8746b6..de81153d2b8b3784c4798d43f70938a502a9a9da 100644 --- a/source/application/SelectCommand/ISelectCommand.h +++ b/source/application/SelectCommand/ISelectCommand.h @@ -27,13 +27,14 @@ public: class GameCommand: public ChangeStateCommand { public: - GameCommand(IStateManager& state_manager, std::unique_ptr<GameBuilderDirector> ptr_director) : - ChangeStateCommand(state_manager), m_ptr_director(std::move(ptr_director)) {}; + GameCommand(IStateManager& state_manager, std::unique_ptr<GameBuilderDirector>& ptr_director, int players) : + ChangeStateCommand(state_manager), m_ptr_director(std::move(ptr_director)), m_players(players) {}; void execute() override { - auto state = m_ptr_director->build(m_state_manager); + auto state = m_ptr_director->build(m_state_manager, m_players); m_state_manager.set_next_state(std::move(state)); }; private: + int m_players; std::unique_ptr<GameBuilderDirector> m_ptr_director; }; \ No newline at end of file diff --git a/source/application/State/GameState.cpp b/source/application/State/GameState.cpp index 9dd9d5930e2d40fef2ff4e95e5592190e7b67fd4..7f8bdf76b9150017d398be49dec624025c81dae9 100644 --- a/source/application/State/GameState.cpp +++ b/source/application/State/GameState.cpp @@ -1,9 +1,10 @@ #include "GameState.h" #include "SelectState.h" -#include "../../../config.h" -#include "../Drawable/Entity/IEntity.h" +#include "ThemeManager.h" + GameState::GameState(IStateManager &state_manager, const sf::VideoMode &video_mode, const std::string &window_title) : - IState(state_manager), IWindowKeeper(config::GAME_VIDEO_MODE, window_title){ } + IState(state_manager), IWindowKeeper(config::GAME_VIDEO_MODE, window_title), + m_menu(), m_score_count_one(std::make_unique<ScoreCount>(1)), m_score_count_two(std::make_unique<ScoreCount>(2)){ } void GameState::event_handling() { sf::Event event{}; @@ -23,42 +24,32 @@ void GameState::event_handling() { } bool GameState::process_key_pressed(sf::Keyboard::Key code) { - switch (code) { - case sf::Keyboard::W: - m_context_manager.save_current_context(); //сохраняем состояние - m_context_manager.get_current_context().pacman.move(Room::UP); //выполнили действие - return true; - case sf::Keyboard::S: - m_context_manager.save_current_context(); - m_context_manager.get_current_context().pacman.move(Room::DOWN); - return true; - case sf::Keyboard::A: - m_context_manager.save_current_context(); - m_context_manager.get_current_context().pacman.move(Room::LEFT); - return true; - case sf::Keyboard::D: - m_context_manager.save_current_context(); - m_context_manager.get_current_context().pacman.move(Room::RIGHT); - return true; + GameContext& context = m_context_manager.get_current_context(); - case sf::Keyboard::Up: - m_context_manager.save_current_context(); //сохраняем состояние - m_context_manager.get_current_context().pacman2.move(Room::UP); //выполнили действие - return true; - case sf::Keyboard::Down: - m_context_manager.save_current_context(); - m_context_manager.get_current_context().pacman2.move(Room::DOWN); - return true; - case sf::Keyboard::Left: - m_context_manager.save_current_context(); - m_context_manager.get_current_context().pacman2.move(Room::LEFT); - return true; - case sf::Keyboard::Right: + if (code == sf::Keyboard::W || code == sf::Keyboard::A || code == sf::Keyboard::S || code == sf::Keyboard::D) { + m_context_manager.save_current_context(); + switch (code) { + case sf::Keyboard::W: context.pacman.move(Room::UP); break; + case sf::Keyboard::S: context.pacman.move(Room::DOWN); break; + case sf::Keyboard::A: context.pacman.move(Room::LEFT); break; + case sf::Keyboard::D: context.pacman.move(Room::RIGHT); break; + } + return true; + } + + if (code == sf::Keyboard::Up || code == sf::Keyboard::Down || code == sf::Keyboard::Left || code == sf::Keyboard::Right) { + if (context.pacman2.get_location() != nullptr) { m_context_manager.save_current_context(); - m_context_manager.get_current_context().pacman2.move(Room::RIGHT); + switch (code) { + case sf::Keyboard::Up: context.pacman2.move(Room::UP); break; + case sf::Keyboard::Down: context.pacman2.move(Room::DOWN); break; + case sf::Keyboard::Left: context.pacman2.move(Room::LEFT); break; + case sf::Keyboard::Right: context.pacman2.move(Room::RIGHT); break; + } return true; - default: return false; + } } + return false; } void GameState::update() { @@ -71,44 +62,63 @@ void GameState::update() { auto ptr_event = ptr_entity->accept(ptr_visitor); if (ptr_event) game_events.emplace_back(std::move(ptr_event)); - IVisitor* ptr_visitor2 = &(context.pacman2); - auto ptr_event2 = ptr_entity->accept(ptr_visitor2); - if (ptr_event2) game_events.emplace_back(std::move(ptr_event2)); + if (context.pacman2.get_location() != nullptr) { + IVisitor* ptr_visitor2 = &(context.pacman2); + auto ptr_event2 = ptr_entity->accept(ptr_visitor2); + if (ptr_event2) game_events.emplace_back(std::move(ptr_event2)); + } } for (auto& static_ptr : context.static_objects) { IVisitor* ptr_visitor = &(context.pacman); - auto ptr_event = static_ptr->accept(ptr_visitor); - if (ptr_event) game_events.emplace_back(std::move(ptr_event)); + if (auto ptr_event = static_ptr->accept(ptr_visitor)) { + ptr_event->add_observer(m_score_count_one.get()); + game_events.emplace_back(std::move(ptr_event)); + } - IVisitor* ptr_visitor2 = &(context.pacman2); - auto ptr_event2 = static_ptr->accept(ptr_visitor2); - if (ptr_event2) game_events.emplace_back(std::move(ptr_event2)); + if (context.pacman2.get_location() != nullptr) { + IVisitor* ptr_visitor2 = &(context.pacman2); + if (auto ptr_event2 = static_ptr->accept(ptr_visitor2)) { + ptr_event2->add_observer(m_score_count_two.get()); + game_events.emplace_back(std::move(ptr_event2)); + } + } + } + + if (context.static_objects.empty()) { + game_events.emplace_back(std::make_unique<WinGame>()); + if (m_score_count_one->get_player_one() > m_score_count_two->get_player_two()) std::cout << "выиграл первый"; + else std::cout << "выиграл второй"; } for (int i = 0; i < game_events.size(); i++) game_events[i]->handle(&m_context_manager.get_current_context()); - if (context.static_objects.empty()) { - game_events.emplace_back(std::move(std::make_unique<WinGame>())); - } game_events.clear(); } void GameState::render() { GameContext& context = m_context_manager.get_current_context(); + sf::Color backgroundColor; switch (context.state) { case GameContext::INGAME: - m_window.clear(config::GAME_COLOR_BACKGROUND_INGAME); + backgroundColor = ThemeManager::Instance().getGameBackgroundInGameColor(); break; case GameContext::LOST: - m_window.clear(config::GAME_COLOR_BACKGROUND_LOST); + backgroundColor = ThemeManager::Instance().getGameBackgroundLostColor(); + break; + case GameContext::WIN: + backgroundColor = ThemeManager::Instance().getGameBackgroundWinColor(); break; default: - m_window.clear(config::GAME_COLOR_BACKGROUND_WIN); + break; } + + m_window.clear(backgroundColor); + m_menu.draw_into(m_window, *m_score_count_one, *m_score_count_two); m_maze.draw_into(m_window); context.pacman.draw_into(m_window); - context.pacman2.draw_into(m_window); + if (context.pacman2.get_location() != nullptr) + context.pacman2.draw_into(m_window); for (auto& obj : context.static_objects) obj->draw_into(m_window); diff --git a/source/application/State/GameState.h b/source/application/State/GameState.h index be23a5395c564d3e92db1e0135c701c4c9c88575..ea557516b4759b121e5779863255222d72395c9f 100644 --- a/source/application/State/GameState.h +++ b/source/application/State/GameState.h @@ -1,6 +1,7 @@ #pragma once #include "IState.h" #include "../Drawable/Maze/Maze.h" +#include "../Drawable/Maze/MenuGame.h" #include "../Context/Context.h" #include "../Event/IGameEvent.h" @@ -11,12 +12,15 @@ public: void update() override; void render() override; bool do_step() override; - void set_maze(Maze&& maze) {m_maze = std::move(maze); } void set_context(GameContext&& context); bool process_key_pressed(sf::Keyboard::Key code); + const ScoreCount& get_score_count() const {return *m_score_count_one, *m_score_count_two; } private: Maze m_maze; + MenuGame m_menu; ContextManager m_context_manager; std::vector<std::unique_ptr<IGameEvent>> m_events; + std::unique_ptr<ScoreCount> m_score_count_one; + std::unique_ptr<ScoreCount> m_score_count_two; }; diff --git a/source/application/State/SelectState.cpp b/source/application/State/SelectState.cpp index e74338877b6e0b130a6b13c00d6c74e9f06a2e4f..8fdfa880f4d216a63bbdd1f47d60649fa372eb67 100644 --- a/source/application/State/SelectState.cpp +++ b/source/application/State/SelectState.cpp @@ -1,10 +1,13 @@ #include "SelectState.h" -#include "../../../config.h" SelectState::SelectState(IStateManager& state_manager, const sf::VideoMode& video_mode, const std::string& window_title) : - IState(state_manager), IWindowKeeper(video_mode, window_title), m_menu(state_manager) {} + IState(state_manager), IWindowKeeper(video_mode, window_title), m_menu(state_manager) { + update_theme(); + set_texture(&BackgroundTexture::instance()); + m_backgorund_sprite.setTexture(m_background->get_texture()); +} void SelectState::event_handling() { sf::Event event{}; @@ -26,7 +29,8 @@ void SelectState::update() { } void SelectState::render() { - m_window.clear(config::SELECT_LEVEL_BACKGROUND_COLOR); + update_theme(); + m_window.draw(m_backgorund_sprite); m_menu.draw_into(m_window); m_window.display(); } diff --git a/source/application/State/SelectState.h b/source/application/State/SelectState.h index deef1af0ff322a3e50790631229e214c2b88e1fc..2d05eccdf85a8bfeaac86cc7d702dcd8e3260505 100644 --- a/source/application/State/SelectState.h +++ b/source/application/State/SelectState.h @@ -1,13 +1,18 @@ #pragma once #include "IState.h" #include "../Drawable/DrawMenu/Menu/Menu.h" +#include "ThemeManager.h" struct SelectState: public IState, public IWindowKeeper { SelectState(IStateManager& state_manager, const sf::VideoMode& video_mode, const std::string& window_title); void event_handling() override; + void set_texture(MyTexture* ptr_texture) { m_background = ptr_texture; } void update() override; void render() override; bool do_step() override; private: + void update_theme() { ThemeManager::Instance().applyTheme(); } + MyTexture* m_background; + sf::Sprite m_backgorund_sprite; Menu m_menu; }; \ No newline at end of file diff --git a/source/application/State/ThemeManager.cpp b/source/application/State/ThemeManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9f1e6015319e7bf58a36141e486e7b0a999353d6 --- /dev/null +++ b/source/application/State/ThemeManager.cpp @@ -0,0 +1,102 @@ +#include "ThemeManager.h" + +ThemeManager& ThemeManager::Instance() { + static ThemeManager instance; + return instance; +} + +sf::Color ThemeManager::getButtonFillColor() const { + return m_currentColors.button_fill; +} + +void ThemeManager::set_theme(ThemeManager::Theme newTheme) { + m_theme = newTheme; + loadThemeColors(); +} + +sf::Color ThemeManager::getButtonOutlineColor() const { + return m_currentColors.button_frame; +} + +sf::Color ThemeManager::getButtonTextColor() const { + return m_currentColors.button_text; +} + +sf::Color ThemeManager::getButtonSelectionColor() const { + return m_currentColors.button_selection; +} + +sf::Color ThemeManager::getTitleTextColor() const { + return m_currentColors.title_text; +} + +sf::Color ThemeManager::getGameBackgroundInGameColor() const { + return m_currentColors.game_background_ingame; +} + +sf::Color ThemeManager::getGameBackgroundWinColor() const { + return m_currentColors.game_background_win; +} + +sf::Color ThemeManager::getGameBackgroundLostColor() const { + return m_currentColors.game_background_lost; +} + +sf::Color ThemeManager::getRoomColor() const { + return m_currentColors.room_color; +} + +sf::Color ThemeManager::getWallColor() const { + return m_currentColors.wall_color; +} + +void ThemeManager::loadThemeColors() { + if (m_theme == Theme::LIGHT) { + m_currentColors = { + sf::Color::White, // button_text + sf::Color::Black, + sf::Color(21, 117, 217), // button_fill + sf::Color(0, 0, 0), // button_selection + sf::Color::White, // button_frame + sf::Color(240, 240, 240), // select_level_background + sf::Color(255, 255, 255), // game_background_ingame + sf::Color(0, 255, 0), // game_background_win + sf::Color(255, 0, 0), // game_background_lost + sf::Color(255, 255, 0), // game_pacman + sf::Color(100, 100, 100), // game_pacman_invisible + sf::Color(200, 200, 255), // game_room + sf::Color(50, 50, 50), // game_wall + sf::Color(255, 165, 0), // game_food + sf::Color(255, 0, 0), // game_enemy + sf::Color::White, // title_text + sf::Color(255, 255, 255), // room_color + sf::Color(0, 0, 0) // wall_color + }; + } else if (m_theme == Theme::DARK) { + m_currentColors = { + sf::Color::White, // button_text + sf::Color::Black, + sf::Color(21, 117, 217), // button_fill + sf::Color(80, 80, 80), // button_selection + sf::Color::White, // button_frame + sf::Color(30, 30, 30), // select_level_background + sf::Color(40, 40, 40), // game_background_ingame + sf::Color(0, 255, 0), // game_background_win + sf::Color(255, 0, 0), // game_background_lost + sf::Color(255, 255, 0), // game_pacman + sf::Color(100, 100, 100), // game_pacman_invisible + sf::Color(100, 100, 100), // game_room + sf::Color(50, 50, 50), // game_wall + sf::Color(255, 165, 0), // game_food + sf::Color(255, 0, 0), // game_enemy + sf::Color::White, // title_text + sf::Color(0, 0, 0), // room_color + sf::Color(0, 0, 255) // wall_color + }; + } +} + +sf::Color ThemeManager::getButtonScoreColor() const { + return m_currentColors.button_text_score; +} + diff --git a/source/application/State/ThemeManager.h b/source/application/State/ThemeManager.h new file mode 100644 index 0000000000000000000000000000000000000000..39f87ee1c793f33857437cffde86ca7052160d92 --- /dev/null +++ b/source/application/State/ThemeManager.h @@ -0,0 +1,55 @@ +#pragma once +#include "../../../config.h" + +struct ThemeColors { + sf::Color button_text; + sf::Color button_text_score; + sf::Color button_fill; + sf::Color button_selection; + sf::Color button_frame; + sf::Color select_level_background; + sf::Color game_background_ingame; + sf::Color game_background_win; + sf::Color game_background_lost; + sf::Color game_pacman; + sf::Color game_pacman_invisible; + sf::Color game_room; + sf::Color game_wall; + sf::Color game_food; + sf::Color game_enemy; + sf::Color title_text; + sf::Color room_color; + sf::Color wall_color; +}; + + +class ThemeManager { +public: + enum class Theme { LIGHT, DARK }; + ThemeManager(const ThemeManager&) = delete; + ThemeManager& operator=(const ThemeManager&) = delete; + static ThemeManager& Instance(); + void applyTheme() {loadThemeColors(); } + void set_theme(Theme newTheme); + + sf::Color getButtonFillColor() const; + sf::Color getButtonOutlineColor() const; + sf::Color getButtonTextColor() const; + sf::Color getButtonScoreColor() const; + sf::Color getButtonSelectionColor() const; + + sf::Color getTitleTextColor() const; + + sf::Color getGameBackgroundInGameColor() const; + sf::Color getGameBackgroundWinColor() const; + sf::Color getGameBackgroundLostColor() const; + sf::Color getRoomColor() const; + sf::Color getWallColor() const; + +private: + Theme m_theme = Theme::LIGHT; + ThemeColors m_currentColors; + void loadThemeColors(); + + ThemeManager() {set_theme(Theme::LIGHT);}; +};