# Extra2D API 教程 - 07. UI 系统 ## 按钮 (Button) Extra2D 提供 Button 组件用于创建交互式按钮。 ### 创建按钮 ```cpp // 创建按钮 auto button = Button::create(); // 设置位置 button->setPosition(Vec2(640.0f, 360.0f)); // 设置锚点(中心) button->setAnchor(0.5f, 0.5f); // 添加到场景 addChild(button); ``` ### 设置按钮文本 ```cpp // 加载字体 auto font = resources.loadFont("assets/font.ttf", 28, true); // 设置按钮字体和文本 button->setFont(font); button->setText("点击我"); button->setTextColor(Colors::Black); ``` ### 设置按钮样式 ```cpp // 设置背景颜色(普通、悬停、按下) button->setBackgroundColor( Colors::White, // 普通状态 Colors::LightGray, // 悬停状态 Colors::Gray // 按下状态 ); // 设置边框 button->setBorder(Colors::Black, 2.0f); // 设置内边距 button->setPadding(Vec2(20.0f, 10.0f)); // 设置固定大小 button->setCustomSize(200.0f, 50.0f); ``` ### 透明按钮 ```cpp // 创建透明按钮(仅文本可点击) auto button = Button::create(); button->setFont(font); button->setText("菜单项"); button->setTextColor(Colors::Black); // 透明背景 button->setBackgroundColor( Colors::Transparent, Colors::Transparent, Colors::Transparent ); // 无边框 button->setBorder(Colors::Transparent, 0.0f); // 无内边距 button->setPadding(Vec2(0.0f, 0.0f)); ``` ## 菜单系统 ### 创建菜单 ```cpp class MenuScene : public Scene { public: void onEnter() override { Scene::onEnter(); auto &resources = Application::instance().resources(); font_ = resources.loadFont("assets/font.ttf", 28, true); float centerX = 640.0f; float startY = 300.0f; // 创建菜单按钮 createMenuButton("开始游戏", centerX, startY, 0); createMenuButton("继续游戏", centerX, startY + 50.0f, 1); createMenuButton("退出", centerX, startY + 100.0f, 2); menuCount_ = 3; selectedIndex_ = 0; updateMenuColors(); } void onUpdate(float dt) override { Scene::onUpdate(dt); auto &input = Application::instance().input(); // 方向键切换选择 if (input.isButtonPressed(SDL_CONTROLLER_BUTTON_DPAD_UP)) { selectedIndex_ = (selectedIndex_ - 1 + menuCount_) % menuCount_; updateMenuColors(); } else if (input.isButtonPressed(SDL_CONTROLLER_BUTTON_DPAD_DOWN)) { selectedIndex_ = (selectedIndex_ + 1) % menuCount_; updateMenuColors(); } // A键确认 if (input.isButtonPressed(SDL_CONTROLLER_BUTTON_A)) { executeMenuItem(); } } private: Ptr font_; std::vector> buttons_; int selectedIndex_ = 0; int menuCount_ = 0; void createMenuButton(const std::string &text, float x, float y, int index) { auto button = Button::create(); button->setFont(font_); button->setText(text); button->setTextColor(Colors::Black); button->setBackgroundColor( Colors::Transparent, Colors::Transparent, Colors::Transparent ); button->setBorder(Colors::Transparent, 0.0f); button->setPadding(Vec2(0.0f, 0.0f)); button->setCustomSize(200.0f, 40.0f); button->setAnchor(0.5f, 0.5f); button->setPosition(x, y); addChild(button); buttons_.push_back(button); } void updateMenuColors() { for (int i = 0; i < buttons_.size(); ++i) { if (buttons_[i]) { buttons_[i]->setTextColor( i == selectedIndex_ ? Colors::Red : Colors::Black ); } } } void executeMenuItem() { switch (selectedIndex_) { case 0: startGame(); break; case 1: continueGame(); break; case 2: exitGame(); break; } } void startGame() { // 切换到游戏场景 } void continueGame() { // 继续游戏 } void exitGame() { Application::instance().quit(); } }; ``` ## 绘制文字 ### 基本文字绘制 ```cpp void onRender(RenderBackend &renderer) override { Scene::onRender(renderer); if (font_) { // 绘制文字 renderer.drawText(*font_, "Hello World", Vec2(100.0f, 100.0f), Colors::White); // 绘制带颜色的文字 renderer.drawText(*font_, "红色文字", Vec2(100.0f, 150.0f), Colors::Red); } } ``` ### 格式化文字 ```cpp void onRender(RenderBackend &renderer) override { Scene::onRender(renderer); if (infoFont_) { auto &app = Application::instance(); // 绘制 FPS std::stringstream ss; ss << "FPS: " << app.fps(); renderer.drawText(*infoFont_, ss.str(), Vec2(50.0f, 50.0f), Colors::Yellow); // 绘制节点数量 ss.str(""); ss << "Nodes: " << nodes_.size(); renderer.drawText(*infoFont_, ss.str(), Vec2(50.0f, 80.0f), Colors::White); } } ``` ## 完整示例 ```cpp class StartScene : public Scene { public: void onEnter() override { Scene::onEnter(); auto &app = Application::instance(); auto &resources = app.resources(); // 加载背景 auto bgTex = resources.loadTexture("assets/background.jpg"); if (bgTex) { auto bg = Sprite::create(bgTex); bg->setAnchor(0.0f, 0.0f); addChild(bg); } // 加载字体 font_ = resources.loadFont("assets/font.ttf", 32, true); float centerX = app.getConfig().width / 2.0f; // 创建标题 titleBtn_ = Button::create(); titleBtn_->setFont(font_); titleBtn_->setText("游戏标题"); titleBtn_->setTextColor(Colors::Gold); titleBtn_->setBackgroundColor( Colors::Transparent, Colors::Transparent, Colors::Transparent ); titleBtn_->setBorder(Colors::Transparent, 0.0f); titleBtn_->setAnchor(0.5f, 0.5f); titleBtn_->setPosition(centerX, 200.0f); addChild(titleBtn_); // 创建菜单按钮 createMenuButton("新游戏", centerX, 350.0f, 0); createMenuButton("继续", centerX, 400.0f, 1); createMenuButton("退出", centerX, 450.0f, 2); menuCount_ = 3; updateMenuColors(); } void onUpdate(float dt) override { Scene::onUpdate(dt); auto &input = Application::instance().input(); if (input.isButtonPressed(SDL_CONTROLLER_BUTTON_DPAD_UP)) { selectedIndex_ = (selectedIndex_ - 1 + menuCount_) % menuCount_; updateMenuColors(); } else if (input.isButtonPressed(SDL_CONTROLLER_BUTTON_DPAD_DOWN)) { selectedIndex_ = (selectedIndex_ + 1) % menuCount_; updateMenuColors(); } if (input.isButtonPressed(SDL_CONTROLLER_BUTTON_A)) { executeMenuItem(); } } private: Ptr font_; Ptr