From 87704da485b4f48445365b6faefc50687ac89b57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=B5=D1=87=D0=B5=D0=BD=D0=B8=D0=BD=20=D0=94=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D0=BB=D0=B0=20=D0=9C=D0=B8=D1=85=D0=B0=D0=B9=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= <dmpechenin@edu.hse.ru> Date: Tue, 11 Mar 2025 23:21:00 +0300 Subject: [PATCH] SimpleBuilder was implemented and other fixes were done --- source/BasicAbstractions/IWindowKeeper.h | 6 +- source/Configuration.h | 8 +-- source/States/GameState/Entities/IEntity.h | 5 +- .../GameState/Entities/Pacman/Pacman.cpp | 2 +- .../StaticEntities/StaticEntities.cpp | 4 +- .../GameState/GameBuilder/GameBuilder.cpp | 59 ++++++++++++++++++- .../GameState/GameBuilder/GameBuilder.h | 20 ++++--- .../GameBuilder/GameBuilderDirector.cpp | 2 +- source/States/GameState/GameState.cpp | 47 +++++++++++++-- source/States/GameState/GameState.h | 12 ++-- source/States/GameState/Maze/Room/Room.cpp | 3 +- source/States/GameState/Maze/Room/Room.h | 5 +- .../GameState/Maze/Room/RoomSide/RoomSide.cpp | 2 +- source/States/SelectState/SelectState.cpp | 8 +-- source/States/SelectState/SelectState.h | 5 +- 15 files changed, 144 insertions(+), 44 deletions(-) diff --git a/source/BasicAbstractions/IWindowKeeper.h b/source/BasicAbstractions/IWindowKeeper.h index 16b5ee0..215a3bd 100644 --- a/source/BasicAbstractions/IWindowKeeper.h +++ b/source/BasicAbstractions/IWindowKeeper.h @@ -1,11 +1,9 @@ #pragma once -#include <Configuration.h> +#include <SFML/Graphics.hpp> class IWindowKeeper { public: - IWindowKeeper(const sf::VideoMode& video_mode, const sf::String& window_title) : m_window(video_mode, window_title) { - m_window.setFramerateLimit(config::FRAME_RATE_LIMIT); - } + IWindowKeeper(const sf::VideoMode& video_mode, const sf::String& window_title) : m_window(video_mode, window_title) {} virtual ~IWindowKeeper() = default; protected: virtual void event_handling() = 0; diff --git a/source/Configuration.h b/source/Configuration.h index 4223a30..676104d 100644 --- a/source/Configuration.h +++ b/source/Configuration.h @@ -38,11 +38,11 @@ namespace config { const sf::Color BUTTON_COLOR_SELECTION{ 255, 180, 180 }; const sf::Color BUTTON_COLOR_FRAME{ 0, 0, 0 }; const sf::Color SELECT_LEVEL_BACKGROUND_COLOR{ 230,230,230 }; - // const sf::Color GAME_COLOR_BACKGROUND_INGAME{ 230,230,230 }; - // const sf::Color GAME_COLOR_BACKGROUND_WIN{ 0, 255, 0 }; - // const sf::Color GAME_COLOR_BACKGROUND_LOST{ 255, 0, 0 }; + const sf::Color GAME_COLOR_BACKGROUND_INGAME{ 230,230,230 }; + const sf::Color GAME_COLOR_BACKGROUND_WIN{ 0, 255, 0 }; + const sf::Color GAME_COLOR_BACKGROUND_LOST{ 255, 0, 0 }; const sf::Color GAME_COLOR_PACMAN{ 250, 150, 0 }; - // const sf::Color GAME_COLOR_ROOM{ 255, 255, 255 }; + const sf::Color GAME_COLOR_ROOM{ 255, 255, 255 }; const sf::Color GAME_COLOR_WALL{ 0, 0, 0 }; const sf::Color GAME_FOOD_COLOR{ 0, 200, 100 }; const sf::Color GAME_ENEMY_COLOR{ 255, 50, 0 }; diff --git a/source/States/GameState/Entities/IEntity.h b/source/States/GameState/Entities/IEntity.h index 51bc31b..6b1e5b2 100644 --- a/source/States/GameState/Entities/IEntity.h +++ b/source/States/GameState/Entities/IEntity.h @@ -4,7 +4,10 @@ class IEntity : public IPreparable { public: - void set_location(Room* ptr_room) noexcept { m_ptr_room = ptr_room; } + void set_location(Room* ptr_room) noexcept { + m_ptr_room = ptr_room; + prepare_for_drawing(); + } [[nodiscard]] Room* get_location() const noexcept { return m_ptr_room; } ~IEntity() override = default; protected: diff --git a/source/States/GameState/Entities/Pacman/Pacman.cpp b/source/States/GameState/Entities/Pacman/Pacman.cpp index b7b96e0..ccf1120 100644 --- a/source/States/GameState/Entities/Pacman/Pacman.cpp +++ b/source/States/GameState/Entities/Pacman/Pacman.cpp @@ -1,7 +1,7 @@ #include <Configuration.h> #include <States/GameState/Entities/Pacman/Pacman.h> -Pacman::Pacman() : m_circle{ config::GAME_PACMAN_SIZE } { +Pacman::Pacman() : m_circle{ config::GAME_PACMAN_SIZE/2 } { m_circle.setFillColor(config::GAME_COLOR_PACMAN); m_circle.setOrigin(config::GAME_PACMAN_SIZE/2, config::GAME_PACMAN_SIZE/2); } diff --git a/source/States/GameState/Entities/StaticEntities/StaticEntities.cpp b/source/States/GameState/Entities/StaticEntities/StaticEntities.cpp index 33b64d3..f3e755e 100644 --- a/source/States/GameState/Entities/StaticEntities/StaticEntities.cpp +++ b/source/States/GameState/Entities/StaticEntities/StaticEntities.cpp @@ -3,7 +3,7 @@ Food::Food() : m_circle(config::GAME_FOOD_SIZE, 6) { m_circle.setFillColor(config::GAME_FOOD_COLOR); - m_circle.setOrigin({config::GAME_FOOD_SIZE/2, config::GAME_FOOD_SIZE/2}); + m_circle.setOrigin({config::GAME_FOOD_SIZE, config::GAME_FOOD_SIZE}); } std::unique_ptr<IStaticEntity> Food::clone() const { @@ -15,6 +15,6 @@ void Food::draw_into(sf::RenderWindow& window) const { } void Food::prepare_for_drawing() { - m_circle.setPosition(m_ptr_room->get_position()); ///< @todo надо ли? + m_circle.setPosition(m_ptr_room->get_position()); } diff --git a/source/States/GameState/GameBuilder/GameBuilder.cpp b/source/States/GameState/GameBuilder/GameBuilder.cpp index e224f37..7cdc323 100644 --- a/source/States/GameState/GameBuilder/GameBuilder.cpp +++ b/source/States/GameState/GameBuilder/GameBuilder.cpp @@ -16,11 +16,11 @@ void CommonBuilder::create_context(float dynamic_objets_ratio) { std::uniform_int_distribution distrib(0 , static_cast<int>(buf_rooms.size()-1)); auto pos = buf_rooms.begin() + distrib(gen); - m_context.pacman.set_location((*(buf_rooms.begin() + distrib(gen)))->get()); + m_context.pacman.set_location((*pos)->get()); buf_rooms.erase(pos); + if (dynamic_objets_ratio > 1) throw std::invalid_argument("GAME_ENEMY_RATIO should be <= 1"); const auto number_of_dynamic_entities = static_cast<size_t>(static_cast<float>(buf_rooms.size()) * dynamic_objets_ratio); - if (number_of_dynamic_entities > 1) throw std::invalid_argument("GAME_ENEMY_RATIO should be <= 1"); for (size_t i = 0; i < number_of_dynamic_entities; ++i) { m_context.dynamic_objects.emplace_back(std::move(std::make_unique<Enemy>())); distrib.param(std::uniform_int_distribution<>::param_type(0, static_cast<int>(buf_rooms.size()) - 1)); @@ -49,3 +49,58 @@ void CommonBuilder::set_all_to_state() { m_game_state->set_maze(Maze(std::move(rooms))); m_game_state->set_context(std::move(m_context)); } + +void SimpleBuilder::create_rooms() { + const auto number_of_rooms_in_row = static_cast<size_t>(m_width / m_room_size); + const auto number_of_rooms_in_col = static_cast<size_t>(m_height / m_room_size); + + sf::Vector2f gap( + (m_width - static_cast<float>(number_of_rooms_in_row) * m_room_size + m_room_size) / 2.f, + (m_height - static_cast<float>(number_of_rooms_in_col) * m_room_size + m_room_size) / 2.f + ); + + for (size_t i = 0; i < number_of_rooms_in_col; ++i) { + std::vector<std::unique_ptr<Room>> room_row; + room_row.reserve(number_of_rooms_in_row); + for (size_t j = 0; j < number_of_rooms_in_row; ++j) { + auto tmp_room = std::make_unique<Room>(m_room_size); + tmp_room->set_color(m_room_color); + tmp_room->set_position(gap + sf::Vector2f{ m_room_size * static_cast<float>(j), m_room_size * static_cast<float>(i) }); + room_row.emplace_back(std::move(tmp_room)); + } + m_rooms.emplace_back(std::move(room_row)); + } +} + +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) { + if (i == 0) { + auto top_wall = std::make_shared<Wall>(*m_rooms[i][j]); + m_rooms[i][j]->set_side(Room::UP, std::move(top_wall)); + } + else { + auto pass = std::make_shared<Pass>(*m_rooms[i - 1][j], *m_rooms[i][j]); + m_rooms[i][j]->set_side(Room::UP, pass); + m_rooms[i - 1][j]->set_side(Room::DOWN, pass); + } + if (j == 0) { + auto left_wall = std::make_shared<Wall>(*m_rooms[i][j]); + m_rooms[i][j]->set_side(Room::LEFT, std::move(left_wall)); + } + else { + auto pass = std::make_shared<Pass>(*m_rooms[i][j - 1], *m_rooms[i][j]); + m_rooms[i][j]->set_side(Room::LEFT, pass); + m_rooms[i][j - 1]->set_side(Room::RIGHT, pass); + } + if (i == m_rooms.size() - 1) { + auto down_wall = std::make_shared<Wall>(*m_rooms[i][j]); + m_rooms[i][j]->set_side(Room::DOWN, std::move(down_wall)); + } + if (j == m_rooms.begin()->size() - 1) { + auto right_wall = std::make_shared<Wall>(*m_rooms[i][j]); + m_rooms[i][j]->set_side(Room::RIGHT, std::move(right_wall)); + } + } + } +} diff --git a/source/States/GameState/GameBuilder/GameBuilder.h b/source/States/GameState/GameBuilder/GameBuilder.h index cefe233..e3aecd9 100644 --- a/source/States/GameState/GameBuilder/GameBuilder.h +++ b/source/States/GameState/GameBuilder/GameBuilder.h @@ -5,38 +5,40 @@ struct IGameBuilder { virtual void create_rooms() = 0; - virtual void set_rooms_side() = 0; + virtual void set_rooms_sides() = 0; virtual void create_context(float dynamic_objets_ratio) = 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; ///< @todo unique_ptr? + virtual std::unique_ptr<GameState> get_game() = 0; virtual ~IGameBuilder() = default; }; class CommonBuilder : public IGameBuilder { public: - CommonBuilder(const float width, const float height, const float room_size) : m_width(width), m_height(height), m_room_size(room_size) {} + CommonBuilder(const float width, const float height, const float room_size, const sf::Color room_color) : + m_width(width), m_height(height), m_room_size(room_size), m_room_color(room_color) {} void create_context(float dynamic_objets_ratio) 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 { return std::move(m_game_state); } -private: +protected: float m_width; float m_height; float m_room_size; + sf::Color m_room_color; std::vector<std::vector<std::unique_ptr<Room>>> m_rooms; GameContext m_context; std::unique_ptr<GameState> m_game_state; }; struct SimpleBuilder : CommonBuilder { - using CommonBuilder::CommonBuilder; ///< @todo ??? - void create_rooms() override {} - void set_rooms_side() override {} + using CommonBuilder::CommonBuilder; + void create_rooms() override; + void set_rooms_sides() override; }; struct ComplexBuilder : CommonBuilder { - using CommonBuilder::CommonBuilder; ///< @todo ??? + using CommonBuilder::CommonBuilder; void create_rooms() override {} - void set_rooms_side() override {} + void set_rooms_sides() override {} }; \ No newline at end of file diff --git a/source/States/GameState/GameBuilder/GameBuilderDirector.cpp b/source/States/GameState/GameBuilder/GameBuilderDirector.cpp index eb298c2..a678a28 100644 --- a/source/States/GameState/GameBuilder/GameBuilderDirector.cpp +++ b/source/States/GameState/GameBuilder/GameBuilderDirector.cpp @@ -2,7 +2,7 @@ std::unique_ptr<GameState> GameBuilderDirector::build(IStateManager& state_manager) const { m_ptr_builder->create_rooms(); - m_ptr_builder->set_rooms_side(); + m_ptr_builder->set_rooms_sides(); m_ptr_builder->create_context(m_dynamic_object_ratio); m_ptr_builder->create_state(state_manager, m_mode, m_window_title); m_ptr_builder->set_all_to_state(); diff --git a/source/States/GameState/GameState.cpp b/source/States/GameState/GameState.cpp index 56b7e71..25ae533 100644 --- a/source/States/GameState/GameState.cpp +++ b/source/States/GameState/GameState.cpp @@ -1,9 +1,46 @@ #include <States/GameState/GameState.h> -#include <iostream> /// @todo remove it -#include <States/ExitState/ExitState.h> +#include <States/SelectState/SelectState.h> + +void GameState::event_handling() { + sf::Event event{}; + while (m_window.pollEvent(event)) { + if (event.type == sf::Event::Closed) { + m_state_manager.set_next_state(std::make_unique<SelectState>(m_state_manager, config::SELECT_LEVEL_VIDEO_MODE, config::SELECT_LEVEL_TITLE)); + } + } +} + +void GameState::update() { + if (m_context_manager.get_current_context().state != GameContext::INGAME) + return; + for (const auto& obj : m_context_manager.get_current_context().dynamic_objects) + obj->action(); +} + +void GameState::render() { + switch (m_context_manager.get_current_context().state) { + case GameContext::INGAME: + m_window.clear(config::GAME_COLOR_BACKGROUND_INGAME); + break; + case GameContext::WIN: + m_window.clear(config::GAME_COLOR_BACKGROUND_WIN); + break; + case GameContext::LOST: + m_window.clear(config::GAME_COLOR_BACKGROUND_LOST); + } + m_window.clear(config::GAME_COLOR_BACKGROUND_INGAME); + m_maze.draw_into(m_window); + for (const auto& obj : m_context_manager.get_current_context().static_objects) + obj->draw_into(m_window); + for (const auto& obj : m_context_manager.get_current_context().dynamic_objects) + obj->draw_into(m_window); + m_context_manager.get_current_context().pacman.draw_into(m_window); + m_window.display(); +} bool GameState::do_step() { - std::cout << "Game state" << std::endl; - m_state_manager.set_next_state(std::make_unique<ExitState>(m_state_manager)); + event_handling(); + update(); + render(); return true; -} \ No newline at end of file +} diff --git a/source/States/GameState/GameState.h b/source/States/GameState/GameState.h index 63d49f6..16359aa 100644 --- a/source/States/GameState/GameState.h +++ b/source/States/GameState/GameState.h @@ -1,4 +1,5 @@ #pragma once +#include <Configuration.h> #include <BasicAbstractions/IState.h> #include <BasicAbstractions/IWindowKeeper.h> #include <States/GameState/Maze/Maze.h> @@ -7,16 +8,17 @@ class GameState : public IState, public IWindowKeeper { public: explicit GameState(IStateManager& state_manager, const sf::VideoMode& video_mode, const sf::String& window_title) : - IState(state_manager), IWindowKeeper(video_mode, window_title) {} + IState(state_manager), IWindowKeeper(video_mode, window_title) { + m_window.setFramerateLimit(config::FRAME_RATE_LIMIT); + } bool do_step() override; void set_maze(Maze&& maze) { m_maze = std::move(maze); } void set_context(GameContext&& context) { m_context_manager.reset(std::move(context)); } private: - void event_handling() override {}; - void update() override {}; - void render() override {}; + void event_handling() override; + void update() override; + void render() override; private: Maze m_maze; ContextManager m_context_manager; }; - diff --git a/source/States/GameState/Maze/Room/Room.cpp b/source/States/GameState/Maze/Room/Room.cpp index ea3b4a7..75c9fcf 100644 --- a/source/States/GameState/Maze/Room/Room.cpp +++ b/source/States/GameState/Maze/Room/Room.cpp @@ -7,7 +7,7 @@ Room::Room(float size) : m_rectangle({size, size}) { void Room::set_side(const Direction side, std::shared_ptr<IRoomSide>&& ptr_side) { if (side == INVALID) throw std::invalid_argument("Invalid direction"); m_sides[side] = std::move(ptr_side); - ptr_side->prepare_for_drawing(); + m_sides[side]->prepare_for_drawing(); } Room::Direction Room::get_direction(const IRoomSide* ptr_side) const { @@ -24,4 +24,3 @@ void Room::draw_into(sf::RenderWindow& window) const { side->draw_into(window); } } - diff --git a/source/States/GameState/Maze/Room/Room.h b/source/States/GameState/Maze/Room/Room.h index 2825cb2..fd33e60 100644 --- a/source/States/GameState/Maze/Room/Room.h +++ b/source/States/GameState/Maze/Room/Room.h @@ -1,6 +1,6 @@ #pragma once -#include <BasicAbstractions/IPreparable.h> +#include <BasicAbstractions/IDrawable.h> #include <States/GameState/Maze/Room/RoomSide/RoomSide.h> #include <array> @@ -13,6 +13,7 @@ public: explicit Room(float size); float get_size() const noexcept { return m_rectangle.getSize().x; } void set_position(const sf::Vector2f pos) { m_rectangle.setPosition(pos); } + void set_color(const sf::Color color) { m_rectangle.setFillColor(color); } sf::Vector2f get_position() const noexcept { return m_rectangle.getPosition(); } void set_side(Direction side, std::shared_ptr<IRoomSide>&& ptr_side); IRoomSide* get_side(const Direction side) const noexcept { return m_sides[side].get(); } @@ -20,6 +21,6 @@ public: void draw_into(sf::RenderWindow& window) const override; private: sf::RectangleShape m_rectangle; - std::array<std::shared_ptr<IRoomSide>, 4> m_sides; ///< @todo shared_ptr? Две комнаты владеют одним IRoomSide + std::array<std::shared_ptr<IRoomSide>, 4> m_sides; }; diff --git a/source/States/GameState/Maze/Room/RoomSide/RoomSide.cpp b/source/States/GameState/Maze/Room/RoomSide/RoomSide.cpp index 4a443b5..bf7a2d5 100644 --- a/source/States/GameState/Maze/Room/RoomSide/RoomSide.cpp +++ b/source/States/GameState/Maze/Room/RoomSide/RoomSide.cpp @@ -15,7 +15,7 @@ void Wall::prepare_for_drawing() { sf::Vector2f{pos.x - size/2, pos.y + size/2}, sf::Vector2f{pos.x + size/2, pos.y + size/2}}; - switch (Room::Direction direction = m_room.get_direction(this)) { + switch (m_room.get_direction(this)) { case Room::Direction::UP: m_line[0] = sf::Vertex(corners[0], config::GAME_COLOR_WALL); m_line[1] = sf::Vertex(corners[1], config::GAME_COLOR_WALL); diff --git a/source/States/SelectState/SelectState.cpp b/source/States/SelectState/SelectState.cpp index 942a43b..28fa929 100644 --- a/source/States/SelectState/SelectState.cpp +++ b/source/States/SelectState/SelectState.cpp @@ -10,7 +10,7 @@ Menu::Menu(IStateManager& state_manager) { auto easy_level_command = std::make_unique<GameCommand>( state_manager, std::make_unique<GameBuilderDirector>( - std::make_unique<SimpleBuilder>(config::GAME_VIDEO_MODE.width, config::GAME_VIDEO_MODE.height, config::ROOM_SIZE), + std::make_unique<SimpleBuilder>(config::GAME_VIDEO_MODE.width, config::GAME_VIDEO_MODE.height, config::ROOM_SIZE, config::GAME_COLOR_ROOM), config::GAME_VIDEO_MODE, config::EASY_GAME_TITLE, config::EASY_GAME_ENEMY_RATIO)); @@ -18,7 +18,7 @@ Menu::Menu(IStateManager& state_manager) { auto medium_level_command = std::make_unique<GameCommand>( state_manager, std::make_unique<GameBuilderDirector>( - std::make_unique<SimpleBuilder>(config::GAME_VIDEO_MODE.width, config::GAME_VIDEO_MODE.height, config::ROOM_SIZE), + std::make_unique<SimpleBuilder>(config::GAME_VIDEO_MODE.width, config::GAME_VIDEO_MODE.height, config::ROOM_SIZE, config::GAME_COLOR_ROOM), config::GAME_VIDEO_MODE, config::MEDIUM_GAME_TITLE, config::MEDIUM_GAME_ENEMY_RATIO)); @@ -26,7 +26,7 @@ Menu::Menu(IStateManager& state_manager) { auto hard_level_command = std::make_unique<GameCommand>( state_manager, std::make_unique<GameBuilderDirector>( - std::make_unique<ComplexBuilder>(config::GAME_VIDEO_MODE.width, config::GAME_VIDEO_MODE.height, config::ROOM_SIZE), + std::make_unique<ComplexBuilder>(config::GAME_VIDEO_MODE.width, config::GAME_VIDEO_MODE.height, config::ROOM_SIZE, config::GAME_COLOR_ROOM), config::GAME_VIDEO_MODE, config::HARD_GAME_TITLE, config::HARD_GAME_ENEMY_RATIO)); @@ -66,7 +66,7 @@ void SelectState::event_handling() { while (m_window.pollEvent(event)) { if (event.type == sf::Event::Closed) { m_state_manager.set_next_state(std::make_unique<ExitState>(m_state_manager)); - m_window.close(); + //m_window.close(); ///< @todo убрать вероятно } if (event.type == sf::Event::Resized) { sf::View view = m_window.getView(); diff --git a/source/States/SelectState/SelectState.h b/source/States/SelectState/SelectState.h index 8903982..f94f31c 100644 --- a/source/States/SelectState/SelectState.h +++ b/source/States/SelectState/SelectState.h @@ -1,4 +1,5 @@ #pragma once +#include <Configuration.h> #include <BasicAbstractions/IState.h> #include <BasicAbstractions/IWindowKeeper.h> #include <BasicAbstractions/IDrawable.h> @@ -16,7 +17,9 @@ private: class SelectState : public IState, public IWindowKeeper { public: explicit SelectState(IStateManager& state_manager, const sf::VideoMode& video_mode, const sf::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) { + m_window.setFramerateLimit(config::FRAME_RATE_LIMIT); + } bool do_step() override; private: void event_handling() override; -- GitLab