/
del00n
/
Space_Lab
Обзор
Документация
Войти
/
del00n
/
Space_Lab
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
Menu.cpp
482 строки
17 KB
del00n
upload files
22 янв 2026, 13:52
Верифицирован
22 янв 2026, 13:52
4016b42
Код
Авторство
О чём код?
#include "Menu.h" #include <iostream> #include <cmath> static constexpr float SCENE_W = 800.f; static constexpr float SCENE_H = 600.f; static sf::Color planetColorByIndex(std::size_t idx) { static const sf::Color c[] = { sf::Color(140, 120, 255), sf::Color(120, 200, 255), sf::Color(255, 140, 180), sf::Color(200, 180, 120), sf::Color(180, 255, 160) }; return c[idx % (sizeof(c) / sizeof(c[0]))]; } static bool hitPlanet(const PlanetConfig& p, sf::Vector2f mouse) { sf::Vector2f center(p.x, p.y); sf::Vector2f d = mouse - center; return (d.x * d.x + d.y * d.y) <= (p.radius * p.radius); } Menu::Menu() : levelManager(), editingMode(false) { if (!font.loadFromFile("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf")) { std::cerr << "Failed to load font" << std::endl; } setupMainMenu(); setupLevelSelect(); levelManager.loadLevel(0); editingConfig = levelManager.getCurrentLevel(); editingConfig.waypointCount = std::clamp(editingConfig.waypointCount, 2, 10); currentState = MenuState::MAIN_MENU; } void Menu::setupMainMenu() { mainMenuButtons.clear(); mainMenuButtons.emplace_back(sf::Vector2f(300, 150), sf::Vector2f(200, 50), "Start Game"); mainMenuButtons.emplace_back(sf::Vector2f(300, 220), sf::Vector2f(200, 50), "Edit Levels"); mainMenuButtons.emplace_back(sf::Vector2f(300, 290), sf::Vector2f(200, 50), "Exit"); } void Menu::setupLevelSelect() { levelSelectButtons.clear(); for (int i = 0; i < LevelManager::TOTAL_LEVELS; i++) { float x = 50 + (i % 5) * 150; float y = 100 + (i / 5) * 70; levelSelectButtons.emplace_back(sf::Vector2f(x, y), sf::Vector2f(130, 50), "Level " + std::to_string(i + 1)); } levelSelectButtons.emplace_back(sf::Vector2f(50, 500), sf::Vector2f(100, 40), "Back"); } void Menu::saveCurrentLevel() { levelManager.saveLevel(selectedLevel, editingConfig); } MenuState Menu::handleEvents(sf::RenderWindow& window) { sf::Event event; auto currentMousePos = [&]() -> sf::Vector2f { return window.mapPixelToCoords(sf::Mouse::getPosition(window)); }; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) { return MenuState::EXITING; } if (event.type == sf::Event::KeyPressed) { if (currentState == MenuState::LEVEL_EDITOR) { if (event.key.code == sf::Keyboard::Escape) { draggingPlanet = false; selectedPlanet = -1; currentState = MenuState::MAIN_MENU; editingMode = false; } if (event.key.code == sf::Keyboard::Enter) { saveCurrentLevel(); draggingPlanet = false; selectedPlanet = -1; currentState = MenuState::MAIN_MENU; editingMode = false; } if (event.key.code == sf::Keyboard::LBracket) { editingConfig.waypointCount = std::max(2, editingConfig.waypointCount - 1); } if (event.key.code == sf::Keyboard::RBracket) { editingConfig.waypointCount = std::min(10, editingConfig.waypointCount + 1); } if (event.key.code == sf::Keyboard::PageUp) { editingConfig.planetMass = std::min(100000.f, editingConfig.planetMass + 250.f); } if (event.key.code == sf::Keyboard::PageDown) { editingConfig.planetMass = std::max(0.f, editingConfig.planetMass - 250.f); } if (event.key.code == sf::Keyboard::B) { sf::Vector2f mouse = currentMousePos(); PlanetConfig p; p.x = mouse.x; p.y = mouse.y; p.mass = editingConfig.planetMass; p.radius = 30.f; p.x = std::clamp(p.x, p.radius, SCENE_W - p.radius); p.y = std::clamp(p.y, p.radius, SCENE_H - p.radius); editingConfig.planets.push_back(p); selectedPlanet = static_cast<int>(editingConfig.planets.size()) - 1; draggingPlanet = false; } if (event.key.code == sf::Keyboard::Delete) { if (selectedPlanet >= 0 && selectedPlanet < static_cast<int>(editingConfig.planets.size())) { editingConfig.planets.erase(editingConfig.planets.begin() + selectedPlanet); selectedPlanet = -1; draggingPlanet = false; } } } else if (currentState == MenuState::LEVEL_CONFIG) { if (event.key.code == sf::Keyboard::Enter) { currentState = MenuState::PLAYING; } if (event.key.code == sf::Keyboard::Escape) { currentState = MenuState::LEVEL_SELECT; } if (event.key.code == sf::Keyboard::Left) { editingConfig.waypointCount = std::max(2, editingConfig.waypointCount - 1); } if (event.key.code == sf::Keyboard::Right) { editingConfig.waypointCount = std::min(10, editingConfig.waypointCount + 1); } if (event.key.code == sf::Keyboard::Down) { editingConfig.planetMass = std::max(1000.f, editingConfig.planetMass - 100.f); } if (event.key.code == sf::Keyboard::Up) { editingConfig.planetMass = std::min(10000.f, editingConfig.planetMass + 100.f); } } } if (event.type == sf::Event::MouseWheelScrolled) { if (currentState == MenuState::LEVEL_EDITOR && selectedPlanet >= 0 && selectedPlanet < static_cast<int>(editingConfig.planets.size())) { float& m = editingConfig.planets[selectedPlanet].mass; float step = 50.f; if (event.mouseWheelScroll.delta < 0) step = -step; m = std::max(0.f, m + step); } } if (event.type == sf::Event::MouseMoved) { if (currentState == MenuState::LEVEL_EDITOR && draggingPlanet && selectedPlanet >= 0 && selectedPlanet < static_cast<int>(editingConfig.planets.size())) { sf::Vector2f mouse = window.mapPixelToCoords(sf::Vector2i(event.mouseMove.x, event.mouseMove.y)); PlanetConfig& p = editingConfig.planets[selectedPlanet]; sf::Vector2f newPos = mouse + dragOffset; newPos.x = std::clamp(newPos.x, p.radius, SCENE_W - p.radius); newPos.y = std::clamp(newPos.y, p.radius, SCENE_H - p.radius); p.x = newPos.x; p.y = newPos.y; } } if (event.type == sf::Event::MouseButtonPressed) { if (event.mouseButton.button == sf::Mouse::Left) { sf::Vector2f mouse = window.mapPixelToCoords(sf::Vector2i(event.mouseButton.x, event.mouseButton.y)); switch (currentState) { case MenuState::MAIN_MENU: { for (size_t i = 0; i < mainMenuButtons.size(); i++) { if (mainMenuButtons[i].isClicked(mouse)) { if (i == 0) { currentState = MenuState::LEVEL_SELECT; editingMode = false; } else if (i == 1) { currentState = MenuState::LEVEL_SELECT; editingMode = true; } else if (i == 2) { return MenuState::EXITING; } } } break; } case MenuState::LEVEL_SELECT: { for (int i = 0; i < LevelManager::TOTAL_LEVELS; i++) { if (levelSelectButtons[i].isClicked(mouse)) { selectedLevel = i; levelManager.setCurrentLevel(i); editingConfig = levelManager.getCurrentLevel(); editingConfig.waypointCount = std::clamp(editingConfig.waypointCount, 2, 10); if (editingMode) { currentState = MenuState::LEVEL_EDITOR; selectedPlanet = -1; draggingPlanet = false; } else { currentState = MenuState::LEVEL_CONFIG; } } } if (levelSelectButtons.back().isClicked(mouse)) { currentState = MenuState::MAIN_MENU; editingMode = false; } break; } case MenuState::LEVEL_CONFIG: { break; } case MenuState::LEVEL_EDITOR: { int hit = -1; for (int i = static_cast<int>(editingConfig.planets.size()) - 1; i >= 0; --i) { if (hitPlanet(editingConfig.planets[i], mouse)) { hit = i; break; } } if (hit >= 0) { selectedPlanet = hit; PlanetConfig& p = editingConfig.planets[hit]; sf::Vector2f center(p.x, p.y); dragOffset = center - mouse; draggingPlanet = true; } else { selectedPlanet = -1; draggingPlanet = false; } break; } default: break; } } } if (event.type == sf::Event::MouseButtonReleased) { if (currentState == MenuState::LEVEL_EDITOR && event.mouseButton.button == sf::Mouse::Left) { draggingPlanet = false; } } } sf::Vector2f mousePos = currentMousePos(); for (auto& btn : mainMenuButtons) btn.update(mousePos); for (auto& btn : levelSelectButtons) btn.update(mousePos); return currentState; } void Menu::render(sf::RenderWindow& window) { window.clear(sf::Color(15, 15, 30)); switch (currentState) { case MenuState::MAIN_MENU: renderMainMenu(window); break; case MenuState::LEVEL_SELECT: renderLevelSelect(window, editingMode); break; case MenuState::LEVEL_CONFIG: renderLevelConfig(window); break; case MenuState::LEVEL_EDITOR: renderLevelEditor(window); break; default: break; } window.display(); } void Menu::renderMainMenu(sf::RenderWindow& window) { sf::Text title("Space Lab", font, 48); title.setFillColor(sf::Color::Cyan); title.setPosition(280, 30); window.draw(title); sf::Text subtitle("Landing Challenge", font, 24); subtitle.setFillColor(sf::Color::Yellow); subtitle.setPosition(290, 90); window.draw(subtitle); for (auto& btn : mainMenuButtons) { window.draw(btn.shape); sf::Text text(btn.text, font, 18); text.setFillColor(sf::Color::White); sf::FloatRect bounds = text.getLocalBounds(); text.setPosition( btn.shape.getPosition().x + btn.shape.getSize().x / 2.f - bounds.width / 2.f, btn.shape.getPosition().y + btn.shape.getSize().y / 2.f - bounds.height / 2.f - 5.f ); window.draw(text); } } void Menu::renderLevelSelect(sf::RenderWindow& window, bool isEditing) { sf::Text title(isEditing ? "Select Level to Edit" : "Select Level to Play", font, 36); title.setFillColor(sf::Color::Cyan); title.setPosition(50, 20); window.draw(title); for (int i = 0; i < LevelManager::TOTAL_LEVELS; i++) { auto& btn = levelSelectButtons[i]; window.draw(btn.shape); sf::Text text(btn.text, font, 14); text.setFillColor(sf::Color::White); sf::FloatRect bounds = text.getLocalBounds(); text.setPosition( btn.shape.getPosition().x + btn.shape.getSize().x / 2.f - bounds.width / 2.f, btn.shape.getPosition().y + btn.shape.getSize().y / 2.f - bounds.height / 2.f - 3.f ); window.draw(text); } window.draw(levelSelectButtons.back().shape); sf::Text backText(levelSelectButtons.back().text, font, 14); backText.setFillColor(sf::Color::White); sf::FloatRect b = backText.getLocalBounds(); backText.setPosition( levelSelectButtons.back().shape.getPosition().x + 50.f - b.width / 2.f, levelSelectButtons.back().shape.getPosition().y + 20.f - b.height / 2.f ); window.draw(backText); } void Menu::renderLevelConfig(sf::RenderWindow& window) { sf::Text title("Level Configuration", font, 36); title.setFillColor(sf::Color::Cyan); title.setPosition(50, 20); window.draw(title); sf::Text levelName(editingConfig.name, font, 24); levelName.setFillColor(sf::Color::Yellow); levelName.setPosition(50, 100); window.draw(levelName); sf::Text wpText("Waypoint Count: " + std::to_string(editingConfig.waypointCount), font, 20); wpText.setFillColor(sf::Color::White); wpText.setPosition(50, 180); window.draw(wpText); sf::Text wpHint("(LEFT/RIGHT arrows to adjust)", font, 14); wpHint.setFillColor(sf::Color(150, 150, 150)); wpHint.setPosition(50, 210); window.draw(wpHint); sf::Text pmText("Planet Mass: " + std::to_string((int)editingConfig.planetMass), font, 20); pmText.setFillColor(sf::Color::White); pmText.setPosition(50, 280); window.draw(pmText); sf::Text pmHint("(UP/DOWN arrows to adjust)", font, 14); pmHint.setFillColor(sf::Color(150, 150, 150)); pmHint.setPosition(50, 310); window.draw(pmHint); sf::Text hint("ENTER to start | ESC to go back", font, 16); hint.setFillColor(sf::Color::Cyan); hint.setPosition(50, 500); window.draw(hint); } void Menu::renderLevelEditor(sf::RenderWindow& window) { sf::Text title("Edit Level", font, 22); title.setFillColor(sf::Color::Cyan); title.setPosition(15, 10); window.draw(title); sf::RectangleShape boundary(sf::Vector2f(SCENE_W, SCENE_H)); boundary.setPosition(0, 0); boundary.setFillColor(sf::Color::Transparent); boundary.setOutlineThickness(2.f); boundary.setOutlineColor(sf::Color(180, 60, 60)); window.draw(boundary); sf::Vector2f start(50.f, 550.f); sf::Vector2f finish(750.f, 50.f); sf::Vertex line[] = { sf::Vertex(start, sf::Color(120, 120, 120, 120)), sf::Vertex(finish, sf::Color(120, 120, 120, 120)) }; window.draw(line, 2, sf::Lines); sf::CircleShape startDot(7.f); startDot.setOrigin(7.f, 7.f); startDot.setPosition(start); startDot.setFillColor(sf::Color::Yellow); window.draw(startDot); sf::CircleShape finishDot(7.f); finishDot.setOrigin(7.f, 7.f); finishDot.setPosition(finish); finishDot.setFillColor(sf::Color::Green); window.draw(finishDot); for (std::size_t i = 0; i < editingConfig.planets.size(); i++) { const PlanetConfig& pp = editingConfig.planets[i]; sf::CircleShape planet(pp.radius); planet.setOrigin(pp.radius, pp.radius); planet.setPosition(pp.x, pp.y); planet.setFillColor(planetColorByIndex(i)); if (static_cast<int>(i) == selectedPlanet) { planet.setOutlineThickness(3.f); planet.setOutlineColor(sf::Color::White); } else { planet.setOutlineThickness(1.5f); planet.setOutlineColor(sf::Color(0, 0, 0, 120)); } window.draw(planet); sf::Text idx(std::to_string(i + 1), font, 16); idx.setFillColor(sf::Color::Black); sf::FloatRect b = idx.getLocalBounds(); idx.setOrigin(b.width / 2.f, b.height / 2.f); idx.setPosition(pp.x, pp.y - 2.f); window.draw(idx); } sf::Text hint( "B - add planet\n" "DEL - delete selected\n" "Mouse wheel - change selected mass\n" "Drag with LMB\n" "ENTER - save | ESC - exit without saving", font, 13 ); hint.setFillColor(sf::Color(150, 150, 150)); hint.setPosition(10, 40); window.draw(hint); if (selectedPlanet >= 0 && selectedPlanet < static_cast<int>(editingConfig.planets.size())) { const PlanetConfig& p = editingConfig.planets[selectedPlanet]; sf::Text sel( "Selected planet: " + std::to_string(selectedPlanet + 1) + "\nMass = " + std::to_string((int)p.mass) + "\nRadius = " + std::to_string((int)p.radius) + "\nPos = (" + std::to_string((int)p.x) + ", " + std::to_string((int)p.y) + ")", font, 14 ); sel.setFillColor(sf::Color::Cyan); sel.setPosition(520, 540); window.draw(sel); } }