refactor(audio): 示例程序重构音频系统为单例管理器模式
feat(text): 为Text类添加格式化文本创建和设置功能 refactor(ui): 将碰撞演示和空间索引演示的UI改为Text组件实现 chore: 移除不再使用的音频上下文和菜单按钮相关代码
This commit is contained in:
parent
2751b27d90
commit
1f10ce999c
|
|
@ -4,6 +4,9 @@
|
||||||
#include <extra2d/core/types.h>
|
#include <extra2d/core/types.h>
|
||||||
#include <extra2d/graphics/font.h>
|
#include <extra2d/graphics/font.h>
|
||||||
#include <extra2d/ui/widget.h>
|
#include <extra2d/ui/widget.h>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
|
|
@ -29,6 +32,15 @@ public:
|
||||||
static Ptr<Text> create(const String &text);
|
static Ptr<Text> create(const String &text);
|
||||||
static Ptr<Text> create(const String &text, Ptr<FontAtlas> font);
|
static Ptr<Text> create(const String &text, Ptr<FontAtlas> font);
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// 格式化创建方法(类似 printf)
|
||||||
|
// 使用示例:
|
||||||
|
// auto text = Text::createFormat("FPS: %d", 60);
|
||||||
|
// auto text = Text::createFormat(font, "得分: %d", score);
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
static Ptr<Text> createFormat(const char *fmt, ...);
|
||||||
|
static Ptr<Text> createFormat(Ptr<FontAtlas> font, const char *fmt, ...);
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// 链式调用构建器方法
|
// 链式调用构建器方法
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
@ -48,6 +60,38 @@ public:
|
||||||
void setText(const String &text);
|
void setText(const String &text);
|
||||||
const String &getText() const { return text_; }
|
const String &getText() const { return text_; }
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// 格式化文本设置(类似 printf)
|
||||||
|
// 使用示例:
|
||||||
|
// text->setFormat("FPS: %d", 60);
|
||||||
|
// text->setFormat("位置: (%.1f, %.1f)", x, y);
|
||||||
|
// text->setFormat("生命值: %d/100", hp);
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
void setFormat(const char *fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
char buffer[256];
|
||||||
|
vsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
text_ = buffer;
|
||||||
|
sizeDirty_ = true;
|
||||||
|
updateSpatialIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 链式调用的格式化方法
|
||||||
|
// 注意:由于C++可变参数的限制,链式调用需要单独设置格式和值
|
||||||
|
Text *withFormattedText(const char *fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
char buffer[256];
|
||||||
|
vsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
text_ = buffer;
|
||||||
|
sizeDirty_ = true;
|
||||||
|
updateSpatialIndex();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// 字体
|
// 字体
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
#include <extra2d/ui/text.h>
|
#include <extra2d/ui/text.h>
|
||||||
#include <extra2d/graphics/render_backend.h>
|
#include <extra2d/graphics/render_backend.h>
|
||||||
#include <extra2d/core/string.h>
|
#include <extra2d/core/string.h>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
|
|
@ -203,6 +205,29 @@ Ptr<Text> Text::create(const String &text, Ptr<FontAtlas> font) {
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// 格式化创建方法
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
Ptr<Text> Text::createFormat(const char *fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
char buffer[256];
|
||||||
|
vsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
return makePtr<Text>(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ptr<Text> Text::createFormat(Ptr<FontAtlas> font, const char *fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
char buffer[256];
|
||||||
|
vsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
auto t = makePtr<Text>(buffer);
|
||||||
|
t->setFont(font);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
Rect Text::getBoundingBox() const {
|
Rect Text::getBoundingBox() const {
|
||||||
if (!font_ || text_.empty()) {
|
if (!font_ || text_.empty()) {
|
||||||
return Rect();
|
return Rect();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <extra2d/extra2d.h>
|
#include <extra2d/extra2d.h>
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
|
|
||||||
using namespace extra2d;
|
using namespace extra2d;
|
||||||
|
|
||||||
|
|
@ -73,7 +71,7 @@ public:
|
||||||
centerBox_->setPosition(Vec2(centerX, centerY));
|
centerBox_->setPosition(Vec2(centerX, centerY));
|
||||||
addChild(centerBox_);
|
addChild(centerBox_);
|
||||||
|
|
||||||
// 加载字体
|
// 加载字体并创建UI
|
||||||
loadFonts();
|
loadFonts();
|
||||||
|
|
||||||
E2D_LOG_INFO("创建了 {} 个碰撞框", boxes_.size() + 1);
|
E2D_LOG_INFO("创建了 {} 个碰撞框", boxes_.size() + 1);
|
||||||
|
|
@ -102,6 +100,9 @@ public:
|
||||||
// 执行碰撞检测
|
// 执行碰撞检测
|
||||||
performCollisionDetection();
|
performCollisionDetection();
|
||||||
|
|
||||||
|
// 更新UI文本
|
||||||
|
updateUI();
|
||||||
|
|
||||||
// 检查退出按键
|
// 检查退出按键
|
||||||
auto &input = Application::instance().input();
|
auto &input = Application::instance().input();
|
||||||
if (input.isButtonPressed(GamepadButton::Start)) {
|
if (input.isButtonPressed(GamepadButton::Start)) {
|
||||||
|
|
@ -110,28 +111,60 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void onRender(RenderBackend &renderer) override {
|
|
||||||
Scene::onRender(renderer);
|
|
||||||
|
|
||||||
// 绘制说明文字
|
|
||||||
drawUI(renderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* @brief 加载字体资源
|
* @brief 加载字体资源并创建UI文本
|
||||||
*/
|
*/
|
||||||
void loadFonts() {
|
void loadFonts() {
|
||||||
auto &resources = Application::instance().resources();
|
auto &resources = Application::instance().resources();
|
||||||
titleFont_ = resources.loadFont("assets/font.ttf", 60, true);
|
titleFont_ = resources.loadFont("assets/font.ttf", 60, true);
|
||||||
infoFont_ = resources.loadFont("assets/font.ttf", 28, true);
|
infoFont_ = resources.loadFont("assets/font.ttf", 28, true);
|
||||||
|
|
||||||
if (!titleFont_) {
|
// 创建标题文本
|
||||||
E2D_LOG_WARN("无法加载标题字体");
|
titleText_ = Text::create("碰撞检测演示", titleFont_);
|
||||||
}
|
titleText_->setPosition(50.0f, 30.0f);
|
||||||
if (!infoFont_) {
|
titleText_->setTextColor(Color(1.0f, 1.0f, 1.0f, 1.0f));
|
||||||
E2D_LOG_WARN("无法加载信息字体");
|
addChild(titleText_);
|
||||||
|
|
||||||
|
// 创建说明文本
|
||||||
|
descText_ = Text::create("蓝色方块旋转并检测碰撞", infoFont_);
|
||||||
|
descText_->setPosition(50.0f, 80.0f);
|
||||||
|
descText_->setTextColor(Color(0.8f, 0.8f, 0.8f, 1.0f));
|
||||||
|
addChild(descText_);
|
||||||
|
|
||||||
|
collideHintText_ = Text::create("红色 = 检测到碰撞", infoFont_);
|
||||||
|
collideHintText_->setPosition(50.0f, 105.0f);
|
||||||
|
collideHintText_->setTextColor(Color(1.0f, 0.5f, 0.5f, 1.0f));
|
||||||
|
addChild(collideHintText_);
|
||||||
|
|
||||||
|
// 创建动态统计文本
|
||||||
|
collisionText_ = Text::create("", infoFont_);
|
||||||
|
collisionText_->setPosition(50.0f, 150.0f);
|
||||||
|
collisionText_->setTextColor(Color(1.0f, 1.0f, 0.5f, 1.0f));
|
||||||
|
addChild(collisionText_);
|
||||||
|
|
||||||
|
fpsText_ = Text::create("", infoFont_);
|
||||||
|
fpsText_->setPosition(50.0f, 175.0f);
|
||||||
|
fpsText_->setTextColor(Color(0.8f, 1.0f, 0.8f, 1.0f));
|
||||||
|
addChild(fpsText_);
|
||||||
|
|
||||||
|
// 创建退出提示文本
|
||||||
|
float screenHeight = static_cast<float>(Application::instance().getConfig().height);
|
||||||
|
exitHintText_ = Text::create("按 + 键退出", infoFont_);
|
||||||
|
exitHintText_->setPosition(50.0f, screenHeight - 50.0f);
|
||||||
|
exitHintText_->setTextColor(Color(0.8f, 0.8f, 0.8f, 1.0f));
|
||||||
|
addChild(exitHintText_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 更新UI文本
|
||||||
|
*/
|
||||||
|
void updateUI() {
|
||||||
|
auto &app = Application::instance();
|
||||||
|
|
||||||
|
// 使用 setFormat 更新动态文本
|
||||||
|
collisionText_->setFormat("碰撞数: %zu", collisionCount_);
|
||||||
|
fpsText_->setFormat("FPS: %u", app.fps());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -182,44 +215,6 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 绘制UI界面
|
|
||||||
*/
|
|
||||||
void drawUI(RenderBackend &renderer) {
|
|
||||||
if (!titleFont_ || !infoFont_)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto &app = Application::instance();
|
|
||||||
|
|
||||||
// 绘制标题
|
|
||||||
renderer.drawText(*titleFont_, "碰撞检测演示", Vec2(50.0f, 30.0f),
|
|
||||||
Color(1.0f, 1.0f, 1.0f, 1.0f));
|
|
||||||
|
|
||||||
// 绘制说明文字
|
|
||||||
renderer.drawText(*infoFont_, "蓝色方块旋转并检测碰撞", Vec2(50.0f, 80.0f),
|
|
||||||
Color(0.8f, 0.8f, 0.8f, 1.0f));
|
|
||||||
renderer.drawText(*infoFont_, "红色 = 检测到碰撞", Vec2(50.0f, 105.0f),
|
|
||||||
Color(1.0f, 0.5f, 0.5f, 1.0f));
|
|
||||||
|
|
||||||
// 绘制碰撞统计
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << "碰撞数: " << collisionCount_;
|
|
||||||
renderer.drawText(*infoFont_, ss.str(), Vec2(50.0f, 150.0f),
|
|
||||||
Color(1.0f, 1.0f, 0.5f, 1.0f));
|
|
||||||
|
|
||||||
// 绘制 FPS
|
|
||||||
ss.str("");
|
|
||||||
ss << "FPS: " << app.fps();
|
|
||||||
renderer.drawText(*infoFont_, ss.str(), Vec2(50.0f, 175.0f),
|
|
||||||
Color(0.8f, 1.0f, 0.8f, 1.0f));
|
|
||||||
|
|
||||||
// 绘制操作提示
|
|
||||||
float screenHeight = static_cast<float>(app.getConfig().height);
|
|
||||||
renderer.drawText(*infoFont_, "按 + 键退出",
|
|
||||||
Vec2(50.0f, screenHeight - 50.0f),
|
|
||||||
Color(0.8f, 0.8f, 0.8f, 1.0f));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ptr<CollisionBox> centerBox_;
|
Ptr<CollisionBox> centerBox_;
|
||||||
std::vector<Ptr<CollisionBox>> boxes_;
|
std::vector<Ptr<CollisionBox>> boxes_;
|
||||||
float rotationAngle_ = 0.0f;
|
float rotationAngle_ = 0.0f;
|
||||||
|
|
@ -229,6 +224,14 @@ private:
|
||||||
// 字体资源
|
// 字体资源
|
||||||
Ptr<FontAtlas> titleFont_;
|
Ptr<FontAtlas> titleFont_;
|
||||||
Ptr<FontAtlas> infoFont_;
|
Ptr<FontAtlas> infoFont_;
|
||||||
|
|
||||||
|
// UI 文本组件
|
||||||
|
Ptr<Text> titleText_;
|
||||||
|
Ptr<Text> descText_;
|
||||||
|
Ptr<Text> collideHintText_;
|
||||||
|
Ptr<Text> collisionText_;
|
||||||
|
Ptr<Text> fpsText_;
|
||||||
|
Ptr<Text> exitHintText_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
#include "PlayScene.h"
|
#include "PlayScene.h"
|
||||||
|
|
||||||
#include "audio_context.h"
|
#include "audio_manager.h"
|
||||||
#include "audio_controller.h"
|
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
#include "StartScene.h"
|
#include "StartScene.h"
|
||||||
#include "SuccessScene.h"
|
#include "SuccessScene.h"
|
||||||
|
|
@ -93,11 +92,6 @@ PlayScene::PlayScene(int level) {
|
||||||
mapLayer_->setPosition(0.0f, 0.0f);
|
mapLayer_->setPosition(0.0f, 0.0f);
|
||||||
addChild(mapLayer_);
|
addChild(mapLayer_);
|
||||||
|
|
||||||
auto audioNode = AudioController::create();
|
|
||||||
audioNode->setName("AudioController");
|
|
||||||
addChild(audioNode);
|
|
||||||
setAudioController(audioNode);
|
|
||||||
|
|
||||||
setLevel(level);
|
setLevel(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -136,12 +130,10 @@ void PlayScene::onUpdate(float dt) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// X 键直接切换音效
|
// X键直接切换音效
|
||||||
if (input.isButtonPressed(SDL_CONTROLLER_BUTTON_X)) {
|
if (input.isButtonPressed(SDL_CONTROLLER_BUTTON_X)) {
|
||||||
g_SoundOpen = !g_SoundOpen;
|
g_SoundOpen = !g_SoundOpen;
|
||||||
if (auto audio = getAudioController()) {
|
AudioManager::instance().setEnabled(g_SoundOpen);
|
||||||
audio->setEnabled(g_SoundOpen);
|
|
||||||
}
|
|
||||||
updateSoundIcon();
|
updateSoundIcon();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -189,9 +181,7 @@ void PlayScene::executeMenuItem() {
|
||||||
break;
|
break;
|
||||||
case 1: // 切换音效
|
case 1: // 切换音效
|
||||||
g_SoundOpen = !g_SoundOpen;
|
g_SoundOpen = !g_SoundOpen;
|
||||||
if (auto audio = getAudioController()) {
|
AudioManager::instance().setEnabled(g_SoundOpen);
|
||||||
audio->setEnabled(g_SoundOpen);
|
|
||||||
}
|
|
||||||
updateSoundIcon();
|
updateSoundIcon();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -329,9 +319,7 @@ void PlayScene::move(int dx, int dy, int direct) {
|
||||||
g_Pushing = false;
|
g_Pushing = false;
|
||||||
map_.value[map_.roleY][map_.roleX].type = TYPE::Ground;
|
map_.value[map_.roleY][map_.roleX].type = TYPE::Ground;
|
||||||
map_.value[targetY][targetX].type = TYPE::Man;
|
map_.value[targetY][targetX].type = TYPE::Man;
|
||||||
if (auto audio = getAudioController()) {
|
AudioManager::instance().playManMove();
|
||||||
audio->playManMove();
|
|
||||||
}
|
|
||||||
} else if (map_.value[targetY][targetX].type == TYPE::Box) {
|
} else if (map_.value[targetY][targetX].type == TYPE::Box) {
|
||||||
g_Pushing = true;
|
g_Pushing = true;
|
||||||
|
|
||||||
|
|
@ -370,9 +358,7 @@ void PlayScene::move(int dx, int dy, int direct) {
|
||||||
map_.value[targetY][targetX].type = TYPE::Man;
|
map_.value[targetY][targetX].type = TYPE::Man;
|
||||||
map_.value[map_.roleY][map_.roleX].type = TYPE::Ground;
|
map_.value[map_.roleY][map_.roleX].type = TYPE::Ground;
|
||||||
|
|
||||||
if (auto audio = getAudioController()) {
|
AudioManager::instance().playBoxMove();
|
||||||
audio->playBoxMove();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
#include "StartScene.h"
|
#include "StartScene.h"
|
||||||
|
|
||||||
#include "audio_context.h"
|
#include "audio_manager.h"
|
||||||
#include "audio_controller.h"
|
|
||||||
#include "data.h"
|
#include "data.h"
|
||||||
#include "PlayScene.h"
|
#include "PlayScene.h"
|
||||||
#include <extra2d/extra2d.h>
|
#include <extra2d/extra2d.h>
|
||||||
|
|
@ -28,10 +27,6 @@ void StartScene::onEnter() {
|
||||||
setBackgroundColor(extra2d::Colors::Black);
|
setBackgroundColor(extra2d::Colors::Black);
|
||||||
|
|
||||||
if (getChildren().empty()) {
|
if (getChildren().empty()) {
|
||||||
auto audioNode = AudioController::create();
|
|
||||||
audioNode->setName("audio_controller");
|
|
||||||
addChild(audioNode);
|
|
||||||
setAudioController(audioNode);
|
|
||||||
|
|
||||||
float screenW = static_cast<float>(app.getConfig().width);
|
float screenW = static_cast<float>(app.getConfig().width);
|
||||||
float screenH = static_cast<float>(app.getConfig().height);
|
float screenH = static_cast<float>(app.getConfig().height);
|
||||||
|
|
@ -138,9 +133,7 @@ void StartScene::onUpdate(float dt) {
|
||||||
// X键切换音效
|
// X键切换音效
|
||||||
if (input.isButtonPressed(extra2d::GamepadButton::X)) {
|
if (input.isButtonPressed(extra2d::GamepadButton::X)) {
|
||||||
g_SoundOpen = !g_SoundOpen;
|
g_SoundOpen = !g_SoundOpen;
|
||||||
if (auto audio = getAudioController()) {
|
AudioManager::instance().setEnabled(g_SoundOpen);
|
||||||
audio->setEnabled(g_SoundOpen);
|
|
||||||
}
|
|
||||||
updateSoundIcon();
|
updateSoundIcon();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
#include "audio_context.h"
|
|
||||||
|
|
||||||
#include "audio_controller.h"
|
|
||||||
|
|
||||||
namespace pushbox {
|
|
||||||
|
|
||||||
static extra2d::WeakPtr<AudioController> g_audioController;
|
|
||||||
|
|
||||||
void setAudioController(const extra2d::Ptr<AudioController>& controller) {
|
|
||||||
g_audioController = controller;
|
|
||||||
}
|
|
||||||
|
|
||||||
extra2d::Ptr<AudioController> getAudioController() {
|
|
||||||
return g_audioController.lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace pushbox
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <extra2d/extra2d.h>
|
|
||||||
|
|
||||||
namespace pushbox {
|
|
||||||
|
|
||||||
class AudioController;
|
|
||||||
|
|
||||||
void setAudioController(const extra2d::Ptr<AudioController>& controller);
|
|
||||||
extra2d::Ptr<AudioController> getAudioController();
|
|
||||||
|
|
||||||
} // namespace pushbox
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
#include "audio_controller.h"
|
|
||||||
|
|
||||||
#include "storage.h"
|
|
||||||
|
|
||||||
namespace pushbox {
|
|
||||||
|
|
||||||
extra2d::Ptr<AudioController> AudioController::create() {
|
|
||||||
return extra2d::makePtr<AudioController>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioController::onEnter() {
|
|
||||||
Node::onEnter();
|
|
||||||
|
|
||||||
if (!loaded_) {
|
|
||||||
auto& resources = extra2d::Application::instance().resources();
|
|
||||||
|
|
||||||
background_ = resources.loadSound("pushbox_bg", "assets/audio/background.wav");
|
|
||||||
manMove_ = resources.loadSound("pushbox_manmove", "assets/audio/manmove.wav");
|
|
||||||
boxMove_ = resources.loadSound("pushbox_boxmove", "assets/audio/boxmove.wav");
|
|
||||||
|
|
||||||
if (background_) {
|
|
||||||
background_->setLooping(true);
|
|
||||||
background_->play();
|
|
||||||
}
|
|
||||||
|
|
||||||
loaded_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
setEnabled(g_SoundOpen);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioController::setEnabled(bool enabled) {
|
|
||||||
enabled_ = enabled;
|
|
||||||
g_SoundOpen = enabled;
|
|
||||||
saveSoundOpen(enabled);
|
|
||||||
|
|
||||||
if (!background_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enabled_) {
|
|
||||||
background_->resume();
|
|
||||||
} else {
|
|
||||||
background_->pause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioController::playManMove() {
|
|
||||||
if (!enabled_ || !manMove_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
manMove_->play();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioController::playBoxMove() {
|
|
||||||
if (!enabled_ || !boxMove_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
boxMove_->play();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace pushbox
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "data.h"
|
|
||||||
#include <extra2d/extra2d.h>
|
|
||||||
|
|
||||||
namespace pushbox {
|
|
||||||
|
|
||||||
class AudioController : public extra2d::Node {
|
|
||||||
public:
|
|
||||||
static extra2d::Ptr<AudioController> create();
|
|
||||||
|
|
||||||
void onEnter() override;
|
|
||||||
|
|
||||||
void setEnabled(bool enabled);
|
|
||||||
bool isEnabled() const { return enabled_; }
|
|
||||||
|
|
||||||
void playManMove();
|
|
||||||
void playBoxMove();
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool loaded_ = false;
|
|
||||||
bool enabled_ = true;
|
|
||||||
|
|
||||||
extra2d::Ptr<extra2d::Sound> background_;
|
|
||||||
extra2d::Ptr<extra2d::Sound> manMove_;
|
|
||||||
extra2d::Ptr<extra2d::Sound> boxMove_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace pushbox
|
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
#include "audio_manager.h"
|
||||||
|
|
||||||
|
#include "storage.h"
|
||||||
|
|
||||||
|
namespace pushbox {
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 单例实现
|
||||||
|
// ============================================================================
|
||||||
|
AudioManager& AudioManager::instance() {
|
||||||
|
static AudioManager instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 初始化音频资源
|
||||||
|
// ============================================================================
|
||||||
|
void AudioManager::init() {
|
||||||
|
if (initialized_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& resources = extra2d::Application::instance().resources();
|
||||||
|
|
||||||
|
// 加载音效资源
|
||||||
|
background_ = resources.loadSound("pushbox_bg", "assets/audio/background.wav");
|
||||||
|
manMove_ = resources.loadSound("pushbox_manmove", "assets/audio/manmove.wav");
|
||||||
|
boxMove_ = resources.loadSound("pushbox_boxmove", "assets/audio/boxmove.wav");
|
||||||
|
|
||||||
|
// 设置背景音乐循环播放
|
||||||
|
if (background_) {
|
||||||
|
background_->setLooping(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从存储中读取音效设置
|
||||||
|
enabled_ = g_SoundOpen;
|
||||||
|
|
||||||
|
initialized_ = true;
|
||||||
|
|
||||||
|
// 如果音效开启,播放背景音乐
|
||||||
|
if (enabled_ && background_) {
|
||||||
|
background_->play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 启用/禁用音效
|
||||||
|
// ============================================================================
|
||||||
|
void AudioManager::setEnabled(bool enabled) {
|
||||||
|
enabled_ = enabled;
|
||||||
|
g_SoundOpen = enabled;
|
||||||
|
saveSoundOpen(enabled);
|
||||||
|
|
||||||
|
if (!background_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enabled_) {
|
||||||
|
background_->resume();
|
||||||
|
} else {
|
||||||
|
background_->pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 播放角色移动音效
|
||||||
|
// ============================================================================
|
||||||
|
void AudioManager::playManMove() {
|
||||||
|
if (!enabled_ || !manMove_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
manMove_->play();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 播放箱子移动音效
|
||||||
|
// ============================================================================
|
||||||
|
void AudioManager::playBoxMove() {
|
||||||
|
if (!enabled_ || !boxMove_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
boxMove_->play();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 背景音乐控制
|
||||||
|
// ============================================================================
|
||||||
|
void AudioManager::playBackground() {
|
||||||
|
if (background_) {
|
||||||
|
background_->play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioManager::pauseBackground() {
|
||||||
|
if (background_) {
|
||||||
|
background_->pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioManager::resumeBackground() {
|
||||||
|
if (background_) {
|
||||||
|
background_->resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioManager::stopBackground() {
|
||||||
|
if (background_) {
|
||||||
|
background_->stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pushbox
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "data.h"
|
||||||
|
#include <extra2d/extra2d.h>
|
||||||
|
|
||||||
|
namespace pushbox {
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 全局音频管理器 - 单例模式,不依赖场景生命周期
|
||||||
|
// ============================================================================
|
||||||
|
class AudioManager {
|
||||||
|
public:
|
||||||
|
// 获取单例实例
|
||||||
|
static AudioManager& instance();
|
||||||
|
|
||||||
|
// 初始化音频资源
|
||||||
|
void init();
|
||||||
|
|
||||||
|
// 启用/禁用音效
|
||||||
|
void setEnabled(bool enabled);
|
||||||
|
bool isEnabled() const { return enabled_; }
|
||||||
|
|
||||||
|
// 播放音效
|
||||||
|
void playManMove();
|
||||||
|
void playBoxMove();
|
||||||
|
|
||||||
|
// 背景音乐控制
|
||||||
|
void playBackground();
|
||||||
|
void pauseBackground();
|
||||||
|
void resumeBackground();
|
||||||
|
void stopBackground();
|
||||||
|
|
||||||
|
private:
|
||||||
|
AudioManager() = default;
|
||||||
|
~AudioManager() = default;
|
||||||
|
AudioManager(const AudioManager&) = delete;
|
||||||
|
AudioManager& operator=(const AudioManager&) = delete;
|
||||||
|
|
||||||
|
bool initialized_ = false;
|
||||||
|
bool enabled_ = true;
|
||||||
|
|
||||||
|
extra2d::Ptr<extra2d::Sound> background_;
|
||||||
|
extra2d::Ptr<extra2d::Sound> manMove_;
|
||||||
|
extra2d::Ptr<extra2d::Sound> boxMove_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace pushbox
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
#include "StartScene.h"
|
#include "StartScene.h"
|
||||||
#include "data.h"
|
#include "data.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
|
#include "audio_manager.h"
|
||||||
|
|
||||||
using namespace extra2d;
|
using namespace extra2d;
|
||||||
|
|
||||||
|
|
@ -40,6 +41,9 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
pushbox::g_SoundOpen = pushbox::loadSoundOpen(true);
|
pushbox::g_SoundOpen = pushbox::loadSoundOpen(true);
|
||||||
|
|
||||||
|
// 初始化全局音频管理器
|
||||||
|
pushbox::AudioManager::instance().init();
|
||||||
|
|
||||||
// 进入开始场景(主界面)
|
// 进入开始场景(主界面)
|
||||||
app.enterScene(makePtr<pushbox::StartScene>());
|
app.enterScene(makePtr<pushbox::StartScene>());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
#include "menu_button.h"
|
|
||||||
|
|
||||||
#include <extra2d/extra2d.h>
|
|
||||||
|
|
||||||
namespace pushbox {
|
|
||||||
|
|
||||||
extra2d::Ptr<MenuButton> MenuButton::create(extra2d::Ptr<extra2d::FontAtlas> font,
|
|
||||||
const extra2d::String& text,
|
|
||||||
extra2d::Function<void()> onClick) {
|
|
||||||
auto btn = extra2d::makePtr<MenuButton>();
|
|
||||||
btn->setFont(font);
|
|
||||||
btn->setText(text);
|
|
||||||
btn->setPadding(extra2d::Vec2(0.0f, 0.0f));
|
|
||||||
btn->setBackgroundColor(extra2d::Colors::Transparent, extra2d::Colors::Transparent,
|
|
||||||
extra2d::Colors::Transparent);
|
|
||||||
btn->setBorder(extra2d::Colors::Transparent, 0.0f);
|
|
||||||
btn->setTextColor(extra2d::Colors::Black);
|
|
||||||
|
|
||||||
btn->onClick_ = std::move(onClick);
|
|
||||||
btn->setOnClick([wbtn = extra2d::WeakPtr<MenuButton>(btn)]() {
|
|
||||||
if (auto self = wbtn.lock()) {
|
|
||||||
if (self->enabled_ && self->onClick_) {
|
|
||||||
self->onClick_();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 使用事件监听来处理悬停效果
|
|
||||||
// Note: Extra2D 的 Button 类可能有不同的悬停检测机制
|
|
||||||
// 这里简化处理,仅保留基本功能
|
|
||||||
|
|
||||||
return btn;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MenuButton::setEnabled(bool enabled) {
|
|
||||||
enabled_ = enabled;
|
|
||||||
setTextColor(enabled ? extra2d::Colors::Black : extra2d::Colors::LightGray);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace pushbox
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <extra2d/extra2d.h>
|
|
||||||
|
|
||||||
namespace pushbox {
|
|
||||||
|
|
||||||
class MenuButton : public extra2d::Button {
|
|
||||||
public:
|
|
||||||
static extra2d::Ptr<MenuButton> create(extra2d::Ptr<extra2d::FontAtlas> font,
|
|
||||||
const extra2d::String& text,
|
|
||||||
extra2d::Function<void()> onClick);
|
|
||||||
|
|
||||||
void setEnabled(bool enabled);
|
|
||||||
bool isEnabled() const { return enabled_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool enabled_ = true;
|
|
||||||
extra2d::Function<void()> onClick_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace pushbox
|
|
||||||
|
|
@ -178,30 +178,135 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void onRender(RenderBackend &renderer) override {
|
void onRender(RenderBackend &renderer) override {
|
||||||
Scene::onRender(renderer);
|
|
||||||
|
|
||||||
auto renderStart = std::chrono::high_resolution_clock::now();
|
auto renderStart = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
// 节点渲染由Scene自动处理
|
Scene::onRender(renderer);
|
||||||
|
|
||||||
auto renderEnd = std::chrono::high_resolution_clock::now();
|
auto renderEnd = std::chrono::high_resolution_clock::now();
|
||||||
stats_.renderTime =
|
stats_.renderTime =
|
||||||
std::chrono::duration<double, std::milli>(renderEnd - renderStart)
|
std::chrono::duration<double, std::milli>(renderEnd - renderStart)
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
// 绘制UI
|
// 更新UI文本内容
|
||||||
drawUI(renderer);
|
updateUI();
|
||||||
|
|
||||||
|
// 绘制图例方块(Text组件会自动渲染)
|
||||||
|
drawLegend(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* @brief 加载字体资源
|
* @brief 加载字体资源并创建UI文本组件
|
||||||
*/
|
*/
|
||||||
void loadFonts() {
|
void loadFonts() {
|
||||||
auto &resources = Application::instance().resources();
|
auto &resources = Application::instance().resources();
|
||||||
|
|
||||||
titleFont_ = resources.loadFont("assets/font.ttf", 28, true);
|
titleFont_ = resources.loadFont("assets/font.ttf", 28, true);
|
||||||
infoFont_ = resources.loadFont("assets/font.ttf", 16, true);
|
infoFont_ = resources.loadFont("assets/font.ttf", 16, true);
|
||||||
|
|
||||||
|
// 创建标题文本
|
||||||
|
titleText_ = Text::create("引擎空间索引演示", titleFont_);
|
||||||
|
titleText_->setPosition(30.0f, 20.0f);
|
||||||
|
titleText_->setTextColor(Color(1.0f, 1.0f, 1.0f, 1.0f));
|
||||||
|
addChild(titleText_);
|
||||||
|
|
||||||
|
float x = 30.0f;
|
||||||
|
float y = 60.0f;
|
||||||
|
float lineHeight = 22.0f;
|
||||||
|
|
||||||
|
// 创建统计信息文本
|
||||||
|
nodeCountText_ = Text::create("", infoFont_);
|
||||||
|
nodeCountText_->setPosition(x, y);
|
||||||
|
nodeCountText_->setTextColor(Color(0.9f, 0.9f, 0.9f, 1.0f));
|
||||||
|
addChild(nodeCountText_);
|
||||||
|
y += lineHeight;
|
||||||
|
|
||||||
|
strategyText_ = Text::create("", infoFont_);
|
||||||
|
strategyText_->setPosition(x, y);
|
||||||
|
strategyText_->setTextColor(Color(0.5f, 1.0f, 0.5f, 1.0f));
|
||||||
|
addChild(strategyText_);
|
||||||
|
y += lineHeight;
|
||||||
|
|
||||||
|
collisionText_ = Text::create("", infoFont_);
|
||||||
|
collisionText_->setPosition(x, y);
|
||||||
|
collisionText_->setTextColor(Color(1.0f, 0.5f, 0.5f, 1.0f));
|
||||||
|
addChild(collisionText_);
|
||||||
|
y += lineHeight;
|
||||||
|
|
||||||
|
updateTimeText_ = Text::create("", infoFont_);
|
||||||
|
updateTimeText_->setPosition(x, y);
|
||||||
|
updateTimeText_->setTextColor(Color(0.8f, 0.8f, 0.8f, 1.0f));
|
||||||
|
addChild(updateTimeText_);
|
||||||
|
y += lineHeight;
|
||||||
|
|
||||||
|
collisionTimeText_ = Text::create("", infoFont_);
|
||||||
|
collisionTimeText_->setPosition(x, y);
|
||||||
|
collisionTimeText_->setTextColor(Color(0.8f, 0.8f, 0.8f, 1.0f));
|
||||||
|
addChild(collisionTimeText_);
|
||||||
|
y += lineHeight;
|
||||||
|
|
||||||
|
renderTimeText_ = Text::create("", infoFont_);
|
||||||
|
renderTimeText_->setPosition(x, y);
|
||||||
|
renderTimeText_->setTextColor(Color(0.8f, 0.8f, 0.8f, 1.0f));
|
||||||
|
addChild(renderTimeText_);
|
||||||
|
y += lineHeight;
|
||||||
|
|
||||||
|
fpsText_ = Text::create("", infoFont_);
|
||||||
|
fpsText_->setPosition(x, y);
|
||||||
|
fpsText_->setTextColor(Color(0.5f, 1.0f, 0.5f, 1.0f));
|
||||||
|
addChild(fpsText_);
|
||||||
|
y += lineHeight * 1.5f;
|
||||||
|
|
||||||
|
// 创建操作说明文本
|
||||||
|
helpTitleText_ = Text::create("操作说明:", infoFont_);
|
||||||
|
helpTitleText_->setPosition(x, y);
|
||||||
|
helpTitleText_->setTextColor(Color(1.0f, 1.0f, 0.5f, 1.0f));
|
||||||
|
addChild(helpTitleText_);
|
||||||
|
y += lineHeight;
|
||||||
|
|
||||||
|
helpAddText_ = Text::create("A键 - 添加100个节点", infoFont_);
|
||||||
|
helpAddText_->setPosition(x + 10, y);
|
||||||
|
helpAddText_->setTextColor(Color(0.8f, 0.8f, 0.8f, 1.0f));
|
||||||
|
addChild(helpAddText_);
|
||||||
|
y += lineHeight;
|
||||||
|
|
||||||
|
helpRemoveText_ = Text::create("B键 - 移除100个节点", infoFont_);
|
||||||
|
helpRemoveText_->setPosition(x + 10, y);
|
||||||
|
helpRemoveText_->setTextColor(Color(0.8f, 0.8f, 0.8f, 1.0f));
|
||||||
|
addChild(helpRemoveText_);
|
||||||
|
y += lineHeight;
|
||||||
|
|
||||||
|
helpToggleText_ = Text::create("X键 - 切换索引策略", infoFont_);
|
||||||
|
helpToggleText_->setPosition(x + 10, y);
|
||||||
|
helpToggleText_->setTextColor(Color(0.8f, 0.8f, 0.8f, 1.0f));
|
||||||
|
addChild(helpToggleText_);
|
||||||
|
y += lineHeight;
|
||||||
|
|
||||||
|
helpExitText_ = Text::create("+键 - 退出程序", infoFont_);
|
||||||
|
helpExitText_->setPosition(x + 10, y);
|
||||||
|
helpExitText_->setTextColor(Color(0.8f, 0.8f, 0.8f, 1.0f));
|
||||||
|
addChild(helpExitText_);
|
||||||
|
|
||||||
|
// 创建图例文本
|
||||||
|
float legendX = screenWidth_ - 200.0f;
|
||||||
|
float legendY = 20.0f;
|
||||||
|
|
||||||
|
legendTitleText_ = Text::create("图例:", infoFont_);
|
||||||
|
legendTitleText_->setPosition(legendX, legendY);
|
||||||
|
legendTitleText_->setTextColor(Color(1.0f, 1.0f, 1.0f, 1.0f));
|
||||||
|
addChild(legendTitleText_);
|
||||||
|
legendY += 25.0f;
|
||||||
|
|
||||||
|
legendNormalText_ = Text::create("- 正常", infoFont_);
|
||||||
|
legendNormalText_->setPosition(legendX + 20.0f, legendY);
|
||||||
|
legendNormalText_->setTextColor(Color(0.8f, 0.8f, 0.8f, 1.0f));
|
||||||
|
addChild(legendNormalText_);
|
||||||
|
legendY += 25.0f;
|
||||||
|
|
||||||
|
legendCollidingText_ = Text::create("- 碰撞中", infoFont_);
|
||||||
|
legendCollidingText_->setPosition(legendX + 20.0f, legendY);
|
||||||
|
legendCollidingText_->setTextColor(Color(0.8f, 0.8f, 0.8f, 1.0f));
|
||||||
|
addChild(legendCollidingText_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -302,99 +407,39 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 绘制UI界面
|
* @brief 更新UI文本内容
|
||||||
*/
|
*/
|
||||||
void drawUI(RenderBackend &renderer) {
|
void updateUI() {
|
||||||
if (!titleFont_ || !infoFont_)
|
if (!nodeCountText_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto &app = Application::instance();
|
auto &app = Application::instance();
|
||||||
|
|
||||||
// 绘制标题
|
// 使用 setFormat 格式化文本
|
||||||
renderer.drawText(*titleFont_, "引擎空间索引演示", Vec2(30.0f, 20.0f),
|
nodeCountText_->setFormat("节点数量: %zu", stats_.nodeCount);
|
||||||
Color(1.0f, 1.0f, 1.0f, 1.0f));
|
strategyText_->setFormat("索引策略: %s", stats_.strategyName);
|
||||||
|
collisionText_->setFormat("碰撞对数: %zu", stats_.collisionCount);
|
||||||
|
updateTimeText_->setFormat("更新时间: %.2f ms", stats_.updateTime);
|
||||||
|
collisionTimeText_->setFormat("碰撞检测: %.2f ms", stats_.collisionTime);
|
||||||
|
renderTimeText_->setFormat("渲染时间: %.2f ms", stats_.renderTime);
|
||||||
|
fpsText_->setFormat("FPS: %u", app.fps());
|
||||||
|
}
|
||||||
|
|
||||||
// 绘制性能统计
|
/**
|
||||||
std::stringstream ss;
|
* @brief 绘制图例方块
|
||||||
float x = 30.0f;
|
*/
|
||||||
float y = 60.0f;
|
void drawLegend(RenderBackend &renderer) {
|
||||||
float lineHeight = 22.0f;
|
|
||||||
|
|
||||||
ss << "节点数量: " << stats_.nodeCount;
|
|
||||||
renderer.drawText(*infoFont_, ss.str(), Vec2(x, y),
|
|
||||||
Color(0.9f, 0.9f, 0.9f, 1.0f));
|
|
||||||
y += lineHeight;
|
|
||||||
|
|
||||||
ss.str("");
|
|
||||||
ss << "索引策略: " << stats_.strategyName;
|
|
||||||
renderer.drawText(*infoFont_, ss.str(), Vec2(x, y),
|
|
||||||
Color(0.5f, 1.0f, 0.5f, 1.0f));
|
|
||||||
y += lineHeight;
|
|
||||||
|
|
||||||
ss.str("");
|
|
||||||
ss << "碰撞对数: " << stats_.collisionCount;
|
|
||||||
renderer.drawText(*infoFont_, ss.str(), Vec2(x, y),
|
|
||||||
Color(1.0f, 0.5f, 0.5f, 1.0f));
|
|
||||||
y += lineHeight;
|
|
||||||
|
|
||||||
ss.str("");
|
|
||||||
ss << std::fixed << std::setprecision(2);
|
|
||||||
ss << "更新时间: " << stats_.updateTime << " ms";
|
|
||||||
renderer.drawText(*infoFont_, ss.str(), Vec2(x, y),
|
|
||||||
Color(0.8f, 0.8f, 0.8f, 1.0f));
|
|
||||||
y += lineHeight;
|
|
||||||
|
|
||||||
ss.str("");
|
|
||||||
ss << "碰撞检测: " << stats_.collisionTime << " ms";
|
|
||||||
renderer.drawText(*infoFont_, ss.str(), Vec2(x, y),
|
|
||||||
Color(0.8f, 0.8f, 0.8f, 1.0f));
|
|
||||||
y += lineHeight;
|
|
||||||
|
|
||||||
ss.str("");
|
|
||||||
ss << "渲染时间: " << stats_.renderTime << " ms";
|
|
||||||
renderer.drawText(*infoFont_, ss.str(), Vec2(x, y),
|
|
||||||
Color(0.8f, 0.8f, 0.8f, 1.0f));
|
|
||||||
y += lineHeight;
|
|
||||||
|
|
||||||
ss.str("");
|
|
||||||
ss << "FPS: " << app.fps();
|
|
||||||
renderer.drawText(*infoFont_, ss.str(), Vec2(x, y),
|
|
||||||
Color(0.5f, 1.0f, 0.5f, 1.0f));
|
|
||||||
y += lineHeight * 1.5f;
|
|
||||||
|
|
||||||
// 绘制操作说明
|
|
||||||
renderer.drawText(*infoFont_, "操作说明:", Vec2(x, y),
|
|
||||||
Color(1.0f, 1.0f, 0.5f, 1.0f));
|
|
||||||
y += lineHeight;
|
|
||||||
renderer.drawText(*infoFont_, "A键 - 添加100个节点", Vec2(x + 10, y),
|
|
||||||
Color(0.8f, 0.8f, 0.8f, 1.0f));
|
|
||||||
y += lineHeight;
|
|
||||||
renderer.drawText(*infoFont_, "B键 - 移除100个节点", Vec2(x + 10, y),
|
|
||||||
Color(0.8f, 0.8f, 0.8f, 1.0f));
|
|
||||||
y += lineHeight;
|
|
||||||
renderer.drawText(*infoFont_, "X键 - 切换索引策略", Vec2(x + 10, y),
|
|
||||||
Color(0.8f, 0.8f, 0.8f, 1.0f));
|
|
||||||
y += lineHeight;
|
|
||||||
renderer.drawText(*infoFont_, "+键 - 退出程序", Vec2(x + 10, y),
|
|
||||||
Color(0.8f, 0.8f, 0.8f, 1.0f));
|
|
||||||
|
|
||||||
// 绘制图例
|
|
||||||
float legendX = screenWidth_ - 200.0f;
|
float legendX = screenWidth_ - 200.0f;
|
||||||
float legendY = 20.0f;
|
float legendY = 20.0f + 25.0f; // 在标题下方
|
||||||
renderer.drawText(*infoFont_, "图例:", Vec2(legendX, legendY),
|
|
||||||
Color(1.0f, 1.0f, 1.0f, 1.0f));
|
|
||||||
legendY += 25.0f;
|
|
||||||
|
|
||||||
|
// 绘制正常状态方块
|
||||||
renderer.fillRect(Rect(legendX, legendY, 15.0f, 15.0f),
|
renderer.fillRect(Rect(legendX, legendY, 15.0f, 15.0f),
|
||||||
Color(0.5f, 0.5f, 0.9f, 0.7f));
|
Color(0.5f, 0.5f, 0.9f, 0.7f));
|
||||||
renderer.drawText(*infoFont_, "- 正常", Vec2(legendX + 20.0f, legendY),
|
|
||||||
Color(0.8f, 0.8f, 0.8f, 1.0f));
|
|
||||||
legendY += 25.0f;
|
legendY += 25.0f;
|
||||||
|
|
||||||
|
// 绘制碰撞状态方块
|
||||||
renderer.fillRect(Rect(legendX, legendY, 15.0f, 15.0f),
|
renderer.fillRect(Rect(legendX, legendY, 15.0f, 15.0f),
|
||||||
Color(1.0f, 0.2f, 0.2f, 0.9f));
|
Color(1.0f, 0.2f, 0.2f, 0.9f));
|
||||||
renderer.drawText(*infoFont_, "- 碰撞中", Vec2(legendX + 20.0f, legendY),
|
|
||||||
Color(0.8f, 0.8f, 0.8f, 1.0f));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Ptr<PhysicsNode>> nodes_;
|
std::vector<Ptr<PhysicsNode>> nodes_;
|
||||||
|
|
@ -404,6 +449,24 @@ private:
|
||||||
|
|
||||||
Ptr<FontAtlas> titleFont_;
|
Ptr<FontAtlas> titleFont_;
|
||||||
Ptr<FontAtlas> infoFont_;
|
Ptr<FontAtlas> infoFont_;
|
||||||
|
|
||||||
|
// UI 文本组件
|
||||||
|
Ptr<Text> titleText_;
|
||||||
|
Ptr<Text> nodeCountText_;
|
||||||
|
Ptr<Text> strategyText_;
|
||||||
|
Ptr<Text> collisionText_;
|
||||||
|
Ptr<Text> updateTimeText_;
|
||||||
|
Ptr<Text> collisionTimeText_;
|
||||||
|
Ptr<Text> renderTimeText_;
|
||||||
|
Ptr<Text> fpsText_;
|
||||||
|
Ptr<Text> helpTitleText_;
|
||||||
|
Ptr<Text> helpAddText_;
|
||||||
|
Ptr<Text> helpRemoveText_;
|
||||||
|
Ptr<Text> helpToggleText_;
|
||||||
|
Ptr<Text> helpExitText_;
|
||||||
|
Ptr<Text> legendTitleText_;
|
||||||
|
Ptr<Text> legendNormalText_;
|
||||||
|
Ptr<Text> legendCollidingText_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue