GameBuilder.cpp 16.58 KiB
#include <States/GameState/GameBuilder/GameBuilder.h>
#include <random>
#include <queue>
void CommonBuilder::create_context(const float dynamic_objets_ratio) {
    std::mt19937 gen(std::random_device{}());
    std::vector<std::vector<std::unique_ptr<Room>>::iterator> buf_rooms;
    for (auto& row : m_rooms) {
        for (auto room = row.begin(); room != row.end(); ++room) {
            if (*room == nullptr) continue;
            buf_rooms.push_back(room);
    if (buf_rooms.empty()) return;
    std::uniform_int_distribution distrib(0 , static_cast<int>(buf_rooms.size()-1));
    auto pos = buf_rooms.begin() + distrib(gen);
    const sf::Vector2f pacman_pos = (*pos)->get()->get_position();
    m_context.pacman.set_initial_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);
    for (size_t i = 0; i < number_of_dynamic_entities; ++i) {
        distrib.param(std::uniform_int_distribution<>::param_type(0, static_cast<int>(buf_rooms.size()) - 1));
        pos = buf_rooms.begin() + distrib(gen);
        if (float pos_x = (*pos)->get()->get_position().x, pos_y = (*pos)->get()->get_position().y;
            std::sqrt((pos_x-pacman_pos.x) * (pos_x-pacman_pos.x) + (pos_y-pacman_pos.y) * (pos_y-pacman_pos.y)) <= m_room_size * 2) {
            m_context.static_objects.emplace_back(std::move(std::make_unique<Food>()));
            m_context.static_objects.back()->set_initial_location((*pos)->get());
        else {
            m_context.dynamic_objects.emplace_back(std::move(std::make_unique<Enemy>()));
            m_context.dynamic_objects.back()->set_initial_location((*pos)->get());
        buf_rooms.erase(pos);
    for (const auto& it_room : buf_rooms) {
        m_context.static_objects.emplace_back(std::move(std::make_unique<Food>()));
        m_context.static_objects.back()->set_initial_location(it_room->get());
void CommonBuilder::create_state(IStateManager& state_manager, const sf::VideoMode& mode, const std::string& window_title) {
    m_game_state = std::make_unique<GameState>(state_manager, 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) {
            if (room == nullptr) continue;
            rooms.emplace_back(std::move(room));
    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),
        number_of_rooms_in_col = static_cast<size_t>(m_height / m_room_size);
    const 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
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
); 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() { if (m_rooms.empty()) return; if (m_rooms[0].empty()) return; for (const auto & room : m_rooms[0]) room->set_side(Room::UP, std::make_shared<Wall>(*room)); m_rooms[0][0]->set_side(Room::LEFT, std::make_shared<Wall>(*m_rooms[0][0])); for (size_t i = 1; i < m_rooms[0].size() - 1; ++i) { auto tmp_side_ptr = std::make_shared<Pass>(*m_rooms[0][i], *m_rooms[0][i-1]); m_rooms[0][i]->set_side(Room::LEFT, tmp_side_ptr); m_rooms[0][i-1]->set_side(Room::RIGHT, tmp_side_ptr); } auto tmp_side_ptr = std::make_shared<Pass>(*m_rooms[0][m_rooms[0].size()-1], *m_rooms[0][m_rooms[0].size()-2]); m_rooms[0][m_rooms[0].size()-1]->set_side(Room::LEFT, tmp_side_ptr); m_rooms[0][m_rooms[0].size()-2]->set_side(Room::RIGHT, tmp_side_ptr); m_rooms[0][m_rooms[0].size()-1]->set_side(Room::RIGHT, std::make_shared<Wall>(*m_rooms[0][m_rooms[0].size()-1])); for (size_t i = 1; i < m_rooms.size(); ++i) { m_rooms[i][0]->set_side(Room::LEFT, std::make_shared<Wall>(*m_rooms[i][0])); tmp_side_ptr = std::make_shared<Pass>(*m_rooms[i][0], *m_rooms[i-1][0]); m_rooms[i][0]->set_side(Room::UP, tmp_side_ptr); m_rooms[i-1][0]->set_side(Room::DOWN, tmp_side_ptr); for (size_t j = 1; j < m_rooms[i].size(); ++j) { tmp_side_ptr = std::make_shared<Pass>(*m_rooms[i][j], *m_rooms[i-1][j]); m_rooms[i][j]->set_side(Room::UP, tmp_side_ptr); m_rooms[i-1][j]->set_side(Room::DOWN, tmp_side_ptr); tmp_side_ptr = std::make_shared<Pass>(*m_rooms[i][j], *m_rooms[i][j-1]); m_rooms[i][j]->set_side(Room::LEFT, tmp_side_ptr); m_rooms[i][j-1]->set_side(Room::RIGHT, tmp_side_ptr); } m_rooms[i][m_rooms[i].size()-1]->set_side(Room::RIGHT, std::make_shared<Wall>(*m_rooms[i][m_rooms[i].size()-1])); } for (const auto & room : m_rooms[m_rooms.size()-1]) { room->set_side(Room::DOWN, std::make_shared<Wall>(*room)); } } void ComplexBuilder::create_rooms() { const auto number_of_rooms_in_row = static_cast<size_t>(m_width / m_room_size), number_of_rooms_in_col = static_cast<size_t>(m_height / m_room_size); const 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) { if (i % 2 == 0 && j % 2 == 0) continue; 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));
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
} } void ComplexBuilder::set_rooms_sides() { if (m_rooms.empty()) return; if (m_rooms[0].empty()) return; for (size_t i = 0; i < m_rooms.size(); i+=2) { for (const auto & room : m_rooms[i]) { room->set_side(Room::LEFT, std::make_shared<Wall>(*room)); room->set_side(Room::RIGHT, std::make_shared<Wall>(*room)); } } for (const auto & room : m_rooms[0]) room->set_side(Room::UP, std::make_shared<Wall>(*room)); for (size_t i = 1; i < m_rooms.size() - 1; i+=2) { m_rooms[i][0]->set_side(Room::LEFT, std::make_shared<Wall>(*m_rooms[i][0])); m_rooms[i][0]->set_side(Room::UP, std::make_shared<Wall>(*m_rooms[i][0])); m_rooms[i][0]->set_side(Room::DOWN, std::make_shared<Wall>(*m_rooms[i][0])); for (size_t j = 1; j < m_rooms[i].size() - 1; ++j) { if (j % 2 == 0) { m_rooms[i][j]->set_side(Room::UP, std::make_shared<Wall>(*m_rooms[i][j])); m_rooms[i][j]->set_side(Room::DOWN, std::make_shared<Wall>(*m_rooms[i][j])); continue; } auto side_ptr_temp = std::make_shared<Pass>(*m_rooms[i][j], *m_rooms[i-1][j-j/2-1]); m_rooms[i][j]->set_side(Room::UP, side_ptr_temp); m_rooms[i-1][j-j/2-1]->set_side(Room::DOWN, side_ptr_temp); side_ptr_temp = std::make_shared<Pass>(*m_rooms[i][j], *m_rooms[i][j-1]); m_rooms[i][j]->set_side(Room::LEFT, side_ptr_temp); m_rooms[i][j-1]->set_side(Room::RIGHT, side_ptr_temp); side_ptr_temp = std::make_shared<Pass>(*m_rooms[i][j], *m_rooms[i][j+1]); m_rooms[i][j]->set_side(Room::RIGHT, side_ptr_temp); m_rooms[i][j+1]->set_side(Room::LEFT, side_ptr_temp); side_ptr_temp = std::make_shared<Pass>(*m_rooms[i][j], *m_rooms[i+1][j-j/2-1]); m_rooms[i][j]->set_side(Room::DOWN, side_ptr_temp); m_rooms[i+1][j-j/2-1]->set_side(Room::UP, side_ptr_temp); } if (m_rooms[i].size() % 2 == 1) { m_rooms[i][m_rooms[i].size()-1]->set_side(Room::UP, std::make_shared<Wall>(*m_rooms[i][m_rooms[i].size()-1])); m_rooms[i][m_rooms[i].size()-1]->set_side(Room::DOWN, std::make_shared<Wall>(*m_rooms[i][m_rooms[i].size()-1])); } else { auto side_ptr_temp = std::make_shared<Pass>(*m_rooms[i][m_rooms[i].size()-1], *m_rooms[i][m_rooms[i].size()-2]); m_rooms[i][m_rooms[i].size()-1]->set_side(Room::LEFT, side_ptr_temp); m_rooms[i][m_rooms[i].size()-2]->set_side(Room::RIGHT, side_ptr_temp); side_ptr_temp = std::make_shared<Pass>(*m_rooms[i][m_rooms[i].size()-1], *m_rooms[i-1][m_rooms[i].size()-1]); m_rooms[i][m_rooms[i].size()-1]->set_side(Room::UP, side_ptr_temp); m_rooms[i-1][m_rooms[i].size()-1]->set_side(Room::DOWN, side_ptr_temp); } m_rooms[i][m_rooms[i].size()-1]->set_side(Room::RIGHT, std::make_shared<Wall>(*m_rooms[i][m_rooms[i].size()-1])); } for (auto& room : m_rooms[m_rooms.size()-1]) room->set_side(Room::DOWN, std::make_shared<Wall>(*room)); if (m_rooms.size() % 2 == 0) { m_rooms[m_rooms.size()-1][0]->set_side(Room::UP, std::make_shared<Wall>(*m_rooms[m_rooms.size()-1][0])); m_rooms[m_rooms.size()-1][0]->set_side(Room::LEFT, std::make_shared<Wall>(*m_rooms[m_rooms.size()-1][0])); for (size_t i = 1; i < m_rooms[m_rooms.size()-1].size() - 1; ++i) { if (i % 2 == 0) { m_rooms[m_rooms.size()-1][i]->set_side(Room::UP, std::make_shared<Wall>(*m_rooms[m_rooms.size()-1][i])); continue; } auto side_ptr_temp = std::make_shared<Pass>(*m_rooms[m_rooms.size()-1][i], *m_rooms[m_rooms.size()-2][i-i/2-1]); m_rooms[m_rooms.size()-1][i]->set_side(Room::UP, side_ptr_temp); m_rooms[m_rooms.size()-2][i-i/2-1]->set_side(Room::DOWN, side_ptr_temp); side_ptr_temp = std::make_shared<Pass>(*m_rooms[m_rooms.size()-1][i-1], *m_rooms[m_rooms.size()-1][i]); m_rooms[m_rooms.size()-1][i]->set_side(Room::LEFT, side_ptr_temp); m_rooms[m_rooms.size()-1][i-1]->set_side(Room::RIGHT, side_ptr_temp); side_ptr_temp = std::make_shared<Pass>(*m_rooms[m_rooms.size()-1][i+1], *m_rooms[m_rooms.size()-1][i]); m_rooms[m_rooms.size()-1][i]->set_side(Room::RIGHT, side_ptr_temp); m_rooms[m_rooms.size()-1][i+1]->set_side(Room::LEFT, side_ptr_temp);
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
} if (m_rooms[m_rooms.size()-1].size() % 2 == 1) { m_rooms[m_rooms.size()-1][m_rooms[m_rooms.size()-1].size()-1]->set_side(Room::UP, std::make_shared<Wall>(*m_rooms[m_rooms.size()-1][m_rooms[m_rooms.size()-1].size()-1])); } else { auto side_ptr_temp = std::make_shared<Pass>(*m_rooms[m_rooms.size()-1][m_rooms[m_rooms.size()-1].size()-1], *m_rooms[m_rooms.size()-2][m_rooms[m_rooms.size()-1].size()-1]); m_rooms[m_rooms.size()-1][m_rooms[m_rooms.size()-1].size()-1]->set_side(Room::UP, side_ptr_temp); m_rooms[m_rooms.size()-2][m_rooms[m_rooms.size()-1].size()-1]->set_side(Room::DOWN, side_ptr_temp); } m_rooms[m_rooms.size()-1][m_rooms[m_rooms.size()-1].size()-1]->set_side(Room::RIGHT, std::make_shared<Wall>(*m_rooms[m_rooms.size()-1][m_rooms[m_rooms.size()-1].size()-1])); } } ComplexRandomBuilder::ComplexRandomBuilder(const float width, const float height, const float room_size, const sf::Color room_color) : CommonBuilder(width, height, room_size, room_color), m_rooms_grid(static_cast<size_t>(height / m_room_size), std::vector(static_cast<size_t>(width / m_room_size), false)), m_number_of_rooms_in_row(static_cast<size_t>(width / m_room_size)), m_number_of_rooms_in_col(static_cast<size_t>(height / m_room_size)), gen(rd()) {} bool ComplexRandomBuilder::is_valid(const int x, const int y) const { if (x >= m_number_of_rooms_in_row || y >= m_number_of_rooms_in_col || x < 0 || y < 0) return false; return true; } void ComplexRandomBuilder::collapse_function() { std::uniform_int_distribution<size_t> row_dist(0, m_number_of_rooms_in_row-1); std::uniform_int_distribution<size_t> col_dist(0, m_number_of_rooms_in_col-1); std::normal_distribution prob_dist(0.67f, 0.25f); size_t start_x = row_dist(gen); size_t start_y = col_dist(gen); m_rooms_grid[start_y][start_x] = true; size_t room_created = 1; std::queue<std::pair<size_t, size_t>> cells_to_process; cells_to_process.emplace(start_x, start_y); while (!cells_to_process.empty()) { const auto [x, y] = cells_to_process.front(); cells_to_process.pop(); std::vector<std::pair<int, int>> neighbors = { {x - 1, y}, {x + 1, y}, {x, y - 1}, {x, y + 1} }; std::shuffle(neighbors.begin(), neighbors.end(), gen); bool neighbor_created = false; for (const auto& [neighbor_x, neighbor_y] : neighbors) { if (is_valid(neighbor_x, neighbor_y) && !m_rooms_grid[neighbor_y][neighbor_x]) { if (room_created < 20 && !neighbor_created) { m_rooms_grid[neighbor_y][neighbor_x] = true; cells_to_process.emplace(neighbor_x, neighbor_y); neighbor_created = true; room_created++; } else if (prob_dist(gen) < 0.7f) { m_rooms_grid[neighbor_y][neighbor_x] = true; cells_to_process.emplace(neighbor_x, neighbor_y); } } } } } void ComplexRandomBuilder::create_rooms() { collapse_function(); const sf::Vector2f gap( (m_width - static_cast<float>(m_number_of_rooms_in_row) * m_room_size + m_room_size) / 2.f,
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
(m_height - static_cast<float>(m_number_of_rooms_in_col) * m_room_size + m_room_size) / 2.f ); m_rooms.clear(); for (size_t i = 0; i < m_number_of_rooms_in_col; ++i) { std::vector<std::unique_ptr<Room>> room_row; for (size_t j = 0; j < m_number_of_rooms_in_row; ++j) { if (m_rooms_grid[i][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.push_back(std::move(tmp_room)); } else room_row.push_back({}); } m_rooms.emplace_back(std::move(room_row)); } } void ComplexRandomBuilder::set_rooms_sides() { for (size_t i = 0; i < m_number_of_rooms_in_col; ++i) { for (size_t j = 0; j < m_number_of_rooms_in_row; ++j) { if (!m_rooms_grid[i][j]) continue; if (static_cast<int>(j) - 1 >= 0 && m_rooms_grid[i][j-1]) { auto side_ptr_temp = std::make_shared<Pass>(*m_rooms[i][j], *m_rooms[i][j-1]); m_rooms[i][j]->set_side(Room::LEFT, side_ptr_temp); m_rooms[i][j-1]->set_side(Room::RIGHT, side_ptr_temp); } else m_rooms[i][j]->set_side(Room::LEFT, std::make_unique<Wall>(*m_rooms[i][j])); if (static_cast<int>(j) + 1 < m_number_of_rooms_in_row && m_rooms_grid[i][j+1]) {} else m_rooms[i][j]->set_side(Room::RIGHT, std::make_unique<Wall>(*m_rooms[i][j])); if (static_cast<int>(i) - 1 >= 0 && m_rooms_grid[i-1][j]) { auto side_ptr_temp = std::make_shared<Pass>(*m_rooms[i][j], *m_rooms[i-1][j]); m_rooms[i][j]->set_side(Room::UP, side_ptr_temp); m_rooms[i-1][j]->set_side(Room::DOWN, side_ptr_temp); } else m_rooms[i][j]->set_side(Room::UP, std::make_unique<Wall>(*m_rooms[i][j])); if (static_cast<int>(i) + 1 < m_number_of_rooms_in_col && m_rooms_grid[i+1][j]) {} else m_rooms[i][j]->set_side(Room::DOWN, std::make_unique<Wall>(*m_rooms[i][j])); } } }