#include #include #include #include #include #include #include #include using namespace sf; using namespace std; // размеры карты const int H = 25; const int W = 34; // таймер для стрельбы первого и второго игроков float shootTimerFirst = 0; float shootTimerSecond = 0; // наша игровая карта до генерации String TileMap[H] = { " BBBBBBBBBBBBBBBBBBBBBBBB ", " BRRRR RRRRRRRRRRRRB ", "BBBBBBRRRRRRRRRRRRRRRRRRRRRRBBBBBB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "B RRRRRRRRRRRRRRRRRRRRRRRRRR RB", "B RRRRRRRRRRRRRRRRRRRRRRRRR RB", "B RRRRRRRRRRRRRRRRRRRRRRRR RB", "BRR RRRRRRRRRRRRRRRRRRRRRRRR RB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRR RR RRRRRRRRRRRRB", "BRRRRRRRRRRR RR RR RB", "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", }; // запоминаем нашу стандартную карту для перезаписи после рестарта String standart[H] = { " BBBBBBBBBBBBBBBBBBBBBBBB ", " BRRRR RRRRRRRRRRRRB ", "BBBBBBRRRRRRRRRRRRRRRRRRRRRRBBBBBB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "B RRRRRRRRRRRRRRRRRRRRRRRRRR RB", "B RRRRRRRRRRRRRRRRRRRRRRRRR RB", "B RRRRRRRRRRRRRRRRRRRRRRRR RB", "BRR RRRRRRRRRRRRRRRRRRRRRRRR RB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB", "BRRRRRRRRRRR RR RRRRRRRRRRRRB", "BRRRRRRRRRRR RR RR RB", "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", }; class Shell; class Settings // класс хранящий настройки. в данный момент только общую громкость звука { private: int volume; public: Settings() { volume = 100; Listener::setGlobalVolume(volume); // SFML функция. изменяет общую громкость звука } void setVolume(int db) { volume = db; Listener::setGlobalVolume(volume); } int getVolume() { return volume; } ~Settings() { } }; class Entity // обобщённый класс "Объектов" { protected: int currentAxis; // текущее направление движения int axis; // прошлое/текущее направление движения. используется для правильного выстрела в состоянии остановки float speed; String name; // имя у объекта FloatRect rect; // для хранения размеров и координат объекта int health; bool life; float dx, dy; // для передвижения по Х и У int cooldown; // время перезарядки public: Sprite sprite; String getName() { return name; } void setHealth(int damage) { health -= damage; } FloatRect getRect() { return rect; } void setLife() { life = false; } int getLife() { return life; } void setDx(float DX) { dx = DX; } void setDy(float DY) { dy = DY; } int getAxis() { return axis; } ~Entity() { } }; class Player : public Entity // класс главных игроков { private: int score; // кол-во набранных очков bool musicIsPlaying; // для включения и отключения звука движения танка public: Player() { } Player(Texture &image, String Name) { cooldown = 15000; // указываем время перезарядки для главных игроков life = true; musicIsPlaying = 0; // для начала танк стоит. звук движения танка не воспрозводится sprite.setTexture(image); // изменяем спрайт лист rect = FloatRect(15, 15, 30, 30); axis = 3; // по началу смотрим вверх score = 0; health = 100; name = Name; dx = dy = -0.01; currentAxis = 0; speed = 1; // указываем координаты спауна в зависимости от типа игрока(первый либо второй) if (name == "firstplayer") { rect.left = 400; rect.top = 690; } if (name == "secondplayer") { rect.left = 550; rect.top = 690; } } //главный метод обновления игроков void update(float time, Sound &repairSound, Sound &cooldownUPSound) { rect.left += dx*time*speed; // смещаем игрока по Х Collision(0, repairSound, cooldownUPSound); // проверяем столкновения с объектами по Х Physics(); // проверяем на смену грунта под танком rect.top += dy*time*speed; // смещаем по У Collision(1, repairSound, cooldownUPSound); // проверяем столкновения с объектами по У Physics(); sprite.setPosition(rect.left, rect.top); // изменяем координаты отрисовки спрайта if (health <= 0) life = false; if (cooldown < 10000) // минимальное время перезарядки = 10000 cooldown = 10000; // в зависимости от имени и направления движения танка изменяем картинку на правильную if (name == "firstplayer") { if (dx < 0) sprite.setTextureRect(IntRect(222, 32, -30, 30)); if (dx > 0) sprite.setTextureRect(IntRect(224, 32, 30, 30)); if (dy < 0) sprite.setTextureRect(IntRect(0, 32, 30, 30)); if (dy > 0) sprite.setTextureRect(IntRect(160, 32, 30, 30)); } if (name == "secondplayer") { if (dx < 0) sprite.setTextureRect(IntRect(222, 64, -30, 30)); if (dx > 0) sprite.setTextureRect(IntRect(224, 64, 30, 30)); if (dy < 0) sprite.setTextureRect(IntRect(0, 64, 30, 30)); if (dy > 0) sprite.setTextureRect(IntRect(127, 64, 30, 30)); } //если танк не стоит на месте, то запоминаем его направление для стрельбы if (currentAxis != 0) { axis = currentAxis; } currentAxis = 0; dx = 0; dy = 0; } // метод проверки игрока на столкновения с объектами карты. в случае наезда просто выталкиваем его обратно, // либо подбираем бонус(если объект на который вы наехали является бонусом) void Collision(int axis, Sound &repairSound, Sound &cooldownUPSound) { for (int i = rect.top / 30; i < (rect.top + rect.height) / 30; i++) for (int j = rect.left / 30; j < (rect.left + rect.width) / 30; j++) { if ((TileMap[i][j] == 'B') || (TileMap[i][j] == '0') || (TileMap[i][j] == '1') || (TileMap[i][j] == '2') || (TileMap[i][j] == '3') || (TileMap[i][j] == '4')) { if (axis == 0) { if (dx > 0) rect.left = j * 30 - 30; if (dx < 0) rect.left = j * 30 + 30; } if (axis == 1) { if (dy > 0) rect.top = i * 30 - 30; if (dy < 0) rect.top = i * 30 + 30; } } // в случае наезда на H - Health, воспроизводим звук починки танка, увеличиваем кол-во ХП и уничтожаем аптечку. if (TileMap[i][j] == 'H') { repairSound.play(); health += 25; TileMap[i][j] = ' '; } // в случае наезда на C - cooldown, воспроизводим звук улучшения орудия танка, уменьшаем время перезарядки и уничтожаем бонус if (TileMap[i][j] == 'C') { cooldownUPSound.play(); cooldown -= 1500; TileMap[i][j] = ' '; } } } // метод отвечающий за примитивную физику (изменение скорости в зависимости от типа грунта). // заезд засчитывается в случае наезда центра танка void Physics() { int i = (rect.top + 15) / 30; int j = (rect.left + 15) / 30; if (TileMap[i][j] == 'G') speed = 0.80; else if (TileMap[i][j] == 'W') speed = 0.60; else speed = 1; } void setCurrentAxis(int axis) { currentAxis = axis; } int getCurrentAxis() { return currentAxis; } int getShellAxis() { return axis; } float getRectLeft() { return rect.left; } float getRectTop() { return rect.top; } void setScore(int Score) { score += Score; } int getScore() { return score; } int getHealth() { return health; } int getCooldown() { return cooldown; } void setEngineStatus(int status) { musicIsPlaying = status; } // проверяем имя игрока, движется ли танк и предыдущее состояние для избежания зацикливания проигрывания звука void engineSound(Sound &engine1, Sound &engine2) { if (name == "firstplayer") { if ((musicIsPlaying == 0) && (currentAxis != 0)) { engine1.play(); musicIsPlaying = 1; } else if ((musicIsPlaying == 1) && (currentAxis == 0)) { engine1.stop(); musicIsPlaying = 0; } } if (name == "secondplayer") { if ((musicIsPlaying == 0) && (currentAxis != 0)) { engine2.play(); musicIsPlaying = 1; } else if ((musicIsPlaying == 1) && (currentAxis == 0)) { engine2.stop(); musicIsPlaying = 0; } } } ~Player() { } }; class Shell : public Entity // класс "Снаряд" { private: int direction; // направление движения снаряда String shotowner; // имя "владельца" снаряда. то есть тот, кто выстрелил public: Shell() { } Shell(Texture &image, int dir, float x, float y, String shotOwner) { sprite.setTexture(image); // изменяем спрайт лист rect = FloatRect(x, y, 13, 13); life = true; direction = dir; // направление движения снаряда shotowner = shotOwner; speed = 0.16; name = "Shell"; // в зависимости от направления движения указываем его скорость, начальные координаты и изменяем картинку switch (direction) { case 1: dx = -speed; dy = 0; rect.left -= 10; rect.top += 10; sprite.setTextureRect(IntRect(660, 202, 9, 9)); break; case 2: dx = speed; dy = 0; rect.left += 31; rect.top += 10; sprite.setTextureRect(IntRect(693, 202, 9, 9)); break; case 3: dx = 0; dy = -speed; rect.left += 10; rect.top -= 11; sprite.setTextureRect(IntRect(643, 202, 9, 9)); break; case 4: dx = 0; dy = speed; rect.left += 12; rect.top += 30; sprite.setTextureRect(IntRect(678, 202, 9, 9)); break; } } // главный метод обновления снаряда void update(float time, Sound &wallHitSound, Sound &wallHitSound2) { rect.left += dx*time*speed; // изменяем положение по Х rect.top += dy*time*speed; // ихменяем положение по У Collision(wallHitSound, wallHitSound2); // проверяем на столкновения со стенами sprite.setPosition(rect.left, rect.top); // изменяем положение снаряда } // проверка на столкновения с объектами окружения. // проверка осуществляется по двум точкам снаряда. отсчёт от левого верхнего угла // в случае если попали и стрелял игрок, то воспроизводим подходящий звук в зависимости от типа стены void Collision(Sound &wallHitSound, Sound &wallHitSound2) { int i = (5.5 + rect.top) / 30; int j = (2.5 + rect.left) / 30; if (TileMap[i][j] == 'B') { if ((shotowner == "firstplayer") || (shotowner == "secondplayer")) wallHitSound2.play(); life = false; } if (TileMap[i][j] == '1' || TileMap[i][j] == '2' || TileMap[i][j] == '3' || TileMap[i][j] == '4') { if ((shotowner == "firstplayer") || (shotowner == "secondplayer")) wallHitSound.play(); TileMap[i][j] = ' '; life = false; } if (TileMap[i][j] == '0') { if ((shotowner == "firstplayer") || (shotowner == "secondplayer")) wallHitSound.play(); switch (direction) { case 1: TileMap[i][j] = '1'; break; case 2: TileMap[i][j] = '2'; break; case 3: TileMap[i][j] = '3'; break; case 4: TileMap[i][j] = '4'; break; } life = false; } i = (4 + rect.top) / 30; j = (7 + rect.left) / 30; if (TileMap[i][j] == 'B') { if ((shotowner == "firstplayer") || (shotowner == "secondplayer")) wallHitSound2.play(); life = false; } if (TileMap[i][j] == '1' || TileMap[i][j] == '2' || TileMap[i][j] == '3' || TileMap[i][j] == '4') { if ((shotowner == "firstplayer") || (shotowner == "secondplayer")) wallHitSound.play(); TileMap[i][j] = ' '; life = false; } if (TileMap[i][j] == '0') { if ((shotowner == "firstplayer") || (shotowner == "secondplayer")) wallHitSound.play(); switch (direction) { case 1: TileMap[i][j] = '1'; break; case 2: TileMap[i][j] = '2'; break; case 3: TileMap[i][j] = '3'; break; case 4: TileMap[i][j] = '4'; break; } life = false; } } String getShotOwner() { return shotowner; } ~Shell() { } }; // список для хранения снарядов, а также итератор для работы с ним list shells; list::iterator itShell; class Enemy : public Entity // класс врага { private: float basicSpeed; // стандартная скорость float shootTimer; // таймер для стрельбы float moveTimer; // минимальное время для вызова рандомного изменения направления движения int randAxis; public: Enemy(Texture &image, String Name) { moveTimer = 0; shootTimer = 0; sprite.setTexture(image); // меняем картинку спрайта rect = FloatRect(30, 30, 30, 30); axis = 2; // начальное направление для стрельбы dx = 0.01; // начальное движение dy = 0; name = Name; life = true; // в зависимости от типа бота указываем точку спауна, базовую скорость, количество хп и время перезарядки if (name == "EasyBot") { rect.left = 50; rect.top = 300; basicSpeed = 1.15; health = 50; cooldown = 12500; } if (name == "MiddleBot") { rect.left = 350; basicSpeed = 1; health = 100; cooldown = 15000; } if (name == "Boss") { rect.left = 900; rect.top = 300; basicSpeed = 0.80; health = 150; cooldown = 17500; } speed = basicSpeed; // скорость приравнием к выбранной базовой скорости } // главный метод обновления врагов void update(float time) { // увеличиваем время с последней рандомной смены направления. // в случае превышения времени в 20000, обнуляем таймер и генерируем новое направление(может совпасть со старым) moveTimer += time; if (moveTimer > 20000) { moveTimer = 0; randAxis = rand() % 4; if (randAxis == 0) { dx = 0.01; dy = 0; } if (randAxis == 1) { dx = -0.01; dy = 0; } if (randAxis == 2) { dy = 0.01; dx = 0; } if (randAxis == 3) { dy = -0.01; dx = 0; } } rect.left += dx*time*speed; // изменяем координаты по Х Collision(0); // проверяем на столкновения с объектами по Х Physics(); // проверка на смену типа грунта rect.top += dy*time*speed; // изменяем координаты по У Collision(1); // проверяем на столкновения с объектами по У Physics(); // проверка на смену типа грунта sprite.setPosition(rect.left, rect.top); // изменяем положение спрайта if (health <= 0) life = false; // в зависимости от имени и направления движения танка выбираем картинку и изменяем направление для выстрела if (name == "EasyBot") { if (dx < 0) { sprite.setTextureRect(IntRect(320, 0, 30, 30)); axis = 1; } if (dx > 0) { sprite.setTextureRect(IntRect(451, 0, 30, 30)); axis = 2; } if (dy < 0) { sprite.setTextureRect(IntRect(254, 0, 30, 30)); axis = 3; } if (dy > 0) { sprite.setTextureRect(IntRect(384, 0, 30, 30)); axis = 4; } } if (name == "MiddleBot") { if (dx < 0) { sprite.setTextureRect(IntRect(320, 32, 30, 30)); axis = 1; } if (dx > 0) { sprite.setTextureRect(IntRect(449, 32, 30, 30)); axis = 2; } if (dy < 0) { sprite.setTextureRect(IntRect(256, 32, 30, 30)); axis = 3; } if (dy > 0) { sprite.setTextureRect(IntRect(415, 32, 30, 30)); axis = 4; } } if (name == "Boss") { if (dx < 0) { sprite.setTextureRect(IntRect(320, 64, 30, 30)); axis = 1; } if (dx > 0) { sprite.setTextureRect(IntRect(449, 64, 30, 30)); axis = 2; } if (dy < 0) { sprite.setTextureRect(IntRect(257, 64, 30, 30)); axis = 3; } if (dy > 0) { sprite.setTextureRect(IntRect(415, 64, 30, 30)); axis = 4; } } } // проверка на столкновение с объектами игрового окружения. // в случае столкновения выталкиваем игрока и увеличиваем шансы на вызов рандомной смены направление движения void Collision(int axis) { for (int i = rect.top / 30; i < (rect.top + rect.height) / 30; i++) for (int j = rect.left / 30; j < (rect.left + rect.width) / 30; j++) { if ((TileMap[i][j] == 'B') || (TileMap[i][j] == '0') || (TileMap[i][j] == '1') || (TileMap[i][j] == '2') || (TileMap[i][j] == '3') || (TileMap[i][j] == '4')) { if (axis == 0) { if (dx > 0) rect.left = j * 30 - rect.width; if (dx < 0) rect.left = j * 30 + 30; moveTimer += 550; } if (axis == 1) { if (dy > 0) rect.top = i * 30 - rect.height; if (dy < 0) rect.top = i * 30 + 30; moveTimer += 550; } } } } // метод отвечающий за примитивную физику (изменение скорости в зависимости от типа грунта). // заезд засчитывается в случае наезда центра танка // в отличии от метода игроков, здесь изменение происходит исходя из базовой скорости void Physics() { int i = (rect.top + 15) / 30; int j = (rect.left + 15) / 30; if (TileMap[i][j] == 'G') speed = basicSpeed - 0.25; else if (TileMap[i][j] == 'W') speed = basicSpeed - 0.45; else speed = basicSpeed; } // метод для стрельбы врага. void shooting(Texture &image) { if (name == "EasyBot") shells.push_back(new Shell(image, axis, rect.left, rect.top, "EasyBot")); if (name == "MiddleBot") shells.push_back(new Shell(image, axis, rect.left, rect.top, "MiddleBot")); if (name == "Boss") shells.push_back(new Shell(image, axis, rect.left, rect.top, "Boss")); } // изменяем время с последнего выстрела. в случае если оно больше времени перезарядки, то обнуляем таймер и стреляем void setShootTimer(float time, Texture &t) { shootTimer += time; if (shootTimer >= cooldown) { shootTimer = 0; shooting(t); } } int getHealth() { return health; } ~Enemy() { } }; class MainMenu // класс меню. отвечает за все пункты меню. включания завершение игры, паузу и т.п. { protected: // создаём объекты для дальнейшей загрузки текстур Texture menu_texture1, menu_texture2, menu_texture3, menu_texture4, main_menu_texture, background_texture, esc_texture, oneplayer_texture, twoplayers_texture, dark_main_menu_texture, description_texture, controller_texture, mainmenu_texture, pause_texture, continue_texture; Texture gameover_texture, newrecord_texture, settings_texture, volumeTexture, lowTexture, middleTexture, highTexture, mainMenuButtonTexture; // выбранный пункт меню, активно ли меню, выбранное кол-во игроков, рекорд игры int MenuNum, Menu, chooseAmountPlayer, recordScore; public: // в конструкторе загружаем необходимые текстуры и активируем главное меню MainMenu() { menu_texture1.loadFromFile("res/gui/1.png"); menu_texture2.loadFromFile("res/gui/2.png"); menu_texture3.loadFromFile("res/gui/3.png"); menu_texture4.loadFromFile("res/gui/4.png"); esc_texture.loadFromFile("res/gui/7.png"); oneplayer_texture.loadFromFile("res/gui/5.png"); twoplayers_texture.loadFromFile("res/gui/6.png"); background_texture.loadFromFile("res/gui/box.png"); main_menu_texture.loadFromFile("res/gui/wot5years_1024x768_noc_ru.jpg"); dark_main_menu_texture.loadFromFile("res/gui/tzYVSpWEq0s.jpg"); description_texture.loadFromFile("res/gui/9.png"); controller_texture.loadFromFile("res/gui/8.png"); mainmenu_texture.loadFromFile("res/gui/MainMenuLogo.png"); pause_texture.loadFromFile("res/gui/pause.png"); continue_texture.loadFromFile("res/gui/cont.png"); gameover_texture.loadFromFile("res/gui/GAME OVER.png"); newrecord_texture.loadFromFile("res/gui/new record.png"); settings_texture.loadFromFile("res/gui/settings.png"); volumeTexture.loadFromFile("res/gui/VOLUME.png"); lowTexture.loadFromFile("res/gui/LOW.png"); middleTexture.loadFromFile("res/gui/MIDDLE.png"); highTexture.loadFromFile("res/gui/HIGH.png"); mainMenuButtonTexture.loadFromFile("res/gui/MAIN MENU.png"); Menu = 1; MenuNum = 0; chooseAmountPlayer = 0; recordScore = 0; } // отрисовка главного меню и взаимодействие с ним void renderMenu(RenderWindow &window, Sound &enter, Sound &escSound, Settings &settings) { // создаём спрайты для пунктов меню и загружаем в них текстуру Sprite menu1(menu_texture1), menu2(menu_texture2), menu3(menu_texture3), menu4(menu_texture4), main_menu(main_menu_texture), background(background_texture), esc(esc_texture), oneplayer(oneplayer_texture), twoplayers(twoplayers_texture), dark_main_menu(dark_main_menu_texture), description(description_texture), controller(controller_texture), mainmenulogo(mainmenu_texture); Sprite settingsSprite(settings_texture), low(lowTexture), middle(middleTexture), high(highTexture), volumeSprite(volumeTexture); // изменяем положение кнопок menu1.setPosition(100, 230); menu2.setPosition(100, 290); menu3.setPosition(100, 350); settingsSprite.setPosition(100, 410); menu4.setPosition(100, 470); controller.setPosition(200, 290); esc.setPosition(20, 690); oneplayer.setPosition(100, 290); twoplayers.setPosition(100, 350); description.setPosition(200, 270); background.setPosition(90, 0); low.setPosition(250, 350); middle.setPosition(450, 350); high.setPosition(650, 350); mainmenulogo.setPosition(100.5, 50); // объект и цикл событий для взаимодействия с окном(закрытие, сворачивание, передвижение) Event event; while (window.isOpen()) { while (Menu) { while (window.pollEvent(event)) if (event.type == Event::Closed) { Menu = 0; window.close(); break; } // меняем цвет кнопок на белый menu1.setColor(Color::White); menu2.setColor(Color::White); menu3.setColor(Color::White); menu4.setColor(Color::White); settingsSprite.setColor(Color::White); // обнуляем выбранный пункт меню MenuNum = 0; // очищаем экран window.clear(); // в случае если курсор находится на кнопке, то изменяем цвет на жёлтый и изменяем выбранный пункт меню if (IntRect(104, 235, 290, 40).contains(Mouse::getPosition(window))) { menu1.setColor(Color::Yellow); MenuNum = 1; } if (IntRect(104, 295, 290, 40).contains(Mouse::getPosition(window))) { menu2.setColor(Color::Yellow); MenuNum = 2; } if (IntRect(104, 355, 290, 40).contains(Mouse::getPosition(window))) { menu3.setColor(Color::Yellow); MenuNum = 3; } if (IntRect(104, 415, 290, 40).contains(Mouse::getPosition(window))) { settingsSprite.setColor(Color::Yellow); MenuNum = 4; } if (IntRect(104, 475, 290, 40).contains(Mouse::getPosition(window))) { menu4.setColor(Color::Yellow); MenuNum = 5; } // если произошло нажатие левой кнопкой мыши // проверяем на выбранный пункт меню, воспроизводим звук перехода в меню и проделываем тоже самое, что и в начале прошлого пункта меню if (Mouse::isButtonPressed(Mouse::Left)) { if (MenuNum == 1) { enter.play(); while ((!Keyboard::isKeyPressed(Keyboard::Escape)) && (Menu)) { while (window.pollEvent(event)) if (event.type == Event::Closed) { Menu = 0; window.close(); break; } oneplayer.setColor(Color::White); twoplayers.setColor(Color::White); MenuNum = 0; window.clear(); if (IntRect(104, 295, 290, 40).contains(Mouse::getPosition(window))) { oneplayer.setColor(Color::Yellow); MenuNum = 6; } if (IntRect(104, 355, 290, 40).contains(Mouse::getPosition(window))) { twoplayers.setColor(Color::Yellow); MenuNum = 7; } if (Mouse::isButtonPressed(Mouse::Left)) { if (MenuNum == 6) { enter.play(); Menu = 0; } if (MenuNum == 7) { enter.play(); chooseAmountPlayer = 1; Menu = 0; } } window.draw(main_menu); window.draw(background); window.draw(esc); window.draw(oneplayer); window.draw(twoplayers); window.draw(mainmenulogo); window.display(); } escSound.play(); } if (MenuNum == 2) { while (window.pollEvent(event)) if (event.type == Event::Closed) { window.close(); break; } enter.play(); window.draw(dark_main_menu); window.draw(esc); window.draw(controller); window.display(); while (!Keyboard::isKeyPressed(Keyboard::Escape)) while (window.pollEvent(event)) if (event.type == Event::Closed) break; escSound.play(); } if (MenuNum == 3) { while (window.pollEvent(event)) if (event.type == Event::Closed) break; enter.play(); window.draw(dark_main_menu); window.draw(esc); window.draw(description); window.display(); while (!Keyboard::isKeyPressed(Keyboard::Escape)) while (window.pollEvent(event)) if (event.type == Event::Closed) break; escSound.play(); } if (MenuNum == 4) { enter.play(); while ((!Keyboard::isKeyPressed(Keyboard::Escape)) && (Menu)) { while (window.pollEvent(event)) if (event.type == Event::Closed) { Menu = 0; window.close(); break; } low.setColor(Color::White); middle.setColor(Color::White); high.setColor(Color::White); MenuNum = 0; window.clear(); if (IntRect(255, 355, 140, 40).contains(Mouse::getPosition(window))) { low.setColor(Color::Yellow); MenuNum = 1; } if (IntRect(455, 355, 140, 40).contains(Mouse::getPosition(window))) { middle .setColor(Color::Yellow); MenuNum = 2; } if (IntRect(655, 355, 140, 40).contains(Mouse::getPosition(window))) { high.setColor(Color::Yellow); MenuNum = 3; } if (Mouse::isButtonPressed(Mouse::Left)) { if (MenuNum == 1) { enter.play(); settings.setVolume(50); } if (MenuNum == 2) { enter.play(); settings.setVolume(75); } if (MenuNum == 3) { enter.play(); settings.setVolume(100); } } window.draw(dark_main_menu); window.draw(volumeSprite); window.draw(esc); window.draw(low); window.draw(middle); window.draw(high); window.display(); } escSound.play(); } if (MenuNum == 5) { enter.play(); Menu = false; window.close(); } } window.draw(main_menu); window.draw(background); window.draw(menu1); window.draw(menu2); window.draw(menu3); window.draw(menu4); window.draw(settingsSprite); window.draw(mainmenulogo); window.display(); } break; } } // отрисовка паузы void pauseMenu(RenderWindow &window) { // прогружаем наши текстуры в спрайт Sprite pause(pause_texture); Sprite continueSprite(continue_texture); Sprite dark_main_menu(dark_main_menu_texture); // указываем положение для кнопок continueSprite.setPosition(359, 350); Event event; while (window.isOpen()) { while (window.pollEvent(event)) if (event.type == Event::Closed) { window.close(); break; } continueSprite.setColor(Color::White); window.clear(); MenuNum = 0; if (IntRect(370, 355, 282, 40).contains(Mouse::getPosition(window))) { continueSprite.setColor(Color::Yellow); MenuNum = 1; } if (Mouse::isButtonPressed(Mouse::Left)) if (MenuNum == 1) break; // отрисовываем этот спрайт window.draw(dark_main_menu); window.draw(pause); window.draw(continueSprite); // показываем на экран window.display(); } window.clear(); } int getChooseAmountPlayer() { return chooseAmountPlayer; } // отрисовка конца игры для режима с двумя игроками // работает с файлом для режима с двумя игроками int gameOver(int firstScore, int secondScore, RenderWindow &window, Font &font) { Sprite mainMenuSprite(mainMenuButtonTexture); mainMenuSprite.setPosition(359, 325); bool boolExit = false; bool isRecord = false; Sprite newRecord(newrecord_texture); newRecord.setPosition(345, 570); Sprite gameOverSprite(gameover_texture); Sprite dark_main_menu(dark_main_menu_texture); // считываем рекорд с файла readFromFile(); // проверяем не превзошли ли мы прошлый рекорд // если превзошли, то приравнием это к рекорду и записываем в файл. // делаем пометку, что был сделан рекорд. это потребуется для отрисовки дополнительного спрайта if (recordScore < (firstScore + secondScore)) { recordScore = firstScore + secondScore; writeInFile(); isRecord = true; } // примитивный текст с выбранным шрифтом и размером. // указываем цвет // указываем позицию Text firstplayer("Firstplayer:", font, 30); firstplayer.setColor(Color::Red); firstplayer.setPosition(200, 350); Text secondplayer("Secondplayer:", font, 30); secondplayer.setColor(Color::Red); secondplayer.setPosition(700, 350); Text record("Record: ", font, 30); record.setColor(Color::Green); record.setPosition(430, 500); Text Score1("", font, 30); Score1.setColor(Color::Red); Score1.setPosition(200, 390); Text Score2("", font, 30); Score2.setColor(Color::Red); Score2.setPosition(700, 390); // дописываем количество очков к нашему созданному тексту ostringstream score; score << firstScore; Score1.setString("Score: " + score.str()); ostringstream score2; score2 << secondScore; Score2.setString("Score: " + score2.str()); ostringstream recordscore; recordscore << recordScore; record.setString("Record: " + recordscore.str()); // зацикливаем паузу пока игрок не нажмёт кнопку "продолжить" либо не закроет окно с игрой while (boolExit == false) { mainMenuSprite.setColor(Color::White); window.clear(); Event event; while (window.pollEvent(event)) { if (event.type == Event::Closed) { window.close(); return 0; } } if (IntRect(364, 330, 290, 40).contains(Mouse::getPosition(window))) { mainMenuSprite.setColor(Color::Yellow); MenuNum = 1; } if (Mouse::isButtonPressed(Mouse::Left)) if (MenuNum == 1) return 1; window.draw(dark_main_menu); window.draw(gameOverSprite); if(isRecord == true) window.draw(newRecord); window.draw(firstplayer); window.draw(secondplayer); window.draw(mainMenuSprite); window.draw(Score1); window.draw(Score2); window.draw(record); window.display(); } } // отрисовка конца игры для режима с одним игроком. отличается от прошлого режима отсутствием текста для второго игрока // работает с файлом для режима с одним игроком int gameOver(int firstScore, RenderWindow &window, Font &font) { Sprite mainMenuSprite(mainMenuButtonTexture); mainMenuSprite.setPosition(359, 325); bool boolExit = false; bool isRecord = false; Sprite newRecord(newrecord_texture); newRecord.setPosition(345, 570); Sprite gameOverSprite(gameover_texture); Sprite dark_main_menu(dark_main_menu_texture); readFromFile(); if (recordScore < firstScore) { recordScore = firstScore; writeInFile(); isRecord = true; } Text firstplayer("Firstplayer:", font, 30); firstplayer.setColor(Color::Red); firstplayer.setPosition(430, 370); Text Score1("", font, 30); Score1.setColor(Color::Red); Score1.setPosition(430, 410); Text record("Record: ", font, 30); record.setColor(Color::Green); record.setPosition(430, 500); ostringstream score; score << firstScore; Score1.setString("Score: " + score.str()); ostringstream recordscore; recordscore << recordScore; record.setString("Record: " + recordscore.str()); while (boolExit == false) { mainMenuSprite.setColor(Color::White); window.clear(); Event event; while (window.pollEvent(event)) { if (event.type == Event::Closed) { window.close(); return 0; } } if (IntRect(364, 330, 290, 40).contains(Mouse::getPosition(window))) { mainMenuSprite.setColor(Color::Yellow); MenuNum = 1; } if (Mouse::isButtonPressed(Mouse::Left)) if (MenuNum == 1) return 1; window.draw(dark_main_menu); window.draw(gameOverSprite); if (isRecord == true) window.draw(newRecord); window.draw(firstplayer); window.draw(mainMenuSprite); window.draw(Score1); window.draw(record); window.display(); } } // метод чтения из файла void readFromFile() { ifstream fin; if (chooseAmountPlayer == 0) fin.open("res/data/oneplayer.data"); else fin.open("res/data/twoplayers.data"); if (!fin.is_open()) recordScore = 0; else fin >> recordScore; fin.close(); } // метод записи в файл // производится с полной очисткой файла void writeInFile() { ofstream fout; if (chooseAmountPlayer == 0) fout.open("res/data/oneplayer.data", ios_base::trunc); else fout.open("res/data/twoplayers.data", ios_base::trunc); fout << recordScore; fout.close(); } ~MainMenu() { } }; // список для хранения врагов, а также итераторы для работы с ним list enemies; list::iterator it; list::iterator it2; // список для хранения игроков, а также итераторы для работы с ним list players; list::iterator itPlayer; list::iterator itPlayer2; class Spawner // отвечает за рандомизацию спауна врагов { private: int access; // доступ к спауну int levelBot; // уровень(тип) врага float spawnTimer; // таймер public: Spawner() { access = 1; levelBot = 0; spawnTimer = 0; } void addNewEnemy() { access = rand() % 3; switch (access) { case 0: access = 1; break; case 1: access = 1; break; case 2: access = 0; break; } } void randomLevelEnemy() { levelBot = rand() % 6; switch (levelBot) { case 0: levelBot = 0; break; case 1: levelBot = 0; break; case 2: levelBot = 0; break; case 3: levelBot = 1; break; case 4: levelBot = 1; break; case 5: levelBot = 2; break; } } void setSpawnTimer(float time, Texture &t) { // если прошло достаточно времени с момента прошлого вызова спауна spawnTimer += time; if (spawnTimer > 40000) { spawnTimer = 0; spawnIsReady(t); } } void spawnIsReady(Texture &t) { // генерируем решение. шанс спауна ~66.7% addNewEnemy(); if (access == 1) { // генерируем нового врага randomLevelEnemy(); switch (levelBot) { case 0: enemies.push_back(new Enemy(t, "EasyBot")); break; case 1: enemies.push_back(new Enemy(t, "MiddleBot")); break; case 2: enemies.push_back(new Enemy(t, "Boss")); break; } } } ~Spawner() { } }; class Controller // класс управления танками { public: Controller() { } // проверяем имя игрока и даёт ему определённые кнопки управления танком void control(Player &input, Texture &t, Sound &shot) { if (input.getName() == "firstplayer") { if (shootTimerFirst > input.getCooldown()) { if (Keyboard::isKeyPressed(Keyboard::Space)) { shootTimerFirst = 0; shells.push_back(new Shell(t, input.getShellAxis(), input.getRectLeft(), input.getRectTop(), "firstplayer")); shot.play(); } } if (Keyboard::isKeyPressed(Keyboard::A) && input.getCurrentAxis() == 0) { input.setDx(-0.01); input.setCurrentAxis(1); } if (Keyboard::isKeyPressed(Keyboard::D) && input.getCurrentAxis() == 0) { input.setDx(0.01); input.setCurrentAxis(2); } if (Keyboard::isKeyPressed(Keyboard::W) && input.getCurrentAxis() == 0) { input.setDy(-0.01); input.setCurrentAxis(3); } if (Keyboard::isKeyPressed(Keyboard::S) && input.getCurrentAxis() == 0) { input.setDy(0.01); input.setCurrentAxis(4); } } if (input.getName() == "secondplayer") { if (shootTimerSecond > input.getCooldown()) { if (Keyboard::isKeyPressed(Keyboard::RControl)) { shootTimerSecond = 0; shells.push_back(new Shell(t, input.getShellAxis(), input.getRectLeft(), input.getRectTop(), "secondplayer")); shot.play(); } } if (Keyboard::isKeyPressed(Keyboard::Left) && input.getCurrentAxis() == 0) { input.setDx(-0.01); input.setCurrentAxis(1); } if (Keyboard::isKeyPressed(Keyboard::Right) && input.getCurrentAxis() == 0) { input.setDx(0.01); input.setCurrentAxis(2); } if (Keyboard::isKeyPressed(Keyboard::Up) && input.getCurrentAxis() == 0) { input.setDy(-0.01); input.setCurrentAxis(3); } if (Keyboard::isKeyPressed(Keyboard::Down) && input.getCurrentAxis() == 0) { input.setDy(0.01); input.setCurrentAxis(4); } } } ~Controller() { } }; class Bonus // класс генерации бонусов { private: int bonus; int randomBonus; public: Bonus() { bonus = 0; } // если уничтожили 5 танков, то вызываем генерацию бонуса и обнуляем счётчик void bonusIsReady() { if (bonus >= 5) { randBonus(); if (randomBonus == 0) TileMap[21][13] = 'H'; if (randomBonus == 1) TileMap[21][13] = 'C'; bonus = 0; } } void randBonus() { randomBonus = rand() % 2; } void setBonus() { bonus++; } }; class RandomMap // класс генерации карты перед началом игры { private: int randblock; public: RandomMap() { } // вызываем функцию с рандомом и приравниваем элементы игровой карты к соответствующему сгенерированному блоку void randomMap() { for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) { if (TileMap[i][j] == 'R') { randBlock(); switch (randblock) { case 1: TileMap[i][j] = 'W'; break; case 2: TileMap[i][j] = 'B'; break; case 3: TileMap[i][j] = '0'; break; case 4: TileMap[i][j] = 'G'; break; case 5: TileMap[i][j] = '0'; break; case 6: TileMap[i][j] = 'G'; break; case 7: TileMap[i][j] = 'W'; break; } } } } void randBlock() { randblock = rand() % 15; } ~RandomMap() { } }; class RenderMap // класс отрисовки карты { public: RenderMap() { } // проходим по матрице нашей карты, выбираем соответствующий тип, смещаем позицию, отрисовываем карту void renderMap(RenderWindow &window, Sprite tile) { for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) { if (TileMap[i][j] == 'B') tile.setTextureRect(IntRect(512, 32, 30, 30)); if (TileMap[i][j] == '0') tile.setTextureRect(IntRect(512, 0, 30, 30)); if (TileMap[i][j] == 'G') tile.setTextureRect(IntRect(545, 64, 30, 30)); if (TileMap[i][j] == 'W') tile.setTextureRect(IntRect(512, 64, 30, 30)); if (TileMap[i][j] == 'H') tile.setTextureRect(IntRect(672, 222, 30, 30)); if (TileMap[i][j] == 'C') tile.setTextureRect(IntRect(704, 224, 30, 30)); if (TileMap[i][j] == '1') tile.setTextureRect(IntRect(608, 0, 30, 30)); if (TileMap[i][j] == '2') tile.setTextureRect(IntRect(545, 0, 30, 30)); if (TileMap[i][j] == '3') tile.setTextureRect(IntRect(640, 0, 30, 30)); if (TileMap[i][j] == '4') tile.setTextureRect(IntRect(576, 0, 30, 30)); if (TileMap[i][j] == 'R') continue; if (TileMap[i][j] == ' ') continue; tile.setPosition(j * 30, i * 30); window.draw(tile); } } ~RenderMap() { } }; class GameGUI // игровое GUI (количество ХП и набранное кол-во очков в момент игры) { private: Text health1, health2, Score1, Score2; public: // изменяем шрифт, цвет и позицию текста GameGUI(Font &font) { health1.setFont(font); health1.setColor(Color::Red); health1.setPosition(0, -5); health2.setFont(font); health2.setColor(Color::Red); health2.setPosition(872, -5); Score1.setFont(font); Score1.setColor(Color::Red); Score1.setPosition(0, 22); Score2.setFont(font); Score2.setColor(Color::Red); Score2.setPosition(872, 22); } // в зависимости от имени игрока обновляем информацию на экране void drawGUI(RenderWindow &window, Player &itPlayer, Font &font) { if (itPlayer.getName() == "firstplayer") { ostringstream health; health << itPlayer.getHealth(); health1.setString("Health: " + health.str()); window.draw(health1); ostringstream score; score << itPlayer.getScore(); Score1.setString("Score: " + score.str()); window.draw(Score1); } if (itPlayer.getName() == "secondplayer") { ostringstream health; health << itPlayer.getHealth(); health2.setString("Health: " + health.str()); window.draw(health2); ostringstream score; score << itPlayer.getScore(); Score2.setString("Score: " + score.str()); window.draw(Score2); } } // если первый был убит, то приравнием информацию о здоровье к 0 void firstisKilled(RenderWindow &window, int firstScore) { health1.setString("Health: 0"); window.draw(health1); ostringstream score; score << firstScore; Score1.setString("Score: " + score.str()); window.draw(Score1); } // если второй был убит, то приравнием информацию о здоровье к 0 void secondisKilled(RenderWindow &window, int secondScore) { health2.setString("Health: 0"); window.draw(health2); ostringstream score; score << secondScore; Score2.setString("Score: " + score.str()); window.draw(Score2); } ~GameGUI() { } }; class DetectHIT // класс проверки попадания снаряда в игроков/врагов { public: DetectHIT() { } void detectHit(Bonus &bonusObj, Sound &tankExplosionSound, Sound &tankHitSound) { // проходим по списку снарядов for (itShell = shells.begin(); itShell != shells.end(); itShell++) { // проходим по списку врагов for (it2 = enemies.begin(); it2 != enemies.end(); it2++) { // если стрелял игрок if ((((*itShell)->getShotOwner() != "EasyBot") && ((*itShell)->getShotOwner() != "MiddleBot") && (*itShell)->getShotOwner() != "Boss")) if ((*it2)->getName() == "EasyBot" || (*it2)->getName() == "MiddleBot" || (*it2)->getName() == "Boss") // проверяем на пересечение прямоугольников с помощью метода встроенного в SFML if ((*itShell)->getRect().intersects((*it2)->getRect())) { // отнимаем здоровье и уничтожаем снаряд (*it2)->setHealth(50); (*itShell)->setLife(); // если стрелял первый игрок if ((*itShell)->getShotOwner() == "firstplayer") // проходим по списку игроков for (itPlayer = players.begin(); itPlayer != players.end(); itPlayer++) // находим первого игрока в списке if ((*itPlayer)->getName() == "firstplayer") // проверяем уничтожили ли мы танк противника // в случае уничтожения воспроизводим звук взрыва танка // проверяем тип уничтоженного бота // в зависимости от типа бота увеличиваем кол-во очков // если враг не был уничтожен, то просто воспроизводим звук попадания в танк if ((*it2)->getHealth() <= 0) { tankExplosionSound.play(); if ((*it2)->getName() == "EasyBot") (*itPlayer)->setScore(1); if ((*it2)->getName() == "MiddleBot") (*itPlayer)->setScore(2); if ((*it2)->getName() == "Boss") (*itPlayer)->setScore(3); bonusObj.setBonus(); } else tankHitSound.play(); // если стрелял второй игрок if ((*itShell)->getShotOwner() == "secondplayer") for (itPlayer2 = players.begin(); itPlayer2 != players.end(); itPlayer2++) // находим второго игрока и делаем тоже самое что и с первым if ((*itPlayer2)->getName() == "secondplayer") if ((*it2)->getHealth() <= 0) { tankExplosionSound.play(); if ((*it2)->getName() == "EasyBot") (*itPlayer2)->setScore(1); if ((*it2)->getName() == "MiddleBot") (*itPlayer2)->setScore(2); if ((*it2)->getName() == "Boss") (*itPlayer2)->setScore(3); bonusObj.setBonus(); } else tankHitSound.play(); break; } } // проходим по игрокам for (itPlayer = players.begin(); itPlayer != players.end(); itPlayer++) { // если стрелял лёгкий бот if ((*itShell)->getShotOwner() == "EasyBot") // проверяем пересечение прямоугольников средствами SFML // в случае успеха отнимаем кол-во хп соотвутствующее количеству урона от этого бота // выбираем нужный звук if ((*itShell)->getRect().intersects((*itPlayer)->getRect())) { (*itPlayer)->setHealth(30); if ((*itPlayer)->getHealth() <= 0) tankExplosionSound.play(); else tankHitSound.play(); (*itShell)->setLife(); break; } // проделываем тоже самое, что и с лёгким ботом. но увеличиваем урон if ((*itShell)->getShotOwner() == "MiddleBot") if ((*itShell)->getRect().intersects((*itPlayer)->getRect())) { (*itPlayer)->setHealth(40); if ((*itPlayer)->getHealth() <= 0) tankExplosionSound.play(); else tankHitSound.play(); (*itShell)->setLife(); break; } // проделываем тоже самое, что и с лёгким ботом. но увеличиваем урон if ((*itShell)->getShotOwner() == "Boss") if ((*itShell)->getRect().intersects((*itPlayer)->getRect())) { (*itPlayer)->setHealth(50); if ((*itPlayer)->getHealth() <= 0) tankExplosionSound.play(); else tankHitSound.play(); (*itShell)->setLife(); break; } } } } ~DetectHIT() { } }; bool startGame() // главная функция игры { // возвращаемый результат int result = 0; // создание окна средствами SFML RenderWindow window(VideoMode(1020, 750), "BattleCity Survival ALPHA"); // замена иконки программы Image icon; icon.loadFromFile("icon.png"); window.setIcon(128, 128, icon.getPixelsPtr()); // создаём необходимые объекты и загружаем необходимые файлы SoundBuffer enterBuffer; enterBuffer.loadFromFile("res/audio/enter.ogg"); SoundBuffer escBuffer; escBuffer.loadFromFile("res/audio/esc.ogg"); SoundBuffer shotBuffer; shotBuffer.loadFromFile("res/audio/shot.ogg"); SoundBuffer engineFirst; engineFirst.loadFromFile("res/audio/engine.ogg"); SoundBuffer engineSecond; engineSecond.loadFromFile("res/audio/engineSecond.ogg"); SoundBuffer tankExplosion; tankExplosion.loadFromFile("res/audio/tankExplosion.ogg"); SoundBuffer tankHit; tankHit.loadFromFile("res/audio/tankHit.ogg"); SoundBuffer repair; repair.loadFromFile("res/audio/repair.ogg"); SoundBuffer cooldownUP; cooldownUP.loadFromFile("res/audio/cooldownUP.ogg"); SoundBuffer wallHit; wallHit.loadFromFile("res/audio/wallHit.ogg"); SoundBuffer wallHit2; wallHit2.loadFromFile("res/audio/wallHit2.ogg"); Sound enter(enterBuffer); enter.setVolume(20); // изменение громкости Sound escSound(escBuffer); escSound.setVolume(20); Sound shot(shotBuffer); shot.setVolume(100); Sound engineSoundFirst(engineFirst); engineSoundFirst.setVolume(100); engineSoundFirst.setLoop(true); // бесконечное повторение звука Sound engineSoundSecond(engineSecond); engineSoundSecond.setVolume(100); engineSoundSecond.setLoop(true); Sound tankExplosionSound(tankExplosion); tankExplosionSound.setVolume(70); Sound tankHitSound(tankHit); tankHitSound.setVolume(100); Sound repairSound(repair); repairSound.setVolume(70); Sound cooldownUPSound(cooldownUP); cooldownUPSound.setVolume(70); Sound wallHitSound(wallHit); wallHitSound.setVolume(50); Sound wallHitSound2(wallHit2); wallHitSound2.setVolume(40); Controller controller; Spawner spawn; DetectHIT detecthit; RenderMap rendermap; Bonus bonusObj; Event event; RandomMap randMap; Settings settings; Font font; font.loadFromFile("res/gui/font/Candara.ttf"); Music musicMainMenu; musicMainMenu.openFromFile("res/audio/AnOrangePlanet-Percussion.ogg"); musicMainMenu.play(); musicMainMenu.setVolume(50); musicMainMenu.setLoop(true); MainMenu menu; // вызываем метод отрисовки главного меню menu.renderMenu(window, enter, escSound, settings); // останавливаем проигрывание звука главного меню musicMainMenu.stop(); Texture t; t.loadFromFile("res/gui/NES_-_Battle_City_-_General_Sprites.png"); Sprite tile(t); Texture ALPHA; ALPHA.loadFromFile("res/gui/ALPHA WORK IN PROGRESS.png"); Sprite picture(ALPHA); // изменение позиции и цвета picture.setPosition(675, 687); picture.setRotation(-1); picture.setColor(Color::White); GameGUI gameGUI(font); Music music; music.openFromFile("res/audio/AnOrangePlanet_loop_.ogg"); music.play(); // включаем звук игры music.setVolume(40); music.setLoop(true); int firstScore = 0; int secondScore = 0; randMap.randomMap(); // генерируем карту // в зависимости от типа игры выбранного в главном меню записываем в списки 1 или 2 объекта игроков players.push_back(new Player(t, "firstplayer")); if (menu.getChooseAmountPlayer() == 1) players.push_back(new Player(t, "secondplayer")); bool firstIsKilled = false; bool secondIsKilled = false; // запускаем лёгкого бота enemies.push_back(new Enemy(t, "EasyBot")); // запускаем таймер Clock clock; while (window.isOpen()) { // включаем вертикальную синхронизацию (синхронизация максимальной частоты кадров в секунду с вашей частотой обновления экрана) window.setVerticalSyncEnabled(true); // берём затраченное время на цикл в микросекундах / 80 // делением можно регулировать скорость игры float time = (clock.getElapsedTime().asMicroseconds() / 80); // в случае нажатия Esc останавливаем/заглушаем звуки и вызываем паузу if (Keyboard::isKeyPressed(Keyboard::Escape)) { music.pause(); Listener::setGlobalVolume(0); menu.pauseMenu(window); Listener::setGlobalVolume(settings.getVolume()); music.play(); } // перезапускаем часы clock.restart(); // цикл для работы с окном (растяжение, закрытие, сворачивание, перетаскивание) while (window.pollEvent(event)) if (event.type == Event::Closed) window.close(); shootTimerFirst += time; shootTimerSecond += time; // увеличиваем время с прошлого спауна spawn.setSpawnTimer(time, t); // вызываем метод управления for (itPlayer = players.begin(); itPlayer != players.end(); itPlayer++) controller.control(**itPlayer, t, shot); // изменяем время с прошлого выстрела у врагов for (it = enemies.begin(); it != enemies.end(); it++) (*it)->setShootTimer(time, t); // проверяем включение/отключение звука движения танка у игроков for (itPlayer = players.begin(); itPlayer != players.end(); itPlayer++) (*itPlayer)->engineSound(engineSoundFirst, engineSoundSecond); // вызов главного метода обновления // в случае уничтожения игрока проверяем имя, заглушаем звук движения, изменяем флаг и записываем кол-во набранных очков // также удаляем игрока со списка for (itPlayer = players.begin(); itPlayer != players.end();) { (*itPlayer)->update(time, repairSound, cooldownUPSound); if ((*itPlayer)->getLife() == false) { if ((*itPlayer)->getName() == "firstplayer") { engineSoundFirst.stop(); (*itPlayer)->setEngineStatus(0); firstIsKilled = true; firstScore = (*itPlayer)->getScore(); } else { engineSoundSecond.stop(); (*itPlayer)->setEngineStatus(0); secondIsKilled = true; secondScore = (*itPlayer)->getScore(); } itPlayer = players.erase(itPlayer); } else itPlayer++; } // вызов главного метода обновления врагов. // в случае уничтожения удаляем его из списка for (it = enemies.begin(); it != enemies.end();) { (*it)->update(time); if ((*it)->getLife() == false) it = enemies.erase(it); else it++; } // вызов главного метода обновления снарядов. // в случае уничтожения удаляем его из списка for (itShell = shells.begin(); itShell != shells.end();) { (*itShell)->update(time, wallHitSound, wallHitSound2); if ((*itShell)->getLife() == false) itShell = shells.erase(itShell); else itShell++; } // проверяем попадание снаряда в игроков/врагов detecthit.detectHit(bonusObj, tankExplosionSound, tankHitSound); // очищаем экран, делаем фон чёрным window.clear(Color::Black); // отрисосываем карту rendermap.renderMap(window, tile); // отрисовываем картинку "ALPHA. WORK IN PROGRESS" window.draw(picture); // отрисовываем спрайты игроков for (itPlayer = players.begin(); itPlayer != players.end(); itPlayer++) window.draw((*itPlayer)->sprite); // отрисовываем спрайты врагов for (it = enemies.begin(); it != enemies.end(); it++) window.draw((*it)->sprite); // отрисовываем спрайты снарядов for (itShell = shells.begin(); itShell != shells.end(); itShell++) window.draw((*itShell)->sprite); // отрисовываем GUI for (itPlayer = players.begin(); itPlayer != players.end(); itPlayer++) gameGUI.drawGUI(window, **itPlayer, font); // если режим на двух игроков и убиты все игроки, то делаем звук потише и вызываем метод конца игры. // возвращаем результат if (menu.getChooseAmountPlayer() == 1) if ((firstIsKilled == true) && (secondIsKilled == true)) { Listener::setGlobalVolume(settings.getVolume() / 2); result = menu.gameOver(firstScore, secondScore, window, font); return result; } // если режим на одного игрока и он был убил, то делаем звук потише и вызываем метод конца игры. // возвращаем результат if (menu.getChooseAmountPlayer() == 0) if (firstIsKilled == true) { Listener::setGlobalVolume(settings.getVolume() / 2); result = menu.gameOver(firstScore, window, font); return result; } // в случае смерти первого игрока в режиме на двух игроков вызываем метод отрисовки GUI if (firstIsKilled == true) gameGUI.firstisKilled(window, firstScore); // в случае смерти второго игрока в режиме на двух игроков вызываем метод отрисовки GUI if (secondIsKilled == true) gameGUI.secondisKilled(window, secondScore); // проверяем бонус bonusObj.bonusIsReady(); // показываем всё накопившееся на экран window.display(); } } void gameRunning() { // рекурсивный рестарт игры // в случае возвращение 1 мы должны очистить все списки и восстановить игровую карту // запускаем игру заново if (startGame()) { for (itPlayer = players.begin(); itPlayer != players.end();) itPlayer = players.erase(itPlayer); for (it = enemies.begin(); it != enemies.end();) it = enemies.erase(it); for (itShell = shells.begin(); itShell != shells.end();) itShell = shells.erase(itShell); for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) TileMap[i][j] = standart[i][j]; gameRunning(); } } int main() { srand(time(NULL)); // для правильной работы рандома gameRunning(); // вызываем метод запуска игры return 0; }