From 86dd10d9a0ad2f6a043771081a62bf1c5ef13249 Mon Sep 17 00:00:00 2001 From: Sulimov Igor Andreevich <igansulimov@edu.hse.ru> Date: Tue, 25 Mar 2025 01:33:04 +0300 Subject: [PATCH] Almost completed CommonBuilder --- CMakeLists.txt | 2 + include/Builder/Builders/CommonBuilder.h | 8 ++-- include/Builder/GameBuilderDirector.h | 5 +- include/Config.h | 14 +++--- .../Entities/DynamicEntities/Enemy.h | 10 ++-- include/MazeContent/Entities/Pacman.h | 6 +-- .../Entities/StaticEntities/Food.h | 8 ++-- include/States/GameState.h | 5 ++ include/States/SelectState.h | 1 + source/Builder/Builders/CommonBuilder.cpp | 48 +++++++++++++++++++ source/Builder/GameBuilderDirector.cpp | 15 ++++++ .../Entities/DynamicEntities/Enemy.cpp | 14 ++++++ source/MazeContent/Entities/Pacman.cpp | 14 ++++++ .../Entities/StaticEntities/Food.cpp | 19 ++++++++ 14 files changed, 143 insertions(+), 26 deletions(-) create mode 100644 source/Builder/GameBuilderDirector.cpp create mode 100644 source/MazeContent/Entities/StaticEntities/Food.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7578cf3..f7cdcc7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,8 +24,10 @@ add_executable(pac-man "source/MazeContent/Buildings/Pass.cpp" "source/MazeContent/Entities/IEntity.cpp" "source/MazeContent/Entities/Pacman.cpp" + "source/MazeContent/Entities/StaticEntities/Food.cpp" "source/MazeContent/Entities/DynamicEntities/Enemy.cpp" "source/Context/GameContext.cpp" + "source/Builder/GameBuilderDirector.cpp" "source/Builder/Builders/CommonBuilder.cpp" "source/Builder/Builders/SimpleBuilder.cpp" "source/Builder/Builders/ComplexBuilder.cpp" diff --git a/include/Builder/Builders/CommonBuilder.h b/include/Builder/Builders/CommonBuilder.h index 95d06db..6ec6ad7 100644 --- a/include/Builder/Builders/CommonBuilder.h +++ b/include/Builder/Builders/CommonBuilder.h @@ -6,11 +6,11 @@ class CommonBuilder: public IGameBuilder { public: virtual void create_rooms() override {}; ///@todo Определиться, нужны ли данные строчки или нет virtual void set_rooms_sides() override {}; ///@todo Определиться, нужны ли данные строчки или нет - void create_context(float dynamic_objects_ratio) override {}; ///@todo + void create_context(float dynamic_objects_ratio) override; void create_state(IStateManager& state_manager, - sf::VideoMode video_mode, const std::string& window_title) override {}; ///@todo - void set_all_to_state() override {}; ///@todo - std::unique_ptr<GameState> get_game() override {}; ///@todo + sf::VideoMode video_mode, const std::string& window_title) override; + void set_all_to_state() override; + std::unique_ptr<GameState> get_game() override; public: CommonBuilder(float width, float height, float room_size); virtual ~CommonBuilder() = default; diff --git a/include/Builder/GameBuilderDirector.h b/include/Builder/GameBuilderDirector.h index 39770ad..3c6f1ee 100644 --- a/include/Builder/GameBuilderDirector.h +++ b/include/Builder/GameBuilderDirector.h @@ -4,11 +4,10 @@ class GameBuilderDirector { public: - std::unique_ptr<GameState> build(IStateManager& state_manager); ///@todo + std::unique_ptr<GameState> build(IStateManager& state_manager); public: GameBuilderDirector(std::unique_ptr<IGameBuilder> ptr_builder, - const sf::VideoMode& video_mode, const std::string& window_title, - float dynamic_objects_ratio); ///@todo + const sf::VideoMode& video_mode, const std::string& window_title, float dynamic_objects_ratio); private: std::string m_window_title; sf::VideoMode m_video_mode; diff --git a/include/Config.h b/include/Config.h index aea287d..2b147c1 100644 --- a/include/Config.h +++ b/include/Config.h @@ -23,11 +23,11 @@ namespace config { // const float EASY_GAME_ENEMY_RATIO = 0.0f; // const float MEDIUM_GAME_ENEMY_RATIO = 0.03f; // const float HARD_GAME_ENEMY_RATIO = 0.07f; -// const float ROOM_SIZE = 50; -// const float GAME_ENEMY_SIZE = ROOM_SIZE * 0.7; -// const float GAME_FOOD_SIZE = ROOM_SIZE * 0.2; + const float ROOM_SIZE = 50; + const float GAME_ENEMY_SIZE = ROOM_SIZE * 0.7; + const float GAME_FOOD_SIZE = ROOM_SIZE * 0.2; // Пакмэн: -// const float GAME_PACMAN_SIZE = ROOM_SIZE * 0.8; + const float GAME_PACMAN_SIZE = ROOM_SIZE * 0.8; // const sf::Keyboard::Key KEY_LEFT = sf::Keyboard::A; // const sf::Keyboard::Key KEY_RIGHT = sf::Keyboard::D; // const sf::Keyboard::Key KEY_UP = sf::Keyboard::W; @@ -41,9 +41,9 @@ namespace config { // 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_PACMAN{ 250, 150, 0 }; 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 }; + const sf::Color GAME_FOOD_COLOR{ 0, 200, 100 }; + const sf::Color GAME_ENEMY_COLOR{ 255, 50, 0 }; } \ No newline at end of file diff --git a/include/MazeContent/Entities/DynamicEntities/Enemy.h b/include/MazeContent/Entities/DynamicEntities/Enemy.h index bf1d23d..8dc3e67 100644 --- a/include/MazeContent/Entities/DynamicEntities/Enemy.h +++ b/include/MazeContent/Entities/DynamicEntities/Enemy.h @@ -4,12 +4,12 @@ class Enemy: public IDynamicEntity { public: - void prepare_for_drawing() override; ///@todo - void draw_into(sf::RenderWindow& window) const override; ///@todo - std::unique_ptr<IDynamicEntity> clone() const override; ///@todo - void action() override; ///@todo + void prepare_for_drawing() override; + void draw_into(sf::RenderWindow& window) const override; + std::unique_ptr<IDynamicEntity> clone() const override; + void action() override; public: - Enemy(); ///@todo + Enemy(); private: sf::RectangleShape m_rectangle; sf::Clock m_stopwatch; diff --git a/include/MazeContent/Entities/Pacman.h b/include/MazeContent/Entities/Pacman.h index c7f844f..91f9f33 100644 --- a/include/MazeContent/Entities/Pacman.h +++ b/include/MazeContent/Entities/Pacman.h @@ -4,11 +4,11 @@ class Pacman: public IEntity { public: - void prepare_for_drawing() override; ///@todo - void draw_into(sf::RenderWindow& window) const override; ///@todo + void prepare_for_drawing() override; + void draw_into(sf::RenderWindow& window) const override; void move(Room::Direction direction); public: - Pacman(); ///@todo + Pacman(); private: sf::CircleShape m_circle; }; \ No newline at end of file diff --git a/include/MazeContent/Entities/StaticEntities/Food.h b/include/MazeContent/Entities/StaticEntities/Food.h index cd589eb..f250579 100644 --- a/include/MazeContent/Entities/StaticEntities/Food.h +++ b/include/MazeContent/Entities/StaticEntities/Food.h @@ -4,11 +4,11 @@ class Food: public IStaticEntity { public: - void prepare_for_drawing() override; ///@todo - void draw_into(sf::RenderWindow& window) const override; ///@todo - std::unique_ptr<IStaticEntity> clone() override; ///@todo + void prepare_for_drawing() override; + void draw_into(sf::RenderWindow& window) const override; + std::unique_ptr<IStaticEntity> clone() const override; public: - Food(); ///@todo + Food(); private: sf::CircleShape m_circle; }; \ No newline at end of file diff --git a/include/States/GameState.h b/include/States/GameState.h index 873073a..761979d 100644 --- a/include/States/GameState.h +++ b/include/States/GameState.h @@ -9,6 +9,11 @@ class GameState: public IState, public IWindowKeeper { public: void set_maze(Maze&& maze); void set_context(GameContext&& context); + bool do_step() override; ///@todo +protected: + void event_handling() override; ///@todo + void update() override; ///@todo + void render() override; ///@todo public: GameState(IStateManager& state_manager, const sf::VideoMode& video_mode, const std::string& window_title); diff --git a/include/States/SelectState.h b/include/States/SelectState.h index de523e9..1d4c370 100644 --- a/include/States/SelectState.h +++ b/include/States/SelectState.h @@ -6,6 +6,7 @@ class SelectState: public IState, public IWindowKeeper { public: bool do_step() override; +protected: void event_handling() override; void update() override; void render() override; diff --git a/source/Builder/Builders/CommonBuilder.cpp b/source/Builder/Builders/CommonBuilder.cpp index 8c9e575..f345679 100644 --- a/source/Builder/Builders/CommonBuilder.cpp +++ b/source/Builder/Builders/CommonBuilder.cpp @@ -1,5 +1,53 @@ #include "Builder/Builders/CommonBuilder.h" +#include "MazeContent/Entities/DynamicEntities/Enemy.h" +#include "MazeContent/Entities/StaticEntities/Food.h" 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) { + std::vector<Room*> buffer; + for (auto& row : m_rooms) { + for (auto& room : row) { + buffer.push_back(room.get()); + } + } + + int pos = std::rand() % buffer.size(); + m_context.pacman.set_location(buffer.at(pos)); + buffer.erase(buffer.begin() + pos); + + size_t rooms_in_col = static_cast<size_t>(m_height / m_room_size) % 2 == 0 ? m_height / m_room_size - 1 : m_height / m_room_size; + size_t rooms_in_row = static_cast<size_t>(m_width / m_room_size) % 2 == 0 ? m_width / m_room_size - 1 : m_width / m_room_size; + for (size_t i = 0; i < static_cast<size_t>(rooms_in_row * rooms_in_col * dynamic_objects_ratio); ++i) { + pos = std::rand() % buffer.size(); + m_context.dynamic_objects.emplace_back(std::move(std::make_unique<Enemy>())); + m_context.dynamic_objects.back()->set_location(buffer.at(pos)); + buffer.erase(buffer.begin() + pos); + } + + for (size_t i = 0; i < buffer.size(); ++i) { + m_context.static_objects.emplace_back(std::move(std::make_unique<Food>())); + m_context.static_objects.back()->set_location(buffer.at(i)); + } + buffer.clear(); +} + +void CommonBuilder::create_state(IStateManager& state_manager, + sf::VideoMode video_mode, const std::string& window_title) { + m_game_state = std::make_unique<GameState>(state_manager, video_mode, window_title); +} + +void CommonBuilder::set_all_to_state() { + std::vector<std::unique_ptr<Room>> rooms; + for (auto& row : m_rooms) { + for (auto& room : row) + rooms.emplace_back(std::move(room)); + } + m_game_state->set_maze(Maze(std::move(rooms))); + m_game_state->set_context(std::move(m_context)); +} + +std::unique_ptr<GameState> CommonBuilder::get_game() { + return std::move(m_game_state); +} \ No newline at end of file diff --git a/source/Builder/GameBuilderDirector.cpp b/source/Builder/GameBuilderDirector.cpp new file mode 100644 index 0000000..d69bd8e --- /dev/null +++ b/source/Builder/GameBuilderDirector.cpp @@ -0,0 +1,15 @@ +#include "Builder/GameBuilderDirector.h" + +GameBuilderDirector::GameBuilderDirector(std::unique_ptr<IGameBuilder> ptr_builder, + const sf::VideoMode& video_mode, const std::string& window_title, float dynamic_objects_ratio) : + m_ptr_builder(std::move(ptr_builder)), m_video_mode(video_mode), m_window_title(window_title), + m_dynamic_object_ratio(dynamic_objects_ratio) {} + +std::unique_ptr<GameState> GameBuilderDirector::build(IStateManager& state_manager) { + m_ptr_builder->create_rooms(); + m_ptr_builder->set_rooms_sides(); + m_ptr_builder->create_context(m_dynamic_object_ratio); + m_ptr_builder->create_state(state_manager, m_video_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/MazeContent/Entities/DynamicEntities/Enemy.cpp b/source/MazeContent/Entities/DynamicEntities/Enemy.cpp index 989bfcb..e530548 100644 --- a/source/MazeContent/Entities/DynamicEntities/Enemy.cpp +++ b/source/MazeContent/Entities/DynamicEntities/Enemy.cpp @@ -1,9 +1,23 @@ #include "MazeContent/Entities/DynamicEntities/Enemy.h" +#include "Config.h" + +Enemy::Enemy() : m_rectangle({ config::GAME_ENEMY_SIZE / 2, config::GAME_ENEMY_SIZE / 2 }) { + m_rectangle.setOrigin(m_rectangle.getSize() / 2.f); + m_rectangle.setFillColor(config::GAME_ENEMY_COLOR); +} std::unique_ptr<IDynamicEntity> Enemy::clone() const { return std::make_unique<Enemy>(*this); } +void Enemy::prepare_for_drawing() { + m_rectangle.setPosition(m_ptr_room->get_position()); +} + +void Enemy::draw_into(sf::RenderWindow& window) const { + window.draw(m_rectangle); +} + void Enemy::action() { auto miliseconds = static_cast<size_t>(m_stopwatch.getElapsedTime().asMilliseconds()); if (miliseconds < rand() % 10000) diff --git a/source/MazeContent/Entities/Pacman.cpp b/source/MazeContent/Entities/Pacman.cpp index 7799733..867174f 100644 --- a/source/MazeContent/Entities/Pacman.cpp +++ b/source/MazeContent/Entities/Pacman.cpp @@ -1,4 +1,18 @@ #include "MazeContent/Entities/Pacman.h" +#include <Config.h> + +Pacman::Pacman() :m_circle(config::GAME_PACMAN_SIZE / 2) { + m_circle.setOrigin(m_circle.getRadius(), m_circle.getRadius()); + m_circle.setFillColor(config::GAME_COLOR_PACMAN); +} + +void Pacman::prepare_for_drawing() { + m_circle.setPosition(m_ptr_room->get_position()); +} + +void Pacman::draw_into(sf::RenderWindow& window) const { + window.draw(m_circle); +} void Pacman::move(Room::Direction direction) { m_ptr_room->get_side(direction)->enter(this); diff --git a/source/MazeContent/Entities/StaticEntities/Food.cpp b/source/MazeContent/Entities/StaticEntities/Food.cpp new file mode 100644 index 0000000..3b3d683 --- /dev/null +++ b/source/MazeContent/Entities/StaticEntities/Food.cpp @@ -0,0 +1,19 @@ +#include "MazeContent/Entities/StaticEntities/Food.h" +#include "Config.h" + +Food::Food() : m_circle{config::GAME_FOOD_SIZE / 2} { + m_circle.setOrigin(m_circle.getRadius(), m_circle.getRadius()); + m_circle.setFillColor(config::GAME_FOOD_COLOR); +} + +std::unique_ptr<IStaticEntity> Food::clone() const { + return std::make_unique<Food>(*this); +} + +void Food::prepare_for_drawing() { + m_circle.setPosition(m_ptr_room->get_position()); +} + +void Food::draw_into(sf::RenderWindow& window) const { + window.draw(m_circle); +} \ No newline at end of file -- GitLab