From 83a8ae2b51513442d3610bcf043dc80da4d20f6f Mon Sep 17 00:00:00 2001 From: KabaevaNadezhda <nekabaeva@edu.hse.ru> Date: Thu, 20 Mar 2025 17:40:48 +0300 Subject: [PATCH] Middle Commit --- Button.cpp | 10 +- Button.h | 4 +- CMakeLists.txt | 2 +- CommonBuilder.cpp | 65 ++++++++++++ CommonBuilder.h | 34 +++++++ ComplexBuilder.cpp | 50 ++++++++++ ComplexBuilder.h | 15 +++ Enemy.cpp | 12 +-- Enemy.h | 7 +- Food.h | 3 +- GameBuilderDirector.cpp | 23 +++-- GameBuilderDirector.h | 18 +++- GameContext.cpp | 37 +++---- GameContext.h | 18 ++-- GameState.cpp | 26 +++-- GameState.h | 3 +- IGameBuilder.h | 20 ++++ Maze.cpp | 10 ++ Maze.h | 8 +- Menu.cpp | 99 +++++++++++-------- Menu.h | 21 ++-- Pacman.cpp | 7 +- Pacman.h | 1 + SelectState.cpp | 27 ++--- SelectState.h | 2 +- SimpleBuilder.cpp | 50 ++++++++++ SimpleBuilder.h | 15 +++ ...\320\271 \321\204\320\260\320\271\320\273" | 0 28 files changed, 442 insertions(+), 145 deletions(-) create mode 100644 CommonBuilder.cpp create mode 100644 CommonBuilder.h create mode 100644 ComplexBuilder.cpp create mode 100644 ComplexBuilder.h create mode 100644 IGameBuilder.h create mode 100644 SimpleBuilder.cpp create mode 100644 SimpleBuilder.h create mode 100644 "\320\235\320\276\320\262\321\213\320\271 \321\204\320\260\320\271\320\273" diff --git a/Button.cpp b/Button.cpp index 22e4c13..cfc6b52 100644 --- a/Button.cpp +++ b/Button.cpp @@ -1,9 +1,9 @@ // Button.cpp #include "Button.h" -Button::Button() : m_ptr_command(nullptr), m_defaultFillColor(sf::Color::Black), m_selectedFillColor(sf::Color(70, 70, 150)) {} +Button::Button() : m_command(*(ISelectCommand*)nullptr), m_defaultFillColor(sf::Color::Black), m_selectedFillColor(sf::Color(70, 70, 150)) {} // Provide a default value -void Button::set(sf::Vector2f pos, sf::Vector2f button_size, const std::string& text, unsigned int font_size, ISelectCommand* ptr_command) { +void Button::set(sf::Vector2f pos, sf::Vector2f button_size, const std::string& text, unsigned int font_size, ISelectCommand& command) { m_rectangle.setPosition(pos); m_rectangle.setSize(button_size); m_rectangle.setFillColor(m_defaultFillColor); // Default fill color @@ -16,7 +16,7 @@ void Button::set(sf::Vector2f pos, sf::Vector2f button_size, const std::string& m_text.setFillColor(sf::Color::White); // White text color m_text.setPosition(pos.x + button_size.x / 2 - m_text.getLocalBounds().width / 2, pos.y + button_size.y / 2 - m_text.getLocalBounds().height / 2 - font_size / 4); - m_ptr_command = ptr_command; + m_command = command; } bool Button::is_position_in(sf::Vector2f pos) const { @@ -24,9 +24,7 @@ bool Button::is_position_in(sf::Vector2f pos) const { } void Button::push() { - if (m_ptr_command) { - m_ptr_command->execute(); - } + m_command.execute(); } void Button::draw_into(sf::RenderWindow& window) { diff --git a/Button.h b/Button.h index be4b493..c287872 100644 --- a/Button.h +++ b/Button.h @@ -10,13 +10,13 @@ class Button { private: sf::Text m_text; sf::RectangleShape m_rectangle; - ISelectCommand* m_ptr_command; + ISelectCommand& m_command; // Changed to a reference sf::Color m_defaultFillColor; sf::Color m_selectedFillColor; public: Button(); - void set(sf::Vector2f pos, sf::Vector2f button_size, const std::string& text, unsigned int font_size, ISelectCommand* ptr_command); + void set(sf::Vector2f pos, sf::Vector2f button_size, const std::string& text, unsigned int font_size, ISelectCommand& command); bool is_position_in(sf::Vector2f pos) const; void push(); void draw_into(sf::RenderWindow& window); diff --git a/CMakeLists.txt b/CMakeLists.txt index fae7003..c30bcc2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ add_executable(aip_lab3 "aip_lab3.cpp" "IState.h" "Application.h" "ExampleState.h" "IWindowKeeper.h" "ExitState.h" "SelectState.h" "GameState.h" "StateManager.h" - "Button.h" "Button.cpp" "Menu.cpp" "SelectState.cpp" "MyFont.h" "MyFont.cpp" "ISelectCommand.h" "StartGameCommand.h" "StartGameCommand.cpp" "ExitCommand.h" "ExitCommand.cpp" "StateManager.cpp" "GameState.cpp" "ExitState.cpp" "ChangeStateCommand.h" "GameCommand.h" "GameCommand.cpp" "GameBuilderDirector.h" "GameBuilderDirector.cpp" "GameBuilder.h" "SimpleGameBuilder.h" "SimpleGameBuilder.cpp" "ChangeStateCommand.cpp" "IRoomSide.h" "Wall.h" "Wall.cpp" "Room.h" "Room.cpp" "Maze.h" "Maze.cpp" "IEntity.h" "Pass.h" "Pass.cpp" "IPreparable.h" "Pacman.h" "Pacman.cpp" "IStaticEntity.h" "IDynamicEntity.h" "Food.h" "Food.cpp" "Enemy.h" "Enemy.cpp" "GameContext.h" "GameContext.cpp" "ContextManager.h" "ContextManager.cpp") + "Button.h" "Button.cpp" "Menu.cpp" "SelectState.cpp" "MyFont.h" "MyFont.cpp" "ISelectCommand.h" "StartGameCommand.h" "StartGameCommand.cpp" "ExitCommand.h" "ExitCommand.cpp" "StateManager.cpp" "GameState.cpp" "ExitState.cpp" "ChangeStateCommand.h" "GameCommand.h" "GameCommand.cpp" "GameBuilderDirector.h" "GameBuilderDirector.cpp" "GameBuilder.h" "SimpleGameBuilder.h" "SimpleGameBuilder.cpp" "ChangeStateCommand.cpp" "IRoomSide.h" "Wall.h" "Wall.cpp" "Room.h" "Room.cpp" "Maze.h" "Maze.cpp" "IEntity.h" "Pass.h" "Pass.cpp" "IPreparable.h" "Pacman.h" "Pacman.cpp" "IStaticEntity.h" "IDynamicEntity.h" "Food.h" "Food.cpp" "Enemy.h" "Enemy.cpp" "GameContext.h" "GameContext.cpp" "ContextManager.h" "ContextManager.cpp" "IGameBuilder.h" "CommonBuilder.h" "CommonBuilder.cpp" "SimpleBuilder.h" "SimpleBuilder.cpp" "ComplexBuilder.h" "ComplexBuilder.cpp") include(FetchContent) diff --git a/CommonBuilder.cpp b/CommonBuilder.cpp new file mode 100644 index 0000000..09e1d5d --- /dev/null +++ b/CommonBuilder.cpp @@ -0,0 +1,65 @@ +#include "CommonBuilder.h" +#include "Room.h" +#include "Wall.h" +#include "Pass.h" +#include "Pacman.h" +#include "Maze.h" +#include <random> +#include <iostream> + +CommonBuilder::CommonBuilder(int width, int height, int room_size) + : m_width(width), m_height(height), m_room_size(room_size), m_dynamic_objects_ratio(0.0f), m_context(nullptr) { +} + +CommonBuilder::~CommonBuilder() { + for (Room* room : m_rooms) { + delete room; + } +} + +void CommonBuilder::create_context(float dynamic_objects_ratio) { + // Create Pacman (place him in the first room) + auto pacman = std::make_unique<Pacman>(m_rooms[0]); + // Create Maze + auto maze = std::make_unique<Maze>(); + for (Room* room : m_rooms) { + maze->addRoom(room); + } + + m_context = std::make_unique<GameContext>(std::move(pacman), std::move(maze)); + m_dynamic_objects_ratio = dynamic_objects_ratio; + + // Add static entities (food) to rooms + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_real_distribution<> distrib(0.0, 1.0); + + for (Room* room : m_rooms) { + // Add food randomly + if (distrib(gen) < 0.5) { // Adjust probability + m_context->getStaticObjects().push_back(std::make_unique<Food>(room)); + } + } + //Add enemies to rooms + for (Room* room : m_rooms) { + // Add enemies randomly + if (distrib(gen) < m_dynamic_objects_ratio) { // Adjust probability + m_context->getDynamicObjects().push_back(std::make_unique<Enemy>(room)); + } + } +} + +void CommonBuilder::create_state(IStateManager& state_manager, sf::VideoMode mode, std::string window_title) { + m_game_state = new GameState(state_manager); +} + +void CommonBuilder::set_all_to_state() { + if (m_game_state) { + //m_game_state->set_maze(new Maze(*m_context.getMaze())); // Remove this line + m_game_state->set_context(std::move(*m_context)); + } +} + +GameState* CommonBuilder::get_game() { + return m_game_state; +} \ No newline at end of file diff --git a/CommonBuilder.h b/CommonBuilder.h new file mode 100644 index 0000000..d4113c3 --- /dev/null +++ b/CommonBuilder.h @@ -0,0 +1,34 @@ +#ifndef COMMONBUILDER_H +#define COMMONBUILDER_H + +#include "IGameBuilder.h" +#include "Maze.h" +#include "GameContext.h" +#include <vector> +#include "Room.h" +#include "IStaticEntity.h" +#include "Food.h" +#include "Enemy.h" +#include <random> + +class CommonBuilder : public IGameBuilder { +protected: + int m_width; + int m_height; + int m_room_size; + std::vector<Room*> m_rooms; // Store rooms + std::unique_ptr<GameContext> m_context; // Context to build + GameState* m_game_state; // GameState to build + float m_dynamic_objects_ratio; + +public: + CommonBuilder(int width, int height, int room_size); + ~CommonBuilder() override; + + void create_context(float dynamic_objects_ratio) override; + void create_state(IStateManager& state_manager, sf::VideoMode mode, std::string window_title) override; + void set_all_to_state() override; + GameState* get_game() override; +}; + +#endif \ No newline at end of file diff --git a/ComplexBuilder.cpp b/ComplexBuilder.cpp new file mode 100644 index 0000000..29f3e84 --- /dev/null +++ b/ComplexBuilder.cpp @@ -0,0 +1,50 @@ +#include "ComplexBuilder.h" +#include "Room.h" +#include "Wall.h" +#include "Pass.h" +#include <iostream> + +ComplexBuilder::ComplexBuilder(int width, int height, int room_size) : CommonBuilder(width, height, room_size) {} + +ComplexBuilder::~ComplexBuilder() {} + +void ComplexBuilder::create_rooms() { + // Create a 3x3 grid of rooms + for (int y = 0; y < 3; ++y) { + for (int x = 0; x < 3; ++x) { + int roomId = y * 3 + x; + Room* room = new Room(roomId); + m_rooms.push_back(room); + } + } +} + +void ComplexBuilder::set_rooms_sides() { + // Connect rooms with walls and passes + for (int y = 0; y < 3; ++y) { + for (int x = 0; x < 3; ++x) { + int roomId = y * 3 + x; + Room* room = m_rooms[roomId]; + + // Create walls + for (int dir = Room::LEFT; dir <= Room::DOWN; ++dir) { + Room::Direction direction = static_cast<Room::Direction>(dir); + room->setSide(direction, new Wall(room)); + } + + // Connect rooms with passes + if (x < 2) { + // Connect rooms horizontally + Pass* pass = new Pass(room, m_rooms[roomId + 1]); + room->setSide(Room::RIGHT, pass); + m_rooms[roomId + 1]->setSide(Room::LEFT, pass); + } + if (y < 2) { + // Connect rooms vertically + Pass* pass = new Pass(room, m_rooms[roomId + 3]); + room->setSide(Room::DOWN, pass); + m_rooms[roomId + 3]->setSide(Room::UP, pass); + } + } + } +} \ No newline at end of file diff --git a/ComplexBuilder.h b/ComplexBuilder.h new file mode 100644 index 0000000..3f1b2bb --- /dev/null +++ b/ComplexBuilder.h @@ -0,0 +1,15 @@ +#ifndef COMPLEXBUILDER_H +#define COMPLEXBUILDER_H + +#include "CommonBuilder.h" + +class ComplexBuilder : public CommonBuilder { +public: + ComplexBuilder(int width, int height, int room_size); + ~ComplexBuilder() override; + + void create_rooms() override; + void set_rooms_sides() override; +}; + +#endif \ No newline at end of file diff --git a/Enemy.cpp b/Enemy.cpp index 4b5926a..d3d19cd 100644 --- a/Enemy.cpp +++ b/Enemy.cpp @@ -1,7 +1,6 @@ -//Enemy.cpp #include "Enemy.h" #include "Room.h" -#include "IRoomSide.h" // Include IRoomSide +#include "IRoomSide.h" #include <iostream> Enemy::Enemy(Room* startRoom) : m_location(startRoom) { @@ -10,8 +9,8 @@ Enemy::Enemy(Room* startRoom) : m_location(startRoom) { prepare_for_drawing(); } -//Enemy's Copy Constructor -Enemy::Enemy(const Enemy& other) : m_location(other.m_location), m_shape(other.m_shape) {} +// Copy constructor +Enemy::Enemy(const Enemy& other) : m_location(other.m_location), m_shape(other.m_shape), m_stopwatch(other.m_stopwatch) {} Enemy::~Enemy() {} @@ -27,7 +26,7 @@ void Enemy::setRoom(Room* room) { void Enemy::action() { auto milliseconds = static_cast<size_t>(m_stopwatch.getElapsedTime().asMilliseconds()); if (milliseconds < rand() % 5000) { - return; // Enemy does nothing + return; } if (m_location) { @@ -53,7 +52,6 @@ void Enemy::draw_into(sf::RenderWindow& window) { void Enemy::prepare_for_drawing() { if (m_location) { - // Example: Position enemy in the corner of the room - m_shape.setPosition(100 + (m_location->getId() * 100 % 500) + 10, 100 + (m_location->getId() * 100 / 500 * 100) + 10); // 10 is offset + m_shape.setPosition(100 + (m_location->getId() * 100 % 500) + 10, 100 + (m_location->getId() * 100 / 500 * 100) + 10); } } \ No newline at end of file diff --git a/Enemy.h b/Enemy.h index ae06edb..cb0be8b 100644 --- a/Enemy.h +++ b/Enemy.h @@ -1,21 +1,20 @@ -//Enemy.h #ifndef ENEMY_H #define ENEMY_H #include "IDynamicEntity.h" #include "Room.h" #include <SFML/Graphics.hpp> -#include <SFML/System.hpp> // Required for sf::Clock +#include <SFML/System.hpp> class Enemy : public IDynamicEntity { private: Room* m_location; - sf::RectangleShape m_shape; // Visual representation + sf::RectangleShape m_shape; sf::Clock m_stopwatch; public: Enemy(Room* startRoom); - Enemy(const Enemy& other); + Enemy(const Enemy& other); // Copy constructor ~Enemy() override; Room* getRoom() const override; diff --git a/Food.h b/Food.h index 22a0e25..bc3f228 100644 --- a/Food.h +++ b/Food.h @@ -5,6 +5,7 @@ #include "IStaticEntity.h" #include <SFML/Graphics.hpp> +// Food.h class Food : public IStaticEntity { private: Room* m_location; @@ -12,7 +13,7 @@ private: public: Food(Room* startRoom); - Food(const Food& other); + Food(const Food& other); // Copy constructor ~Food() override; Room* getRoom() const override; diff --git a/GameBuilderDirector.cpp b/GameBuilderDirector.cpp index 764c9b1..6a1c6a5 100644 --- a/GameBuilderDirector.cpp +++ b/GameBuilderDirector.cpp @@ -1,14 +1,23 @@ -// GameBuilderDirector.cpp #include "GameBuilderDirector.h" -#include "GameBuilder.h" // Forward declaration +#include "GameState.h" // Include GameState +#include <iostream> -GameBuilderDirector::GameBuilderDirector(GameBuilder* builder) : m_builder(builder) {} +GameBuilderDirector::GameBuilderDirector(IGameBuilder* builder, sf::VideoMode mode, std::string window_title, float dynamic_objects_ratio, IStateManager& state_manager) + : m_builder(builder), m_mode(mode), m_window_title(window_title), m_dynamic_objects_ratio(dynamic_objects_ratio), m_state_manager(state_manager) { +} GameBuilderDirector::~GameBuilderDirector() {} -void GameBuilderDirector::constructGame(int difficulty) { - if (m_builder) { - m_builder->buildLevel(difficulty); - // More building steps using the builder +GameState* GameBuilderDirector::build() { + if (!m_builder) { + std::cerr << "Error: No builder assigned to the director!" << std::endl; + return nullptr; } + + m_builder->create_rooms(); + m_builder->set_rooms_sides(); + m_builder->create_context(m_dynamic_objects_ratio); + m_builder->create_state(m_state_manager, m_mode, m_window_title); + m_builder->set_all_to_state(); + return m_builder->get_game(); } \ No newline at end of file diff --git a/GameBuilderDirector.h b/GameBuilderDirector.h index 2e61457..465b6cb 100644 --- a/GameBuilderDirector.h +++ b/GameBuilderDirector.h @@ -1,16 +1,24 @@ -// GameBuilderDirector.h #ifndef GAMEBUILDERDIRECTOR_H #define GAMEBUILDERDIRECTOR_H -class GameBuilder; // Forward declaration +#include "IGameBuilder.h" +#include "IStateManager.h" +#include <SFML/Graphics.hpp> +#include "GameState.h" class GameBuilderDirector { private: - GameBuilder* m_builder; + IGameBuilder* m_builder; + sf::VideoMode m_mode; + std::string m_window_title; + float m_dynamic_objects_ratio; + IStateManager& m_state_manager; + public: - GameBuilderDirector(GameBuilder* builder); + GameBuilderDirector(IGameBuilder* builder, sf::VideoMode mode, std::string window_title, float dynamic_objects_ratio, IStateManager& state_manager); ~GameBuilderDirector(); - void constructGame(int difficulty); // Difficulty levels: 1, 2, 3 + + GameState* build(); }; #endif \ No newline at end of file diff --git a/GameContext.cpp b/GameContext.cpp index 51ae257..a4922da 100644 --- a/GameContext.cpp +++ b/GameContext.cpp @@ -1,49 +1,40 @@ #include "GameContext.h" -#include "Food.h" // Include Food -#include "Enemy.h" // Include Enemy +#include "Food.h" +#include "Enemy.h" #include "Maze.h" -GameContext::GameContext(Pacman* pacman, Maze* maze) : m_pacman(pacman), m_maze(maze) {} +GameContext::GameContext(std::unique_ptr<Pacman> pacman, std::unique_ptr<Maze> maze) + : m_pacman(std::move(pacman)), m_maze(std::move(maze)) { +} -// Copy constructor GameContext::GameContext(const GameContext& other) : m_state(other.m_state) { - // Copy Pacman - m_pacman = new Pacman(*other.m_pacman); // Use Pacman's copy constructor - - // Copy Maze - m_maze = new Maze(*other.m_maze); + m_pacman = std::make_unique<Pacman>(*other.m_pacman); + m_maze = std::make_unique<Maze>(*other.m_maze); - // Clone static objects for (const auto& static_obj : other.m_static_objects) { - // Check if the static_obj is a Food object, and create a Food clone if (auto food = dynamic_cast<Food*>(static_obj.get())) { - m_static_objects.push_back(std::make_unique<Food>(*food)); //Use Food's copy constructor + m_static_objects.push_back(std::make_unique<Food>(*food)); } } - // Clone dynamic objects for (const auto& dynamic_obj : other.m_dynamic_objects) { - // Check if the dynamic_obj is an Enemy object, and create a Enemy clone if (auto enemy = dynamic_cast<Enemy*>(dynamic_obj.get())) { - m_dynamic_objects.push_back(std::make_unique<Enemy>(*enemy)); //Use Enemy's copy constructor + m_dynamic_objects.push_back(std::make_unique<Enemy>(*enemy)); } } } -GameContext::~GameContext() { - delete m_pacman; - delete m_maze; -} +GameContext::~GameContext() {} Pacman* GameContext::getPacman() const { - return m_pacman; + return m_pacman.get(); } -const std::vector<std::unique_ptr<IStaticEntity>>& GameContext::getStaticObjects() const { +std::vector<std::unique_ptr<IStaticEntity>>& GameContext::getStaticObjects() { // <--- Changed return m_static_objects; } -const std::vector<std::unique_ptr<IDynamicEntity>>& GameContext::getDynamicObjects() const { +std::vector<std::unique_ptr<IDynamicEntity>>& GameContext::getDynamicObjects() { // <--- Changed return m_dynamic_objects; } @@ -56,5 +47,5 @@ void GameContext::setState(State state) { } Maze* GameContext::getMaze() const { - return m_maze; + return m_maze.get(); } \ No newline at end of file diff --git a/GameContext.h b/GameContext.h index dbd94d6..2c15871 100644 --- a/GameContext.h +++ b/GameContext.h @@ -2,7 +2,7 @@ #define GAMECONTEXT_H #include <vector> -#include <memory> // For std::unique_ptr +#include <memory> #include "Pacman.h" #include "IStaticEntity.h" #include "IDynamicEntity.h" @@ -13,27 +13,23 @@ public: enum class State { INGAME, WIN, LOST }; private: - Pacman* m_pacman; + std::unique_ptr<Pacman> m_pacman; std::vector<std::unique_ptr<IStaticEntity>> m_static_objects; std::vector<std::unique_ptr<IDynamicEntity>> m_dynamic_objects; State m_state = State::INGAME; - Maze* m_maze; // Add Maze + std::unique_ptr<Maze> m_maze; public: - GameContext(Pacman* pacman, Maze* maze); // Add Maze - GameContext(const GameContext& other); // Copy constructor + GameContext(std::unique_ptr<Pacman> pacman, std::unique_ptr<Maze> maze); + GameContext(const GameContext& other); ~GameContext(); - // Getters and setters Pacman* getPacman() const; - const std::vector<std::unique_ptr<IStaticEntity>>& getStaticObjects() const; - const std::vector<std::unique_ptr<IDynamicEntity>>& getDynamicObjects() const; + std::vector<std::unique_ptr<IStaticEntity>>& getStaticObjects(); // <--- Changed + std::vector<std::unique_ptr<IDynamicEntity>>& getDynamicObjects(); // <--- Changed State getState() const; void setState(State state); - - // Add Maze Maze* getMaze() const; - }; #endif \ No newline at end of file diff --git a/GameState.cpp b/GameState.cpp index ef17d9b..d8a7a40 100644 --- a/GameState.cpp +++ b/GameState.cpp @@ -19,17 +19,31 @@ bool GameState::do_step(IStateManager& state_manager) { window.close(); } } - - window.clear(sf::Color::Green); - window.display(); - + render(); return window.isOpen(); } + //set maze using r-value reference -void GameState::set_maze(Maze&& maze) { - m_maze = new Maze(maze); +void GameState::set_maze(Maze* maze) { + m_maze = maze; } //set context using r-value reference void GameState::set_context(GameContext&& context) { m_context_manager.reset(std::move(context)); +} + +void GameState::render() { + window.clear(sf::Color::Green); + ContextManager& contextManager = m_context_manager; + GameContext& context = contextManager.get_current_context(); + Maze* maze = context.getMaze(); + if (maze) { + maze->draw_into(window); + } + Pacman* pacman = context.getPacman(); + if (pacman) { + pacman->draw_into(window); + } + + window.display(); } \ No newline at end of file diff --git a/GameState.h b/GameState.h index 754f49d..aa3d861 100644 --- a/GameState.h +++ b/GameState.h @@ -19,8 +19,9 @@ public: ~GameState() override; bool do_step(IStateManager& state_manager) override; - void set_maze(Maze&& maze); + void set_maze(Maze* maze); void set_context(GameContext&& context); + void render(); // Add render method }; #endif \ No newline at end of file diff --git a/IGameBuilder.h b/IGameBuilder.h new file mode 100644 index 0000000..baf39b9 --- /dev/null +++ b/IGameBuilder.h @@ -0,0 +1,20 @@ +#ifndef IGAMEBUILDER_H +#define IGAMEBUILDER_H + +#include "Maze.h" // Include Maze +#include "GameContext.h" // Include GameContext +#include "IStateManager.h" // Include +#include "GameState.h" + +class IGameBuilder { +public: + virtual ~IGameBuilder() {} + virtual void create_rooms() = 0; + virtual void set_rooms_sides() = 0; + virtual void create_context(float dynamic_objects_ratio) = 0; // Ratio of dynamic objects + virtual void create_state(IStateManager& state_manager, sf::VideoMode mode, std::string window_title) = 0; + virtual void set_all_to_state() = 0; + virtual GameState* get_game() = 0; +}; + +#endif \ No newline at end of file diff --git a/Maze.cpp b/Maze.cpp index 88c58b7..be09439 100644 --- a/Maze.cpp +++ b/Maze.cpp @@ -8,6 +8,11 @@ Maze::~Maze() { delete room; } } +Maze::Maze(const Maze& other) { + for (Room* room : other.m_rooms) { + m_rooms.push_back(new Room(*room)); + } +} void Maze::addRoom(Room* room) { m_rooms.push_back(room); @@ -20,4 +25,9 @@ Room* Maze::getRoom(int id) const { } } return nullptr; // Room not found +} +void Maze::draw_into(sf::RenderWindow& window) { + for (Room* room : m_rooms) { + room->draw_into(window); + } } \ No newline at end of file diff --git a/Maze.h b/Maze.h index 872d81f..c61dd5d 100644 --- a/Maze.h +++ b/Maze.h @@ -1,18 +1,22 @@ +//Maze.h #ifndef MAZE_H #define MAZE_H #include <vector> #include "Room.h" +#include "IDrawable.h" -class Maze { +class Maze : public IDrawable { private: std::vector<Room*> m_rooms; public: Maze(); ~Maze(); + Maze(const Maze& other); void addRoom(Room* room); Room* getRoom(int id) const; + void draw_into(sf::RenderWindow& window) override; }; -#endif \ No newline at end of file +#endif diff --git a/Menu.cpp b/Menu.cpp index 700a9ef..f1d7a2e 100644 --- a/Menu.cpp +++ b/Menu.cpp @@ -1,44 +1,68 @@ -//Menu.cpp #include "Menu.h" #include "StartGameCommand.h" #include "ExitCommand.h" -#include "GameCommand.h" // Include +#include "GameCommand.h" +#include "SimpleBuilder.h" +#include "ComplexBuilder.h" +#include "GameBuilderDirector.h" #include <iostream> +#include <SFML/Window/VideoMode.hpp> +#include <memory> -Menu::Menu(IStateManager& state_manager) : m_state_manager(state_manager) { - // Example buttons (you can add more) - addButton(100, 100, 200, 50, "Easy"); - addButton(100, 200, 200, 50, "Medium"); - addButton(100, 300, 200, 50, "Hard"); - addButton(100, 400, 200, 50, "Exit"); +Menu::Menu(IStateManager& state_manager) : m_state_manager(state_manager), m_buttons(MAX_BUTTONS) { + addButton(100, 100, 200, 50, "Easy", 0.2f); + addButton(100, 180, 200, 50, "Medium", 0.4f); + addButton(100, 260, 200, 50, "Hard", 0.6f); + addButton(100, 340, 200, 50, "Exit", 0.0f); // Exit doesn't need dynamic_objects_ratio } -void Menu::addButton(float x, float y, float width, float height, const std::string& text) { +void Menu::addButton(float x, float y, float width, float height, const std::string& text, float dynamic_objects_ratio) { if (m_buttonCount < m_buttons.size()) { - ISelectCommand* command = nullptr; - if (text == "Easy" || text == "Medium" || text == "Hard") { - // Create a GameBuilderDirector and GameBuilder - SimpleGameBuilder* builder = new SimpleGameBuilder(); - GameBuilderDirector* director = new GameBuilderDirector(builder); - command = new GameCommand(m_state_manager, director); + std::unique_ptr<ISelectCommand> command; + GameBuilderDirector* director = nullptr; + + if (text == "Easy") { + SimpleBuilder* builder = new SimpleBuilder(2, 2, 100); + director = new GameBuilderDirector( + builder, + sf::VideoMode(800, 600), + "Pacman - Easy", + dynamic_objects_ratio, + m_state_manager + ); + command = std::make_unique<GameCommand>(m_state_manager, director); + } + else if (text == "Medium") { + ComplexBuilder* builder = new ComplexBuilder(3, 3, 100); + director = new GameBuilderDirector( + builder, + sf::VideoMode(800, 600), + "Pacman - Medium", + dynamic_objects_ratio, + m_state_manager + ); + command = std::make_unique<GameCommand>(m_state_manager, director); + } + else if (text == "Hard") { + ComplexBuilder* builder = new ComplexBuilder(3, 3, 100); + director = new GameBuilderDirector( + builder, + sf::VideoMode(800, 600), + "Pacman - Hard", + dynamic_objects_ratio, + m_state_manager + ); + command = std::make_unique<GameCommand>(m_state_manager, director); } else if (text == "Exit") { - command = new ExitCommand(); + command = std::make_unique<ExitCommand>(); } - m_buttons[m_buttonCount].set(sf::Vector2f(x, y), sf::Vector2f(width, height), text, 24, command); + + m_buttons[m_buttonCount].set(sf::Vector2f(x, y), sf::Vector2f(width, height), text, 24, *command); m_buttonCount++; - } -} -bool Menu::handleMouseClick(sf::Vector2i mousePosition) { - sf::Vector2f mousePosF(static_cast<float>(mousePosition.x), static_cast<float>(mousePosition.y)); - for (size_t i = 0; i < m_buttonCount; ++i) { - if (m_buttons[i].is_position_in(mousePosF)) { - m_buttons[i].push(); - return true; // Click handled - } + if (director) delete director; } - return false; // No button clicked } void Menu::draw_into(sf::RenderWindow& window) { @@ -47,24 +71,13 @@ void Menu::draw_into(sf::RenderWindow& window) { } } -void Menu::handleMouseMove(sf::Vector2i mousePosition) { - sf::Vector2f mousePosF(static_cast<float>(mousePosition.x), static_cast<float>(mousePosition.y)); - Button* newSelectedButton = nullptr; - +bool Menu::handleMouseClick(const sf::Vector2i& mousePos) { + sf::Vector2f mousePosF(static_cast<float>(mousePos.x), static_cast<float>(mousePos.y)); for (size_t i = 0; i < m_buttonCount; ++i) { if (m_buttons[i].is_position_in(mousePosF)) { - newSelectedButton = &m_buttons[i]; - break; - } - } - - if (newSelectedButton != m_selectedButton) { - if (m_selectedButton) { - m_selectedButton->select(false); // Unselect previous button - } - if (newSelectedButton) { - newSelectedButton->select(true); // Select current button + m_buttons[i].push(); + return true; // Click handled } - m_selectedButton = newSelectedButton; } + return false; // No button clicked } \ No newline at end of file diff --git a/Menu.h b/Menu.h index 1eecc2b..269097c 100644 --- a/Menu.h +++ b/Menu.h @@ -1,27 +1,24 @@ -//Menu.h #ifndef MENU_H #define MENU_H -#include <SFML/Graphics.hpp> -#include <array> -#include "Button.h" -#include "GameBuilderDirector.h" // Include #include "IStateManager.h" -#include "SimpleGameBuilder.h" // Include +#include <vector> // Добавлено +#include "Button.h" +#include <SFML/Graphics.hpp> +#include <memory> // Добавлено class Menu { private: - std::array<Button, 4> m_buttons; - size_t m_buttonCount = 0; IStateManager& m_state_manager; - Button* m_selectedButton = nullptr; + std::vector<Button> m_buttons; // Изменить + size_t m_buttonCount = 0; + const size_t MAX_BUTTONS = 4; // Maximum number of buttons public: Menu(IStateManager& state_manager); - bool handleMouseClick(sf::Vector2i mousePosition); + void addButton(float x, float y, float width, float height, const std::string& text, float dynamic_objects_ratio); void draw_into(sf::RenderWindow& window); - void addButton(float x, float y, float width, float height, const std::string& text); - void handleMouseMove(sf::Vector2i mousePosition); + bool handleMouseClick(const sf::Vector2i& mousePos); }; #endif \ No newline at end of file diff --git a/Pacman.cpp b/Pacman.cpp index 9ab71c1..5d3689b 100644 --- a/Pacman.cpp +++ b/Pacman.cpp @@ -1,6 +1,6 @@ #include "Pacman.h" #include "Room.h" -#include "IRoomSide.h" // Include IRoomSide +#include "IRoomSide.h" #include <iostream> Pacman::Pacman(Room* startRoom) : m_location(startRoom) { @@ -9,6 +9,9 @@ Pacman::Pacman(Room* startRoom) : m_location(startRoom) { prepare_for_drawing(); } +// Copy constructor +Pacman::Pacman(const Pacman& other) : m_location(other.m_location), m_shape(other.m_shape) {} + Pacman::~Pacman() {} Room* Pacman::getRoom() const { @@ -42,6 +45,6 @@ void Pacman::draw_into(sf::RenderWindow& window) { void Pacman::prepare_for_drawing() { if (m_location) { // Example: Position Pacman in the center of the room - m_shape.setPosition(100 + (m_location->getId() * 100 % 500) + 30, 100 + (m_location->getId() * 100 / 500 * 100) + 30); // 30 is offset + m_shape.setPosition(100 + (m_location->getId() * 100 % 500) + 30, 100 + (m_location->getId() * 100 / 500 * 100) + 30); } } \ No newline at end of file diff --git a/Pacman.h b/Pacman.h index 455089c..5a8baea 100644 --- a/Pacman.h +++ b/Pacman.h @@ -12,6 +12,7 @@ private: public: Pacman(Room* startRoom); + Pacman(const Pacman& other); // Copy constructor ~Pacman() override; Room* getRoom() const override; diff --git a/SelectState.cpp b/SelectState.cpp index 7e0d69b..e96f482 100644 --- a/SelectState.cpp +++ b/SelectState.cpp @@ -1,18 +1,18 @@ -//SelectState.cpp #include "SelectState.h" -#include "GameState.h" // Include GameState for state transitions -#include "ExitState.h" // Include ExitState for state transitions +#include "GameState.h" +#include "ExitState.h" #include <iostream> -//using namespace std; - +#include "SimpleBuilder.h" // Include +#include "ComplexBuilder.h" // Include + SelectState::SelectState(IStateManager& state_manager) - : m_state_manager(state_manager), m_window(sf::VideoMode(800, 600), "Select State"), + : m_state_manager(state_manager), m_window(sf::VideoMode(800, 600), "Select State"), m_menu(state_manager) { // Add buttons to the menu - m_menu.addButton(100, 100, 200, 50, "Easy"); - m_menu.addButton(100, 200, 200, 50, "Medium"); - m_menu.addButton(100, 100, 200, 50, "Hard"); - m_menu.addButton(100, 200, 200, 50, "Exit"); + m_menu.addButton(100, 100, 200, 50, "Easy", 0.2f); + m_menu.addButton(100, 180, 200, 50, "Medium", 0.4f); + m_menu.addButton(100, 260, 200, 50, "Hard", 0.6f); + m_menu.addButton(100, 340, 200, 50, "Exit", 0.0f); } bool SelectState::do_step(IStateManager& state_manager) { @@ -31,12 +31,15 @@ void SelectState::event_handling() { else if (event.type == sf::Event::MouseButtonPressed) { if (event.mouseButton.button == sf::Mouse::Left) { sf::Vector2i mousePosition = sf::Mouse::getPosition(m_window); - m_menu.handleMouseClick(mousePosition); + if (m_menu.handleMouseClick(mousePosition)) { + // Handle button click here, if needed + } } } } } + void SelectState::update() { // Реализация метода update } @@ -54,3 +57,5 @@ sf::RenderWindow& SelectState::getRenderWindow() { return m_window; // Возвращение ссылки на объект m_window } + + diff --git a/SelectState.h b/SelectState.h index c388f79..7e59185 100644 --- a/SelectState.h +++ b/SelectState.h @@ -17,7 +17,7 @@ private: Menu m_menu; // The menu is stored by value public: - SelectState::SelectState(IStateManager& state_manager); + SelectState(IStateManager& state_manager); virtual bool do_step(IStateManager& state_manager) override; diff --git a/SimpleBuilder.cpp b/SimpleBuilder.cpp new file mode 100644 index 0000000..d1ceaff --- /dev/null +++ b/SimpleBuilder.cpp @@ -0,0 +1,50 @@ +#include "SimpleBuilder.h" +#include "Room.h" +#include "Wall.h" +#include "Pass.h" +#include <iostream> + +SimpleBuilder::SimpleBuilder(int width, int height, int room_size) : CommonBuilder(width, height, room_size) {} + +SimpleBuilder::~SimpleBuilder() {} + +void SimpleBuilder::create_rooms() { + // Create a simple 2x2 grid of rooms + for (int y = 0; y < 2; ++y) { + for (int x = 0; x < 2; ++x) { + int roomId = y * 2 + x; + Room* room = new Room(roomId); + m_rooms.push_back(room); + } + } +} + +void SimpleBuilder::set_rooms_sides() { + // Connect rooms with simple walls and passes + for (int y = 0; y < 2; ++y) { + for (int x = 0; x < 2; ++x) { + int roomId = y * 2 + x; + Room* room = m_rooms[roomId]; + + // Create walls + for (int dir = Room::LEFT; dir <= Room::DOWN; ++dir) { + Room::Direction direction = static_cast<Room::Direction>(dir); + room->setSide(direction, new Wall(room)); + } + + // Connect rooms with passes + if (x < 1) { + // Connect rooms horizontally + Pass* pass = new Pass(room, m_rooms[roomId + 1]); + room->setSide(Room::RIGHT, pass); + m_rooms[roomId + 1]->setSide(Room::LEFT, pass); + } + if (y < 1) { + // Connect rooms vertically + Pass* pass = new Pass(room, m_rooms[roomId + 2]); + room->setSide(Room::DOWN, pass); + m_rooms[roomId + 2]->setSide(Room::UP, pass); + } + } + } +} \ No newline at end of file diff --git a/SimpleBuilder.h b/SimpleBuilder.h new file mode 100644 index 0000000..b140f0d --- /dev/null +++ b/SimpleBuilder.h @@ -0,0 +1,15 @@ +#ifndef SIMPLEBUILDER_H +#define SIMPLEBUILDER_H + +#include "CommonBuilder.h" + +class SimpleBuilder : public CommonBuilder { +public: + SimpleBuilder(int width, int height, int room_size); + ~SimpleBuilder() override; + + void create_rooms() override; + void set_rooms_sides() override; +}; + +#endif \ No newline at end of file diff --git "a/\320\235\320\276\320\262\321\213\320\271 \321\204\320\260\320\271\320\273" "b/\320\235\320\276\320\262\321\213\320\271 \321\204\320\260\320\271\320\273" new file mode 100644 index 0000000..e69de29 -- GitLab