// ============================================================================ // StartScene.cpp - Push Box 开始场景实现 // ============================================================================ #include "StartScene.h" #include "PlayScene.h" #include "audio_manager.h" #include "data.h" #include namespace pushbox { StartScene::StartScene() : BaseScene() { // BaseScene 已处理视口设置 } /** * @brief 加载菜单字体 */ static extra2d::Ptr loadMenuFont() { auto &resources = extra2d::Application::instance().resources(); auto font = resources.loadFont("assets/font.ttf", 28, true); return font; } void StartScene::onEnter() { BaseScene::onEnter(); auto &app = extra2d::Application::instance(); auto &resources = app.resources(); if (children().empty()) { // 使用游戏逻辑分辨率 float screenW = GAME_WIDTH; float screenH = GAME_HEIGHT; auto bgTex = resources.loadTexture("assets/images/start.jpg"); if (bgTex) { auto background = extra2d::Sprite::create(bgTex); float bgWidth = static_cast(bgTex->width()); float bgHeight = static_cast(bgTex->height()); float offsetX = (screenW - bgWidth) / 2.0f; float offsetY = (screenH - bgHeight) / 2.0f; background->setAnchor(0.0f, 0.0f); background->setPosition(offsetX, offsetY); addChild(background); float centerX = screenW / 2.0f; font_ = loadMenuFont(); if (!font_) { return; } // 创建菜单按钮(使用 Button 实现文本居中) startBtn_ = extra2d::Button::create(); startBtn_->setFont(font_); startBtn_->setText("新游戏"); startBtn_->setTextColor(extra2d::Colors::Black); startBtn_->setBackgroundColor(extra2d::Colors::Transparent, extra2d::Colors::Transparent, extra2d::Colors::Transparent); startBtn_->setBorder(extra2d::Colors::Transparent, 0.0f); startBtn_->setPadding(extra2d::Vec2(0.0f, 0.0f)); startBtn_->setCustomSize(200.0f, 40.0f); startBtn_->setAnchor(0.5f, 0.5f); startBtn_->setPosition(centerX, offsetY + 260.0f); addChild(startBtn_); resumeBtn_ = extra2d::Button::create(); resumeBtn_->setFont(font_); resumeBtn_->setText("继续关卡"); resumeBtn_->setTextColor(extra2d::Colors::Black); resumeBtn_->setBackgroundColor(extra2d::Colors::Transparent, extra2d::Colors::Transparent, extra2d::Colors::Transparent); resumeBtn_->setBorder(extra2d::Colors::Transparent, 0.0f); resumeBtn_->setPadding(extra2d::Vec2(0.0f, 0.0f)); resumeBtn_->setCustomSize(200.0f, 40.0f); resumeBtn_->setAnchor(0.5f, 0.5f); resumeBtn_->setPosition(centerX, offsetY + 300.0f); addChild(resumeBtn_); exitBtn_ = extra2d::Button::create(); exitBtn_->setFont(font_); exitBtn_->setText("退出"); exitBtn_->setTextColor(extra2d::Colors::Black); exitBtn_->setBackgroundColor(extra2d::Colors::Transparent, extra2d::Colors::Transparent, extra2d::Colors::Transparent); exitBtn_->setBorder(extra2d::Colors::Transparent, 0.0f); exitBtn_->setPadding(extra2d::Vec2(0.0f, 0.0f)); exitBtn_->setCustomSize(200.0f, 40.0f); exitBtn_->setAnchor(0.5f, 0.5f); exitBtn_->setPosition(centerX, offsetY + 340.0f); addChild(exitBtn_); // 音效开关按钮(使用 Button 的切换模式) auto soundOn = resources.loadTexture("assets/images/soundon.png"); auto soundOff = resources.loadTexture("assets/images/soundoff.png"); if (soundOn && soundOff) { soundBtn_ = extra2d::Button::create(); soundBtn_->setToggleMode(true); soundBtn_->setStateBackgroundImage(soundOff, soundOn); soundBtn_->setOn(g_SoundOpen); soundBtn_->setAnchor(0.0f, 0.0f); soundBtn_->setPosition(offsetX + 50.0f, offsetY + 50.0f); soundBtn_->setOnStateChange([](bool isOn) { g_SoundOpen = isOn; AudioManager::instance().setEnabled(isOn); }); addChild(soundBtn_); } } } // 始终有3个菜单项 menuCount_ = 3; updateMenuColors(); } void StartScene::onUpdate(float dt) { BaseScene::onUpdate(dt); auto &app = extra2d::Application::instance(); auto &input = app.input(); // 方向键上下切换选择 if (input.isButtonPressed(extra2d::GamepadButton::DPadUp)) { selectedIndex_ = (selectedIndex_ - 1 + menuCount_) % menuCount_; updateMenuColors(); } else if (input.isButtonPressed(extra2d::GamepadButton::DPadDown)) { selectedIndex_ = (selectedIndex_ + 1) % menuCount_; updateMenuColors(); } // A键确认 if (input.isButtonPressed(extra2d::GamepadButton::A)) { executeMenuItem(); } // X键切换音效(备用,按钮也可点击切换) if (input.isButtonPressed(extra2d::GamepadButton::X)) { g_SoundOpen = !g_SoundOpen; AudioManager::instance().setEnabled(g_SoundOpen); if (soundBtn_) { soundBtn_->setOn(g_SoundOpen); } } } /** * @brief 更新菜单颜色 */ void StartScene::updateMenuColors() { // 根据选中状态更新按钮文本颜色 // 选中的项用红色,未选中的用黑色,禁用的项用深灰色 if (startBtn_) { startBtn_->setTextColor(selectedIndex_ == 0 ? extra2d::Colors::Red : extra2d::Colors::Black); } if (resumeBtn_) { // "继续关卡"始终显示,但当 g_CurrentLevel == 1 时禁用(深灰色) if (g_CurrentLevel > 1) { // 可用状态:选中为红色,未选中为黑色 resumeBtn_->setTextColor(selectedIndex_ == 1 ? extra2d::Colors::Red : extra2d::Colors::Black); } else { // 禁用状态:深灰色 (RGB: 80, 80, 80) resumeBtn_->setTextColor(extra2d::Color(80, 80, 80, 255)); } } if (exitBtn_) { exitBtn_->setTextColor(selectedIndex_ == 2 ? extra2d::Colors::Red : extra2d::Colors::Black); } } /** * @brief 执行选中的菜单项 */ void StartScene::executeMenuItem() { // 始终有3个选项,但"继续关卡"(索引1)在 g_CurrentLevel == 1 时禁用 switch (selectedIndex_) { case 0: startNewGame(); break; case 1: // 只有当 g_CurrentLevel > 1 时才能选择"继续关卡" if (g_CurrentLevel > 1) { continueGame(); } break; case 2: exitGame(); break; } } /** * @brief 开始新游戏 */ void StartScene::startNewGame() { extra2d::Application::instance().scenes().replaceScene( extra2d::makePtr(1), extra2d::TransitionType::Fade, 0.5f); } /** * @brief 继续游戏 */ void StartScene::continueGame() { extra2d::Application::instance().scenes().replaceScene( extra2d::makePtr(g_CurrentLevel), extra2d::TransitionType::Fade, 0.5f); } /** * @brief 退出游戏 */ void StartScene::exitGame() { extra2d::Application::instance().quit(); } } // namespace pushbox