diff --git a/Extra2D/examples/collision_demo/main.cpp b/Extra2D/examples/collision_demo/main.cpp deleted file mode 100644 index 7d4bac0..0000000 --- a/Extra2D/examples/collision_demo/main.cpp +++ /dev/null @@ -1,292 +0,0 @@ -#include -#include -#include - -using namespace extra2d; - -// ============================================================================ -// 碰撞测试节点 - 有实际边界框 -// ============================================================================ -class CollisionBox : public Node { -public: - CollisionBox(float width, float height, const Color &color) - : width_(width), height_(height), color_(color), isColliding_(false) { - // 启用空间索引,这是碰撞检测的关键 - setSpatialIndexed(true); - } - - void setColliding(bool colliding) { isColliding_ = colliding; } - - Rect getBoundingBox() const override { - // 返回实际的矩形边界 - Vec2 pos = getPosition(); - return Rect(pos.x - width_ / 2, pos.y - height_ / 2, width_, height_); - } - - void onRender(RenderBackend &renderer) override { - Vec2 pos = getPosition(); - - // 绘制填充矩形 - Color fillColor = isColliding_ ? Color(1.0f, 0.2f, 0.2f, 0.8f) : color_; - renderer.fillRect( - Rect(pos.x - width_ / 2, pos.y - height_ / 2, width_, height_), - fillColor); - - // 绘制边框 - Color borderColor = isColliding_ ? Color(1.0f, 0.0f, 0.0f, 1.0f) - : Color(1.0f, 1.0f, 1.0f, 0.5f); - float borderWidth = isColliding_ ? 3.0f : 2.0f; - renderer.drawRect( - Rect(pos.x - width_ / 2, pos.y - height_ / 2, width_, height_), - borderColor, borderWidth); - } - -private: - float width_, height_; - Color color_; - bool isColliding_; -}; - -// ============================================================================ -// 碰撞检测场景 -// ============================================================================ -class CollisionDemoScene : public Scene { -public: - void onEnter() override { - E2D_LOG_INFO("CollisionDemoScene::onEnter - 碰撞检测演示"); - - // 设置背景色 - setBackgroundColor(Color(0.05f, 0.05f, 0.1f, 1.0f)); - - // 获取屏幕中心 - auto &app = Application::instance(); - float centerX = app.getConfig().width / 2.0f; - float centerY = app.getConfig().height / 2.0f; - - // 创建静态碰撞框 - createStaticBoxes(centerX, centerY); - - // 创建移动的中心方块 - centerBox_ = - makePtr(80.0f, 80.0f, Color(0.2f, 0.6f, 1.0f, 0.8f)); - centerBox_->setPosition(Vec2(centerX, centerY)); - addChild(centerBox_); - - // 加载字体 - loadFonts(); - - E2D_LOG_INFO("创建了 {} 个碰撞框", boxes_.size() + 1); - } - - void onUpdate(float dt) override { - Scene::onUpdate(dt); - - // 旋转中心方块 - rotationAngle_ += rotationSpeed_ * dt; - if (rotationAngle_ >= 360.0f) - rotationAngle_ -= 360.0f; - - // 让中心方块沿圆形路径移动 - float radius = 150.0f; - float rad = rotationAngle_ * 3.14159f / 180.0f; - - auto &app = Application::instance(); - Vec2 center = - Vec2(app.getConfig().width / 2.0f, app.getConfig().height / 2.0f); - - centerBox_->setPosition(Vec2(center.x + std::cos(rad) * radius, - center.y + std::sin(rad) * radius)); - centerBox_->setRotation(rotationAngle_); - - // 执行碰撞检测 - performCollisionDetection(); - - // 检查退出按键 - auto &input = Application::instance().input(); - if (input.isButtonPressed(SDL_CONTROLLER_BUTTON_START)) { - E2D_LOG_INFO("退出应用"); - Application::instance().quit(); - } - } - - void onRender(RenderBackend &renderer) override { - Scene::onRender(renderer); - - // 绘制说明文字 - drawUI(renderer); - } - -private: - /** - * @brief 加载字体资源 - */ - void loadFonts() { - auto &resources = Application::instance().resources(); - - // 使用后备字体加载功能 -#ifdef PLATFORM_SWITCH - std::vector fontPaths = { - "romfs:/assets/font.ttf" // 备选字体 - }; -#else - std::vector fontPaths = {FileSystem::resolvePath("font.ttf")}; -#endif - - titleFont_ = resources.loadFontWithFallbacks(fontPaths, 60, true); - infoFont_ = resources.loadFontWithFallbacks(fontPaths, 28, true); - - if (!titleFont_) { - E2D_LOG_WARN("无法加载标题字体"); - } - if (!infoFont_) { - E2D_LOG_WARN("无法加载信息字体"); - } - } - - /** - * @brief 创建静态碰撞框 - */ - void createStaticBoxes(float centerX, float centerY) { - // 创建围绕中心的静态碰撞框 - std::vector> positions = { - {Vec2(centerX - 200, centerY - 150), Color(0.3f, 1.0f, 0.3f, 0.7f)}, - {Vec2(centerX + 200, centerY - 150), Color(1.0f, 0.3f, 0.3f, 0.7f)}, - {Vec2(centerX - 200, centerY + 150), Color(0.3f, 0.3f, 1.0f, 0.7f)}, - {Vec2(centerX + 200, centerY + 150), Color(1.0f, 1.0f, 0.3f, 0.7f)}, - {Vec2(centerX, centerY - 220), Color(1.0f, 0.3f, 1.0f, 0.7f)}, - {Vec2(centerX, centerY + 220), Color(0.3f, 1.0f, 1.0f, 0.7f)}, - }; - - for (const auto &[pos, color] : positions) { - auto box = makePtr(70.0f, 70.0f, color); - box->setPosition(pos); - addChild(box); - boxes_.push_back(box); - } - } - - /** - * @brief 执行碰撞检测 - */ - void performCollisionDetection() { - // 清除之前的碰撞状态 - centerBox_->setColliding(false); - for (auto &box : boxes_) { - box->setColliding(false); - } - - // 使用空间索引进行碰撞检测 - auto collisions = queryCollisions(); - - collisionCount_ = collisions.size(); - - // 标记碰撞的节点 - for (const auto &[nodeA, nodeB] : collisions) { - if (auto boxA = dynamic_cast(nodeA)) { - boxA->setColliding(true); - } - if (auto boxB = dynamic_cast(nodeB)) { - boxB->setColliding(true); - } - } - } - - /** - * @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(app.getConfig().height); - renderer.drawText(*infoFont_, "按 + 键退出", - Vec2(50.0f, screenHeight - 50.0f), - Color(0.8f, 0.8f, 0.8f, 1.0f)); - } - - Ptr centerBox_; - std::vector> boxes_; - float rotationAngle_ = 0.0f; - float rotationSpeed_ = 60.0f; // 旋转速度(度/秒) - size_t collisionCount_ = 0; - - // 字体资源 - Ptr titleFont_; - Ptr infoFont_; -}; - -// ============================================================================ -// 程序入口 -// ============================================================================ - -#ifdef _WIN32 -int main(int argc, char *argv[]) -#else -extern "C" int main(int argc, char *argv[]) -#endif -{ - (void)argc; - (void)argv; - - // 初始化日志系统 - Logger::init(); - Logger::setLevel(LogLevel::Debug); - - E2D_LOG_INFO("========================"); - E2D_LOG_INFO("Easy2D 碰撞检测演示"); - E2D_LOG_INFO("========================"); - - // 获取应用实例 - auto &app = Application::instance(); - - // 配置应用 - AppConfig config; - config.title = "Easy2D - 碰撞检测演示"; - config.width = 1280; - config.height = 720; - config.vsync = true; - config.fpsLimit = 60; - - // 初始化应用 - if (!app.init(config)) { - E2D_LOG_ERROR("应用初始化失败!"); - return -1; - } - - // 进入场景 - app.enterScene(makePtr()); - - E2D_LOG_INFO("开始主循环..."); - - // 运行应用 - app.run(); - - E2D_LOG_INFO("应用结束"); - - return 0; -} diff --git a/Extra2D/examples/collision_demo/romfs/assets/font.ttf b/Extra2D/examples/collision_demo/romfs/assets/font.ttf deleted file mode 100644 index 8997148..0000000 Binary files a/Extra2D/examples/collision_demo/romfs/assets/font.ttf and /dev/null differ diff --git a/Extra2D/examples/hello_world/main.cpp b/Extra2D/examples/hello_world/main.cpp deleted file mode 100644 index be25d7e..0000000 --- a/Extra2D/examples/hello_world/main.cpp +++ /dev/null @@ -1,207 +0,0 @@ -#include -#include - -#ifdef PLATFORM_SWITCH -#include -#endif - -using namespace extra2d; - -// ============================================================================ -// 字体配置 -// ============================================================================ - -/** - * @brief 获取字体候选列表 - * @return 按优先级排序的字体路径列表 - */ -static std::vector getFontCandidates() { - return { - FileSystem::resolvePath("font.ttf"), // 微软雅黑(中文支持) - FileSystem::resolvePath("Gasinamu.ttf"), // 备选字体 - FileSystem::resolvePath("default.ttf"), // 默认字体 - }; -} - -/** - * @brief 加载字体,支持多种字体后备 - * @param resources 资源管理器引用 - * @param fontSize 字体大小 - * @param useSDF 是否使用SDF渲染 - * @return 成功加载的字体图集,失败返回nullptr - */ -static Ptr loadFontWithFallbacks(ResourceManager &resources, - int fontSize, bool useSDF) { - auto candidates = getFontCandidates(); - - for (const auto &fontPath : candidates) { - auto font = resources.loadFont(fontPath, fontSize, useSDF); - if (font) { - E2D_LOG_INFO("成功加载字体: {}", fontPath); - return font; - } - E2D_LOG_WARN("字体加载失败,尝试下一个: {}", fontPath); - } - - E2D_LOG_ERROR("所有字体候选都加载失败!"); - return nullptr; -} - -// ============================================================================ -// Hello World 场景 -// ============================================================================ - -/** - * @brief Hello World 场景类 - * 显示简单的 "Hello World" 文字 - */ -class HelloWorldScene : public Scene { -public: - /** - * @brief 场景进入时调用 - */ - void onEnter() override { - E2D_LOG_INFO("HelloWorldScene::onEnter - 进入场景"); - - // 设置背景颜色为深蓝色 - setBackgroundColor(Color(0.1f, 0.1f, 0.3f, 1.0f)); - - // 加载字体(支持多种字体后备) - auto &resources = Application::instance().resources(); - font_ = loadFontWithFallbacks(resources, 48, true); - - if (!font_) { - E2D_LOG_ERROR("字体加载失败,文字渲染将不可用!"); - } - } - - /** - * @brief 每帧更新时调用 - * @param dt 时间间隔(秒) - */ - void onUpdate(float dt) override { - Scene::onUpdate(dt); - - // 检查退出按键 - auto &input = Application::instance().input(); - -#ifdef PLATFORM_SWITCH - // Switch: 使用手柄 START 按钮 - if (input.isButtonPressed(SDL_CONTROLLER_BUTTON_START)) { - E2D_LOG_INFO("退出应用 (START 按钮)"); - Application::instance().quit(); - } -#else - // PC: 支持 ESC 键或手柄 START 按钮 - if (input.isKeyPressed(Key::Escape) || - input.isButtonPressed(SDL_CONTROLLER_BUTTON_START)) { - E2D_LOG_INFO("退出应用 (ESC 键或 START 按钮)"); - Application::instance().quit(); - } -#endif - } - - /** - * @brief 渲染时调用 - * @param renderer 渲染后端 - */ - void onRender(RenderBackend &renderer) override { - Scene::onRender(renderer); - - if (!font_) - return; - - // 屏幕中心位置 - float centerX = 640.0f; // 1280 / 2 - float centerY = 360.0f; // 720 / 2 - - // 绘制 "你好世界" 文字(白色,居中) - Color white(1.0f, 1.0f, 1.0f, 1.0f); - renderer.drawText(*font_, "你好世界", Vec2(centerX - 100.0f, centerY), - white); - - // 绘制提示文字(黄色) - Color yellow(1.0f, 1.0f, 0.0f, 1.0f); -#ifdef PLATFORM_SWITCH - renderer.drawText(*font_, "退出按键(START 按钮)", - Vec2(centerX - 80.0f, centerY + 50.0f), yellow); -#else - renderer.drawText(*font_, "退出按键(ESC 或 START 按钮)", - Vec2(centerX - 80.0f, centerY + 50.0f), yellow); -#endif - } - -private: - Ptr font_; // 字体图集 -}; - -// ============================================================================ -// 程序入口 -// ============================================================================ - -/** - * @brief 初始化应用配置 - * @return 应用配置结构体 - */ -static AppConfig createAppConfig() { - AppConfig config; - config.title = "Easy2D - Hello World"; - config.width = 1280; - config.height = 720; - config.vsync = true; - config.fpsLimit = 60; - -#ifdef PLATFORM_PC - // PC 端默认窗口模式 - config.fullscreen = false; - config.resizable = true; -#endif - - return config; -} - -/** - * @brief 程序入口 - */ -#ifdef _WIN32 -int main(int argc, char *argv[]) -#else -extern "C" int main(int argc, char *argv[]) -#endif -{ - (void)argc; - (void)argv; - - // 初始化日志系统 - Logger::init(); - Logger::setLevel(LogLevel::Debug); - - E2D_LOG_INFO("========================"); - E2D_LOG_INFO("Easy2D Hello World Demo"); - E2D_LOG_INFO("Platform: {}", platform::getPlatformName()); - E2D_LOG_INFO("========================"); - - // 获取应用实例 - auto &app = Application::instance(); - - // 配置应用 - auto config = createAppConfig(); - - // 初始化应用 - if (!app.init(config)) { - E2D_LOG_ERROR("应用初始化失败!"); - return -1; - } - - // 进入 Hello World 场景 - app.enterScene(makePtr()); - - E2D_LOG_INFO("开始主循环..."); - - // 运行应用 - app.run(); - - E2D_LOG_INFO("应用结束"); - - return 0; -} diff --git a/Extra2D/examples/hello_world/romfs/assets/font.ttf b/Extra2D/examples/hello_world/romfs/assets/font.ttf deleted file mode 100644 index 8997148..0000000 Binary files a/Extra2D/examples/hello_world/romfs/assets/font.ttf and /dev/null differ diff --git a/Extra2D/examples/spatial_index_demo/main.cpp b/Extra2D/examples/spatial_index_demo/main.cpp deleted file mode 100644 index b0fe530..0000000 --- a/Extra2D/examples/spatial_index_demo/main.cpp +++ /dev/null @@ -1,451 +0,0 @@ -#include -#include -#include -#include -#include - -using namespace extra2d; - -// ============================================================================ -// 性能统计 -// ============================================================================ -struct PerformanceStats { - double updateTime = 0.0; - double collisionTime = 0.0; - double renderTime = 0.0; - size_t collisionCount = 0; - size_t nodeCount = 0; - const char *strategyName = "Unknown"; -}; - -// ============================================================================ -// 碰撞节点 - 使用引擎自带的空间索引功能 -// ============================================================================ -class PhysicsNode : public Node { -public: - PhysicsNode(float size, const Color &color, int id) - : size_(size), color_(color), id_(id), isColliding_(false) { - // 启用引擎自带的空间索引功能 - // 这是关键:设置 spatialIndexed_ = true 让节点参与空间索引 - setSpatialIndexed(true); - - // 随机速度 - std::random_device rd; - std::mt19937 gen(rd() + id); - std::uniform_real_distribution velDist(-150.0f, 150.0f); - velocity_ = Vec2(velDist(gen), velDist(gen)); - } - - void setColliding(bool colliding) { isColliding_ = colliding; } - bool isColliding() const { return isColliding_; } - int getId() const { return id_; } - - // 必须实现 getBoundingBox() 才能参与空间索引碰撞检测 - Rect getBoundingBox() const override { - Vec2 pos = getPosition(); - return Rect(pos.x - size_ / 2, pos.y - size_ / 2, size_, size_); - } - - void update(float dt, float screenWidth, float screenHeight) { - Vec2 pos = getPosition(); - pos = pos + velocity_ * dt; - - // 边界反弹 - if (pos.x < size_ / 2 || pos.x > screenWidth - size_ / 2) { - velocity_.x = -velocity_.x; - pos.x = std::clamp(pos.x, size_ / 2, screenWidth - size_ / 2); - } - if (pos.y < size_ / 2 || pos.y > screenHeight - size_ / 2) { - velocity_.y = -velocity_.y; - pos.y = std::clamp(pos.y, size_ / 2, screenHeight - size_ / 2); - } - - setPosition(pos); - } - - void onRender(RenderBackend &renderer) override { - Vec2 pos = getPosition(); - - // 碰撞时变红色 - Color fillColor = isColliding_ ? Color(1.0f, 0.2f, 0.2f, 0.9f) : color_; - renderer.fillRect(Rect(pos.x - size_ / 2, pos.y - size_ / 2, size_, size_), - fillColor); - - // 绘制边框 - Color borderColor = isColliding_ ? Color(1.0f, 0.0f, 0.0f, 1.0f) - : Color(0.3f, 0.3f, 0.3f, 0.5f); - renderer.drawRect(Rect(pos.x - size_ / 2, pos.y - size_ / 2, size_, size_), - borderColor, 1.0f); - } - -private: - float size_; - Color color_; - int id_; - bool isColliding_; - Vec2 velocity_; -}; - -// ============================================================================ -// 空间索引演示场景 -// ============================================================================ -class SpatialIndexDemoScene : public Scene { -public: - void onEnter() override { - E2D_LOG_INFO("SpatialIndexDemoScene::onEnter - 引擎空间索引演示"); - - auto &app = Application::instance(); - screenWidth_ = static_cast(app.getConfig().width); - screenHeight_ = static_cast(app.getConfig().height); - - // 设置背景色 - setBackgroundColor(Color(0.05f, 0.05f, 0.1f, 1.0f)); - - // 创建1000个碰撞节点 - createNodes(1000); - - // 加载字体 - loadFonts(); - - E2D_LOG_INFO("创建了 {} 个碰撞节点", nodes_.size()); - E2D_LOG_INFO("空间索引已启用: {}", isSpatialIndexingEnabled()); - } - - void onUpdate(float dt) override { - Scene::onUpdate(dt); - - auto startTime = std::chrono::high_resolution_clock::now(); - - // 更新所有节点位置 - for (auto &node : nodes_) { - node->update(dt, screenWidth_, screenHeight_); - } - - auto updateEndTime = std::chrono::high_resolution_clock::now(); - stats_.updateTime = - std::chrono::duration(updateEndTime - startTime) - .count(); - - // 使用引擎自带的空间索引进行碰撞检测 - performCollisionDetection(); - - auto collisionEndTime = std::chrono::high_resolution_clock::now(); - stats_.collisionTime = std::chrono::duration( - collisionEndTime - updateEndTime) - .count(); - - stats_.nodeCount = nodes_.size(); - - // 获取当前使用的空间索引策略 - stats_.strategyName = getSpatialManager().getStrategyName(); - - // 检查退出按键 - auto &input = Application::instance().input(); - if (input.isButtonPressed(SDL_CONTROLLER_BUTTON_START)) { - E2D_LOG_INFO("退出应用"); - Application::instance().quit(); - } - - // 按A键添加节点 - if (input.isButtonPressed(SDL_CONTROLLER_BUTTON_A)) { - addNodes(100); - } - - // 按B键减少节点 - if (input.isButtonPressed(SDL_CONTROLLER_BUTTON_B)) { - removeNodes(100); - } - - // 按X键切换空间索引策略 - if (input.isButtonPressed(SDL_CONTROLLER_BUTTON_X)) { - toggleSpatialStrategy(); - } - } - - void onRender(RenderBackend &renderer) override { - Scene::onRender(renderer); - - auto renderStart = std::chrono::high_resolution_clock::now(); - - // 节点渲染由Scene自动处理 - - auto renderEnd = std::chrono::high_resolution_clock::now(); - stats_.renderTime = - std::chrono::duration(renderEnd - renderStart) - .count(); - - // 绘制UI - drawUI(renderer); - } - -private: - /** - * @brief 加载字体资源 - */ - void loadFonts() { - auto &resources = Application::instance().resources(); - -#ifdef PLATFORM_SWITCH - std::vector fontPaths = { - "romfs:/assets/msjh.ttf", - "romfs:/assets/default.ttf", - "romfs:/assets/font.ttf", - }; -#else - std::vector fontPaths = { - FileSystem::resolvePath("msjh.ttf"), - FileSystem::resolvePath("default.ttf"), - FileSystem::resolvePath("font.ttf"), - }; -#endif - - titleFont_ = resources.loadFontWithFallbacks(fontPaths, 28, true); - infoFont_ = resources.loadFontWithFallbacks(fontPaths, 16, true); - } - - /** - * @brief 创建指定数量的节点 - */ - void createNodes(size_t count) { - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_real_distribution posX(50.0f, screenWidth_ - 50.0f); - std::uniform_real_distribution posY(50.0f, screenHeight_ - 50.0f); - std::uniform_real_distribution colorR(0.2f, 0.9f); - std::uniform_real_distribution colorG(0.2f, 0.9f); - std::uniform_real_distribution colorB(0.2f, 0.9f); - - for (size_t i = 0; i < count; ++i) { - Color color(colorR(gen), colorG(gen), colorB(gen), 0.7f); - auto node = makePtr(20.0f, color, static_cast(i)); - node->setPosition(Vec2(posX(gen), posY(gen))); - addChild(node); - nodes_.push_back(node); - } - } - - /** - * @brief 添加节点 - */ - void addNodes(size_t count) { - size_t currentCount = nodes_.size(); - if (currentCount + count > 5000) { - E2D_LOG_WARN("节点数量已达上限(5000)"); - return; - } - createNodes(count); - E2D_LOG_INFO("添加 {} 个节点,当前总数: {}", count, nodes_.size()); - } - - /** - * @brief 移除节点 - */ - void removeNodes(size_t count) { - if (count >= nodes_.size()) { - count = nodes_.size(); - } - if (count == 0) - return; - - for (size_t i = 0; i < count; ++i) { - removeChild(nodes_.back()); - nodes_.pop_back(); - } - E2D_LOG_INFO("移除 {} 个节点,当前总数: {}", count, nodes_.size()); - } - - /** - * @brief 切换空间索引策略 - */ - void toggleSpatialStrategy() { - auto &spatialManager = getSpatialManager(); - SpatialStrategy currentStrategy = spatialManager.getCurrentStrategy(); - - if (currentStrategy == SpatialStrategy::QuadTree) { - spatialManager.setStrategy(SpatialStrategy::SpatialHash); - E2D_LOG_INFO("切换到空间哈希策略"); - } else { - spatialManager.setStrategy(SpatialStrategy::QuadTree); - E2D_LOG_INFO("切换到四叉树策略"); - } - } - - /** - * @brief 使用引擎自带的空间索引进行碰撞检测 - * - * 关键方法: - * - Scene::queryCollisions() - 查询场景中所有碰撞的节点对 - * - SpatialManager::queryCollisions() - 空间管理器的碰撞检测 - */ - void performCollisionDetection() { - // 清除之前的碰撞状态 - for (auto &node : nodes_) { - node->setColliding(false); - } - - // 使用引擎自带的空间索引进行碰撞检测 - // 这是核心:Scene::queryCollisions() 会自动使用 SpatialManager - auto collisions = queryCollisions(); - - stats_.collisionCount = collisions.size(); - - // 标记碰撞的节点 - for (const auto &[nodeA, nodeB] : collisions) { - if (auto boxA = dynamic_cast(nodeA)) { - boxA->setColliding(true); - } - if (auto boxB = dynamic_cast(nodeB)) { - boxB->setColliding(true); - } - } - } - - /** - * @brief 绘制UI界面 - */ - void drawUI(RenderBackend &renderer) { - if (!titleFont_ || !infoFont_) - return; - - auto &app = Application::instance(); - - // 绘制标题 - renderer.drawText(*titleFont_, "引擎空间索引演示", Vec2(30.0f, 20.0f), - Color(1.0f, 1.0f, 1.0f, 1.0f)); - - // 绘制性能统计 - std::stringstream ss; - float x = 30.0f; - float y = 60.0f; - 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 legendY = 20.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), - 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; - - renderer.fillRect(Rect(legendX, legendY, 15.0f, 15.0f), - 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> nodes_; - PerformanceStats stats_; - float screenWidth_ = 1280.0f; - float screenHeight_ = 720.0f; - - Ptr titleFont_; - Ptr infoFont_; -}; - -// ============================================================================ -// 程序入口 -// ============================================================================ - -#ifdef _WIN32 -int main(int argc, char *argv[]) -#else -extern "C" int main(int argc, char *argv[]) -#endif -{ - (void)argc; - (void)argv; - - Logger::init(); - Logger::setLevel(LogLevel::Debug); - - E2D_LOG_INFO("========================"); - E2D_LOG_INFO("Easy2D 引擎空间索引演示"); - E2D_LOG_INFO("========================"); - - auto &app = Application::instance(); - - AppConfig config; - config.title = "Easy2D - 引擎空间索引演示"; - config.width = 1280; - config.height = 720; - config.vsync = true; - config.fpsLimit = 60; - - if (!app.init(config)) { - E2D_LOG_ERROR("应用初始化失败!"); - return -1; - } - - app.enterScene(makePtr()); - - E2D_LOG_INFO("开始主循环..."); - - app.run(); - - E2D_LOG_INFO("应用结束"); - - return 0; -} diff --git a/Extra2D/examples/spatial_index_demo/romfs/assets/font.ttf b/Extra2D/examples/spatial_index_demo/romfs/assets/font.ttf deleted file mode 100644 index 8997148..0000000 Binary files a/Extra2D/examples/spatial_index_demo/romfs/assets/font.ttf and /dev/null differ diff --git a/docs/API_REFERENCE.md b/docs/API_REFERENCE.md deleted file mode 100644 index 410f1b6..0000000 --- a/docs/API_REFERENCE.md +++ /dev/null @@ -1,959 +0,0 @@ -# Extra2D API 参考文档 - -## 目录 - -- [核心系统](#核心系统) -- [应用管理](#应用管理) -- [场景系统](#场景系统) -- [节点系统](#节点系统) -- [输入系统](#输入系统) -- [资源管理](#资源管理) -- [动画系统](#动画系统) -- [音频系统](#音频系统) -- [文件系统](#文件系统) - ---- - -## 核心系统 - -### 类型定义 - -```cpp -namespace extra2d { - -// 基本类型 -using Vec2 = glm::vec2; -using Vec3 = glm::vec3; -using Vec4 = glm::vec4; -using Mat3 = glm::mat3; -using Mat4 = glm::mat4; - -// 智能指针 -template -using Ptr = std::shared_ptr; - -template -Ptr makePtr(Args&&... args) { - return std::make_shared(std::forward(args)...); -} - -} // namespace extra2d -``` - -### 颜色类 - -```cpp -struct Color { - float r, g, b, a; - - Color(float r = 1.0f, float g = 1.0f, float b = 1.0f, float a = 1.0f); - - // 预定义颜色 - static Color White; - static Color Black; - static Color Red; - static Color Green; - static Color Blue; - static Color Yellow; - static Color Transparent; -}; -``` - -### 矩形类 - -```cpp -struct Rect { - float x, y, width, height; - - Rect(float x = 0, float y = 0, float w = 0, float h = 0); - - bool contains(const Vec2& point) const; - bool intersects(const Rect& other) const; - - float left() const { return x; } - float right() const { return x + width; } - float top() const { return y; } - float bottom() const { return y + height; } - Vec2 center() const { return Vec2(x + width/2, y + height/2); } -}; -``` - ---- - -## 应用管理 - -### AppConfig - -应用配置结构体。 - -```cpp -struct AppConfig { - String title = "Extra2D Application"; - int width = 800; - int height = 600; - bool fullscreen = false; - bool resizable = true; - bool vsync = true; - int fpsLimit = 0; // 0 = 不限制 - BackendType renderBackend = BackendType::OpenGL; - int msaaSamples = 0; -}; -``` - -### Application - -应用主类,单例模式。 - -```cpp -class Application { -public: - // 获取单例实例 - static Application& instance(); - - // 初始化应用 - bool init(const AppConfig& config); - - // 运行主循环 - void run(); - - // 退出应用 - void quit(); - - // 进入场景 - void enterScene(Ptr scene); - void enterScene(Ptr scene, Ptr transition); - - // 获取子系统 - Input& input(); - AudioEngine& audio(); - ResourceManager& resources(); - RenderBackend& renderer(); - - // 获取配置 - const AppConfig& getConfig() const; - - // 获取当前 FPS - float fps() const; - - // Switch 特定:检测是否连接底座 - bool isDocked() const; -}; -``` - -**使用示例:** - -```cpp -#include - -using namespace extra2d; - -int main() { - // 初始化日志 - Logger::init(); - Logger::setLevel(LogLevel::Debug); - - // 配置应用 - AppConfig config; - config.title = "My Game"; - config.width = 1280; - config.height = 720; - config.vsync = true; - - // 初始化应用 - auto& app = Application::instance(); - if (!app.init(config)) { - E2D_LOG_ERROR("应用初始化失败!"); - return -1; - } - - // 进入场景 - app.enterScene(makePtr()); - - // 运行主循环 - app.run(); - - return 0; -} -``` - ---- - -## 场景系统 - -### Scene - -场景类,作为游戏内容的容器。 - -```cpp -class Scene : public Node { -public: - // 构造函数 - Scene(); - - // 场景生命周期回调 - virtual void onEnter(); // 进入场景时调用 - virtual void onExit(); // 退出场景时调用 - virtual void onUpdate(float dt); // 每帧更新 - virtual void onRender(RenderBackend& renderer); // 渲染 - - // 设置背景颜色 - void setBackgroundColor(const Color& color); - - // 空间索引 - void setSpatialIndexingEnabled(bool enabled); - bool isSpatialIndexingEnabled() const; - - // 查询碰撞 - std::vector> queryCollisions(); - - // 获取空间管理器 - SpatialManager& getSpatialManager(); -}; -``` - -### Transition - -场景过渡动画基类。 - -```cpp -class Transition { -public: - explicit Transition(float duration); - - virtual void update(float dt) = 0; - virtual void render(RenderBackend& renderer, - Ptr fromScene, - Ptr toScene) = 0; - - bool isFinished() const; -}; - -// 内置过渡效果 -class FadeTransition : public Transition { -public: - FadeTransition(float duration, const Color& color = Color::Black); -}; - -class SlideTransition : public Transition { -public: - SlideTransition(float duration, Direction direction); -}; -``` - ---- - -## 节点系统 - -### Node - -所有场景对象的基类。 - -```cpp -class Node { -public: - Node(); - virtual ~Node(); - - // 变换 - void setPosition(const Vec2& pos); - Vec2 getPosition() const; - - void setRotation(float degrees); - float getRotation() const; - - void setScale(const Vec2& scale); - Vec2 getScale() const; - - void setAnchor(const Vec2& anchor); - Vec2 getAnchor() const; - - // 层级 - void addChild(Ptr child); - void removeChild(Ptr child); - void removeFromParent(); - - // 可见性 - void setVisible(bool visible); - bool isVisible() const; - - // 动作 - void runAction(Ptr action); - void stopAllActions(); - - // 渲染 - virtual void onRender(RenderBackend& renderer); - - // 更新 - virtual void onUpdate(float dt); - - // 边界框(用于碰撞检测) - virtual Rect getBoundingBox() const; - - // 空间索引 - void setSpatialIndexed(bool indexed); - bool isSpatialIndexed() const; -}; -``` - -### Sprite - -精灵节点,用于显示2D图像。 - -```cpp -class Sprite : public Node { -public: - // 创建方法 - static Ptr create(Ptr texture); - static Ptr create(const std::string& texturePath); - - // 设置纹理 - void setTexture(Ptr texture); - Ptr getTexture() const; - - // 设置纹理矩形(用于精灵表) - void setTextureRect(const Rect& rect); - - // 设置颜色调制 - void setColor(const Color& color); - Color getColor() const; - - // 翻转 - void setFlippedX(bool flipped); - void setFlippedY(bool flipped); -}; -``` - -### Text - -文本节点。 - -```cpp -class Text : public Node { -public: - static Ptr create(const std::string& text = ""); - - // 文本内容 - void setText(const std::string& text); - std::string getText() const; - - // 字体 - void setFont(Ptr font); - void setFontSize(int size); - - // 颜色 - void setTextColor(const Color& color); - Color getTextColor() const; - - // 对齐 - void setHorizontalAlignment(Alignment align); - void setVerticalAlignment(Alignment align); -}; -``` - ---- - -## 输入系统 - -### Input - -输入管理类。 - -```cpp -class Input { -public: - // 键盘 - bool isKeyDown(int keyCode) const; // 按键是否按下 - bool isKeyPressed(int keyCode) const; // 按键是否刚按下 - bool isKeyReleased(int keyCode) const; // 按键是否刚释放 - - // 手柄按钮 - bool isButtonDown(int button) const; - bool isButtonPressed(int button) const; - bool isButtonReleased(int button) const; - - // 摇杆 - Vec2 getLeftStick() const; - Vec2 getRightStick() const; - - // 鼠标(PC端) - Vec2 getMousePosition() const; - bool isMouseDown(int button) const; - bool isMousePressed(int button) const; - - // 触摸(Switch/移动端) - bool isTouching() const; - Vec2 getTouchPosition() const; - int getTouchCount() const; -}; -``` - -### 按键码 (Key) - -```cpp -namespace Key { - // 字母 - A, B, C, D, E, F, G, H, I, J, K, L, M, - N, O, P, Q, R, S, T, U, V, W, X, Y, Z, - - // 数字 - Num0, Num1, Num2, Num3, Num4, - Num5, Num6, Num7, Num8, Num9, - - // 功能键 - F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, - - // 方向键 - Up, Down, Left, Right, - - // 特殊键 - Escape, Enter, Tab, Backspace, Space, - Insert, Delete, Home, End, PageUp, PageDown, - LeftShift, LeftControl, LeftAlt, LeftSuper, - RightShift, RightControl, RightAlt, RightSuper -} -``` - -**使用示例:** - -```cpp -void MyScene::onUpdate(float dt) { - auto& input = Application::instance().input(); - - // 键盘输入 - if (input.isKeyPressed(Key::Space)) { - // 空格键按下 - jump(); - } - - if (input.isKeyDown(Key::Left)) { - // 左方向键按住 - moveLeft(); - } - - // 手柄输入 - if (input.isButtonPressed(GamepadButton::A)) { - // A 按钮按下 - jump(); - } - - // 摇杆输入 - Vec2 leftStick = input.getLeftStick(); - move(leftStick.x * speed, leftStick.y * speed); -} -``` - ---- - -## 资源管理 - -### ResourceManager - -资源管理类,负责加载和管理游戏资源。 - -```cpp -class ResourceManager { -public: - // 纹理 - Ptr loadTexture(const std::string& path); - Ptr getTexture(const std::string& path); - void unloadTexture(const std::string& path); - - // 字体 - Ptr loadFont(const std::string& path, int size, bool useSDF = false); - Ptr loadFontWithFallbacks(const std::vector& paths, - int size, bool useSDF = false); - - // 音频 - Ptr loadSound(const std::string& path); - Ptr loadMusic(const std::string& path); - - // 精灵表 - Ptr loadSpriteSheet(const std::string& path); - - // 清理 - void unloadAll(); - void unloadUnused(); -}; -``` - -### Texture - -纹理类。 - -```cpp -class Texture { -public: - // 获取尺寸 - int getWidth() const; - int getHeight() const; - Vec2 getSize() const; - - // 获取 OpenGL 纹理 ID - GLuint getTextureID() const; -}; -``` - -### FontAtlas - -字体图集类。 - -```cpp -class FontAtlas { -public: - // 获取字体信息 - int getFontSize() const; - bool isSDF() const; - - // 获取字符信息 - const Glyph& getGlyph(char32_t charCode) const; - - // 获取行高 - float getLineHeight() const; - - // 获取纹理 - Ptr getTexture() const; -}; -``` - -**使用示例:** - -```cpp -void MyScene::onEnter() { - auto& resources = Application::instance().resources(); - - // 加载纹理 - auto playerTexture = resources.loadTexture("player.png"); - auto enemyTexture = resources.loadTexture("enemies/slime.png"); - - // 加载字体 - auto font = resources.loadFont("font.ttf", 24, true); - - // 创建精灵 - auto player = Sprite::create(playerTexture); - addChild(player); - - // 创建文本 - auto text = Text::create("Hello World"); - text->setFont(font); - addChild(text); -} -``` - ---- - -## 动画系统 - -### Action - -动作基类。 - -```cpp -class Action { -public: - virtual void update(float dt) = 0; - virtual bool isFinished() const = 0; - void reset(); -}; -``` - -### 基础动作 - -```cpp -// 移动 -class MoveTo : public Action { -public: - MoveTo(float duration, const Vec2& position); -}; - -class MoveBy : public Action { -public: - MoveBy(float duration, const Vec2& delta); -}; - -// 缩放 -class ScaleTo : public Action { -public: - ScaleTo(float duration, const Vec2& scale); - ScaleTo(float duration, float scale); -}; - -class ScaleBy : public Action { -public: - ScaleBy(float duration, const Vec2& scale); - ScaleBy(float duration, float scale); -}; - -// 旋转 -class RotateTo : public Action { -public: - RotateTo(float duration, float degrees); -}; - -class RotateBy : public Action { -public: - RotateBy(float duration, float degrees); -}; - -// 淡入淡出 -class FadeTo : public Action { -public: - FadeTo(float duration, float opacity); -}; - -class FadeIn : public Action { -public: - FadeIn(float duration); -}; - -class FadeOut : public Action { -public: - FadeOut(float duration); -}; - -// 延迟 -class Delay : public Action { -public: - Delay(float duration); -}; - -// 回调 -class CallFunc : public Action { -public: - CallFunc(std::function callback); -}; -``` - -### 组合动作 - -```cpp -// 顺序执行 -class Sequence : public Action { -public: - Sequence(std::vector> actions); - - template - static Ptr create(Args&&... args) { - return makePtr(std::vector>{std::forward(args)...}); - } -}; - -// 同时执行 -class Spawn : public Action { -public: - Spawn(std::vector> actions); -}; - -// 重复 -class Repeat : public Action { -public: - Repeat(Ptr action, int times = -1); // -1 = 无限重复 -}; - -// 反向 -class Reverse : public Action { -public: - Reverse(Ptr action); -}; -``` - -### 缓动函数 - -```cpp -namespace Ease { - // 线性 - float linear(float t); - - // 二次 - float inQuad(float t); - float outQuad(float t); - float inOutQuad(float t); - - // 三次 - float inCubic(float t); - float outCubic(float t); - float inOutCubic(float t); - - // 弹性 - float inElastic(float t); - float outElastic(float t); - - // 弹跳 - float inBounce(float t); - float outBounce(float t); - - // 回退 - float inBack(float t); - float outBack(float t); -} -``` - -**使用示例:** - -```cpp -// 创建精灵 -auto sprite = Sprite::create("player.png"); -sprite->setPosition(Vec2(100, 100)); -addChild(sprite); - -// 简单动作 -sprite->runAction(makePtr(1.0f, Vec2(300, 200))); - -// 组合动作 -sprite->runAction(makePtr( - makePtr(0.5f, Vec2(1.5f, 1.5f)), - makePtr(0.2f), - makePtr(0.5f, Vec2(1.0f, 1.0f)), - makePtr([]() { - E2D_LOG_INFO("动画完成!"); - }) -)); - -// 重复动画 -sprite->runAction(makePtr( - makePtr( - makePtr(1.0f, 360.0f), - makePtr(0.5f) - ) -)); -``` - ---- - -## 音频系统 - -### AudioEngine - -音频引擎类。 - -```cpp -class AudioEngine { -public: - // 音量控制 (0.0 - 1.0) - void setMasterVolume(float volume); - float getMasterVolume() const; - - void setBGMVolume(float volume); - void setSFXVolume(float volume); - - // 播放控制 - void pauseAll(); - void resumeAll(); - void stopAll(); -}; -``` - -### Sound - -音效类(短音频,适合音效)。 - -```cpp -class Sound { -public: - void play(int loops = 0); // loops: 0=播放1次, -1=无限循环 - void stop(); - void pause(); - void resume(); - - void setVolume(float volume); - bool isPlaying() const; -}; -``` - -### Music - -音乐类(长音频,适合背景音乐)。 - -```cpp -class Music { -public: - void play(int loops = -1); - void stop(); - void pause(); - void resume(); - - void setVolume(float volume); - bool isPlaying() const; - - void setLoopPoints(double start, double end); -}; -``` - -**使用示例:** - -```cpp -void MyScene::onEnter() { - auto& audio = Application::instance().audio(); - auto& resources = Application::instance().resources(); - - // 加载并播放背景音乐 - auto bgm = resources.loadMusic("bgm/level1.ogg"); - bgm->play(-1); // 无限循环 - bgm->setVolume(0.7f); - - // 加载音效 - jumpSound_ = resources.loadSound("sfx/jump.wav"); - coinSound_ = resources.loadSound("sfx/coin.wav"); -} - -void MyScene::jump() { - jumpSound_->play(); -} - -void MyScene::collectCoin() { - coinSound_->play(); -} -``` - ---- - -## 文件系统 - -### FileSystem - -跨平台文件系统工具类。 - -```cpp -class FileSystem { -public: - // 路径解析(自动处理平台差异) - // PC: "assets/font.ttf" -> "C:/.../assets/font.ttf" - // Switch: "assets/font.ttf" -> "romfs:/assets/font.ttf" - static std::string resolvePath(const std::string& relativePath); - - // 获取资源根目录 - static std::string getResourceRoot(); - - // 获取可执行文件目录 - static std::string getExecutableDirectory(); - - // 获取当前工作目录 - static std::string getCurrentWorkingDirectory(); - - // 路径组合 - static std::string combinePath(const std::string& path1, - const std::string& path2); - - // 文件/目录检查 - static bool fileExists(const std::string& path); - static bool directoryExists(const std::string& path); - - // 读取文件内容 - static std::vector readFile(const std::string& path); - static std::string readTextFile(const std::string& path); - - // 写入文件 - static bool writeFile(const std::string& path, - const std::vector& data); - static bool writeTextFile(const std::string& path, - const std::string& content); -}; -``` - -**使用示例:** - -```cpp -// 解析资源路径(跨平台) -std::string fontPath = FileSystem::resolvePath("fonts/main.ttf"); -// PC: "C:/.../assets/fonts/main.ttf" -// Switch: "romfs:/assets/fonts/main.ttf" - -// 检查文件是否存在 -if (FileSystem::fileExists(fontPath)) { - auto font = resources.loadFont(fontPath, 24); -} - -// 读取配置文件 -std::string configPath = FileSystem::resolvePath("config/game.json"); -std::string jsonContent = FileSystem::readTextFile(configPath); -``` - ---- - -## 日志系统 - -### Logger - -日志系统。 - -```cpp -enum class LogLevel { - Debug, - Info, - Warning, - Error -}; - -class Logger { -public: - static void init(); - static void shutdown(); - - static void setLevel(LogLevel level); - - // 日志宏 - #define E2D_LOG_DEBUG(...) // 调试日志 - #define E2D_LOG_INFO(...) // 信息日志 - #define E2D_LOG_WARN(...) // 警告日志 - #define E2D_LOG_ERROR(...) // 错误日志 -}; -``` - -**使用示例:** - -```cpp -void MyClass::doSomething() { - E2D_LOG_DEBUG("进入函数 doSomething"); - - if (!loadData()) { - E2D_LOG_ERROR("加载数据失败!"); - return; - } - - E2D_LOG_INFO("成功加载 {} 条记录", recordCount); -} -``` - ---- - -## 平台兼容性 - -### 平台检测 - -```cpp -// 编译时检测 -#ifdef PLATFORM_SWITCH - // Switch 代码 -#elif defined(PLATFORM_PC) - // PC 代码 - #ifdef PLATFORM_WINDOWS - // Windows 代码 - #elif defined(PLATFORM_LINUX) - // Linux 代码 - #elif defined(PLATFORM_MACOS) - // macOS 代码 - #endif -#endif - -// 运行时检测 -namespace platform { - bool isSwitch(); - bool isPC(); - bool isWindows(); - bool isLinux(); - bool isMacOS(); - const char* getPlatformName(); -} -``` - ---- - -## 更多文档 - -- [Switch 构建指南](./SWITCH_BUILD_GUIDE.md) -- [PC 构建指南](./PC_BUILD_GUIDE.md) -- [迁移完成记录](./SWITCH_MIGRATION_COMPLETE.md) - ---- - -**最后更新**: 2026年2月10日 -**Extra2D 版本**: 3.1.0 diff --git a/docs/DataStore.md b/docs/DataStore.md deleted file mode 100644 index b54afa1..0000000 --- a/docs/DataStore.md +++ /dev/null @@ -1,822 +0,0 @@ -# DataStore 数据持久化系统 - -## 概述 - -`DataStore` 是 Easy2D 引擎的数据持久化类,提供 INI 文件格式的数据存储功能,并支持 Nintendo Switch 平台的官方存档系统。 - -## 特性 - -- ✅ INI 文件格式读写 -- ✅ Nintendo Switch 官方存档系统支持 -- ✅ 多用户存档隔离 -- ✅ 事务支持(批量操作 + 回滚) -- ✅ 自动保存和脏数据检测 -- ✅ 跨平台兼容(Switch/PC) - ---- - -## 快速开始 - -### 基本使用 - -```cpp -#include - -using namespace extra2d; - -// 创建 DataStore 实例 -DataStore data; - -// 加载数据文件 -data.load("config.ini"); - -// 读取数据 -int level = data.getInt("Player", "Level", 1); -std::string name = data.getString("Player", "Name", "Unknown"); - -// 写入数据 -data.setInt("Player", "Level", 10); -data.setString("Player", "Name", "Hero"); - -// 保存到文件 -data.save("config.ini"); -``` - -### Switch 存档系统使用 - -```cpp -DataStore saveData; - -// 挂载存档(自动获取当前用户) -if (saveData.mountSaveData(SaveDataType::Account)) { - // 从存档加载 - saveData.loadFromSave("savegame.ini"); - - // 修改数据 - saveData.setInt("Progress", "Level", 5); - saveData.setInt("Progress", "Score", 1000); - - // 保存到存档(自动提交) - saveData.saveToSave("savegame.ini"); - - // 卸载存档 - saveData.unmountSaveData(); -} -``` - ---- - -## API 参考 - -### 枚举类型 - -#### SaveDataType - -存档数据类型枚举: - -| 值 | 说明 | -|---|---| -| `SaveDataType::Account` | 用户存档,与特定用户账户关联 | -| `SaveDataType::Common` | 公共存档,所有用户共享 | -| `SaveDataType::Cache` | 缓存数据,可被系统清理 | -| `SaveDataType::Device` | 设备存档,与设备绑定 | -| `SaveDataType::Temporary` | 临时数据,应用退出后清理 | - -#### UserId - -用户ID结构体: - -```cpp -struct UserId { - uint64_t uid[2]; // 用户唯一标识 - - bool isValid() const; // 检查ID是否有效 -}; -``` - ---- - -### 构造函数 - -```cpp -DataStore(); -~DataStore(); -``` - -**说明:** -- 析构时会自动提交未保存的事务 -- 如果存档已挂载,会自动卸载 - ---- - -### 文件操作 - -#### load - -```cpp -bool load(const std::string &filename); -``` - -加载 INI 文件。 - -**参数:** -- `filename` - 文件路径 - -**返回值:** -- `true` - 加载成功 -- `false` - 加载失败 - -**示例:** -```cpp -if (!data.load("config.ini")) { - E2D_LOG_WARN("配置文件不存在,将创建新文件"); -} -``` - ---- - -#### save - -```cpp -bool save(const std::string &filename = ""); -``` - -保存到 INI 文件。 - -**参数:** -- `filename` - 文件路径,为空则使用上次加载的文件名 - -**返回值:** -- `true` - 保存成功 -- `false` - 保存失败 - -**说明:** -- 如果在事务中,只标记为脏数据,不实际写入 -- 事务外自动保存(当设置数据时) - ---- - -### Switch 存档系统 - -#### mountSaveData - -```cpp -bool mountSaveData( - SaveDataType type = SaveDataType::Account, - const UserId &userId = UserId(), - const std::string &mountName = "save" -); -``` - -挂载 Switch 存档数据。 - -**参数:** -- `type` - 存档类型 -- `userId` - 用户ID(Account 类型需要,为空则自动获取当前用户) -- `mountName` - 挂载点名称 - -**返回值:** -- `true` - 挂载成功 -- `false` - 挂载失败 - -**示例:** -```cpp -// 挂载当前用户的存档 -if (data.mountSaveData(SaveDataType::Account)) { - // 存档已挂载,路径为 "save:/" -} - -// 挂载公共存档 -if (data.mountSaveData(SaveDataType::Common, UserId(), "common")) { - // 公共存档已挂载,路径为 "common:/" -} -``` - ---- - -#### unmountSaveData - -```cpp -void unmountSaveData(const std::string &mountName = "save"); -``` - -卸载存档挂载。 - -**参数:** -- `mountName` - 挂载点名称 - -**说明:** -- 卸载前会自动提交未保存的更改 - ---- - -#### commitSaveData - -```cpp -bool commitSaveData(const std::string &mountName = "save"); -``` - -提交存档更改。 - -**⚠️ 重要:** 修改存档数据后必须调用此方法,否则更改不会持久化! - -**参数:** -- `mountName` - 挂载点名称 - -**返回值:** -- `true` - 提交成功 -- `false` - 提交失败 - -**示例:** -```cpp -data.setInt("Game", "Score", 100); -data.save(); -data.commitSaveData(); // 必须提交! -``` - ---- - -#### isSaveDataMounted - -```cpp -bool isSaveDataMounted() const; -``` - -检查存档是否已挂载。 - -**返回值:** -- `true` - 已挂载 -- `false` - 未挂载 - ---- - -#### getSaveDataPath - -```cpp -std::string getSaveDataPath(const std::string &path = "") const; -``` - -获取挂载点路径。 - -**参数:** -- `path` - 子路径 - -**返回值:** -- 完整路径(如 "save:/data/config.ini") - -**示例:** -```cpp -std::string fullPath = data.getSaveDataPath("config/settings.ini"); -// 返回: "save:/config/settings.ini" -``` - ---- - -### 用户账户管理 - -#### getCurrentUserId - -```cpp -static UserId getCurrentUserId(); -``` - -获取当前预选用户ID。 - -**返回值:** -- 用户ID(无效时返回空ID) - -**示例:** -```cpp -UserId user = DataStore::getCurrentUserId(); -if (user.isValid()) { - E2D_LOG_INFO("当前用户: 0x{:X}{:X}", user.uid[1], user.uid[0]); -} -``` - ---- - -#### setDefaultUserId / getDefaultUserId - -```cpp -void setDefaultUserId(const UserId &userId); -UserId getDefaultUserId() const; -``` - -设置/获取默认用户ID。 - -**说明:** -- 用于多用户场景下的默认用户选择 - ---- - -### 数据读写 - -#### getString - -```cpp -std::string getString( - const std::string §ion, - const std::string &key, - const std::string &defaultValue = "" -); -``` - -获取字符串值。 - -**参数:** -- `section` - 节名称 -- `key` - 键名称 -- `defaultValue` - 默认值(键不存在时返回) - -**返回值:** -- 字符串值 - ---- - -#### getInt - -```cpp -int getInt( - const std::string §ion, - const std::string &key, - int defaultValue = 0 -); -``` - -获取整数值。 - ---- - -#### getFloat - -```cpp -float getFloat( - const std::string §ion, - const std::string &key, - float defaultValue = 0.0f -); -``` - -获取浮点数值。 - ---- - -#### getBool - -```cpp -bool getBool( - const std::string §ion, - const std::string &key, - bool defaultValue = false -); -``` - -获取布尔值。 - -**说明:** -- 支持 "true"/"false"、"yes"/"no"、"1"/"0" 等格式 - ---- - -#### setString - -```cpp -void setString( - const std::string §ion, - const std::string &key, - const std::string &value -); -``` - -设置字符串值。 - -**说明:** -- 自动标记为脏数据 -- 事务外自动保存 - ---- - -#### setInt - -```cpp -void setInt( - const std::string §ion, - const std::string &key, - int value -); -``` - -设置整数值。 - ---- - -#### setFloat - -```cpp -void setFloat( - const std::string §ion, - const std::string &key, - float value -); -``` - -设置浮点数值。 - ---- - -#### setBool - -```cpp -void setBool( - const std::string §ion, - const std::string &key, - bool value -); -``` - -设置布尔值。 - ---- - -#### removeKey - -```cpp -void removeKey(const std::string §ion, const std::string &key); -``` - -删除键。 - ---- - -#### removeSection - -```cpp -void removeSection(const std::string §ion); -``` - -删除整个 section。 - ---- - -#### hasKey - -```cpp -bool hasKey(const std::string §ion, const std::string &key); -``` - -检查键是否存在。 - ---- - -#### hasSection - -```cpp -bool hasSection(const std::string §ion); -``` - -检查 section 是否存在。 - ---- - -#### clear - -```cpp -void clear(); -``` - -清除所有数据。 - ---- - -### 事务支持 - -#### beginTransaction - -```cpp -void beginTransaction(); -``` - -开始事务。 - -**说明:** -- 事务中的修改不会立即写入文件 -- 支持批量操作,提高性能 -- 事务可以回滚 - -**示例:** -```cpp -data.beginTransaction(); - -// 批量修改 -data.setInt("Player", "Level", 10); -data.setInt("Player", "Exp", 1000); -data.setString("Player", "Title", "Knight"); - -// 提交事务 -data.commit(); -``` - ---- - -#### commit - -```cpp -bool commit(); -``` - -提交事务。 - -**返回值:** -- `true` - 提交成功 -- `false` - 提交失败 - -**说明:** -- 写入文件并提交存档(如果已挂载) -- 事务结束后自动保存 - ---- - -#### rollback - -```cpp -void rollback(); -``` - -回滚事务。 - -**说明:** -- 放弃事务中的所有修改 -- 重新加载文件恢复数据 - -**示例:** -```cpp -data.beginTransaction(); -data.setInt("Test", "Value", 999); - -// 放弃修改 -data.rollback(); - -// Value 恢复为原来的值 -``` - ---- - -#### isInTransaction - -```cpp -bool isInTransaction() const; -``` - -检查是否在事务中。 - ---- - -### 工具方法 - -#### getAllSections - -```cpp -std::vector getAllSections() const; -``` - -获取所有 section 名称。 - -**返回值:** -- section 名称列表 - ---- - -#### getAllKeys - -```cpp -std::vector getAllKeys(const std::string §ion) const; -``` - -获取指定 section 的所有 key。 - -**参数:** -- `section` - section 名称 - -**返回值:** -- key 名称列表 - ---- - -#### loadFromSave - -```cpp -bool loadFromSave(const std::string &path); -``` - -从存档加载(自动处理挂载路径)。 - -**参数:** -- `path` - 存档内文件路径 - -**返回值:** -- `true` - 加载成功 -- `false` - 加载失败(存档未挂载或文件不存在) - -**示例:** -```cpp -if (data.loadFromSave("savegame.ini")) { - // 加载成功 -} -``` - ---- - -#### saveToSave - -```cpp -bool saveToSave(const std::string &path); -``` - -保存到存档(自动处理挂载路径和提交)。 - -**参数:** -- `path` - 存档内文件路径 - -**返回值:** -- `true` - 保存成功 -- `false` - 保存失败 - -**说明:** -- 自动调用 `commitSaveData()` 提交更改 - ---- - -## 完整示例 - -### 游戏存档管理 - -```cpp -#include - -using namespace extra2d; - -class SaveManager { -private: - DataStore saveData_; - bool mounted_ = false; - -public: - bool initialize() { - // 挂载用户存档 - mounted_ = saveData_.mountSaveData(SaveDataType::Account); - if (!mounted_) { - E2D_LOG_ERROR("存档挂载失败"); - return false; - } - - // 加载存档 - if (!saveData_.loadFromSave("game_save.ini")) { - E2D_LOG_INFO("存档不存在,创建新存档"); - createNewSave(); - } - - return true; - } - - void shutdown() { - if (mounted_) { - saveData_.unmountSaveData(); - mounted_ = false; - } - } - - void createNewSave() { - saveData_.beginTransaction(); - - saveData_.setString("Player", "Name", "Player1"); - saveData_.setInt("Player", "Level", 1); - saveData_.setInt("Player", "Exp", 0); - saveData_.setInt("Progress", "Chapter", 1); - saveData_.setInt("Settings", "Difficulty", 1); - - saveData_.commit(); - saveData_.saveToSave("game_save.ini"); - } - - void saveGame(const PlayerData &player) { - saveData_.beginTransaction(); - - saveData_.setInt("Player", "Level", player.level); - saveData_.setInt("Player", "Exp", player.exp); - saveData_.setInt("Player", "Health", player.health); - saveData_.setInt("Player", "Mana", player.mana); - saveData_.setInt("Progress", "Chapter", player.chapter); - saveData_.setString("Progress", "Checkpoint", player.checkpoint); - - if (saveData_.commit()) { - saveData_.saveToSave("game_save.ini"); - E2D_LOG_INFO("游戏已保存"); - } else { - E2D_LOG_ERROR("保存失败"); - } - } - - void loadGame(PlayerData &player) { - player.level = saveData_.getInt("Player", "Level", 1); - player.exp = saveData_.getInt("Player", "Exp", 0); - player.health = saveData_.getInt("Player", "Health", 100); - player.mana = saveData_.getInt("Player", "Mana", 50); - player.chapter = saveData_.getInt("Progress", "Chapter", 1); - player.checkpoint = saveData_.getString("Progress", "Checkpoint", "start"); - } - - bool hasSaveFile() { - return saveData_.hasSection("Player"); - } -}; -``` - -### 设置管理 - -```cpp -class SettingsManager { -private: - DataStore settings_; - -public: - void load() { - // PC 平台使用普通文件 - #ifndef __SWITCH__ - settings_.load("settings.ini"); - #else - // Switch 平台使用存档 - if (settings_.mountSaveData(SaveDataType::Common)) { - settings_.loadFromSave("settings.ini"); - } - #endif - } - - void save() { - #ifndef __SWITCH__ - settings_.save("settings.ini"); - #else - settings_.saveToSave("settings.ini"); - settings_.unmountSaveData(); - #endif - } - - int getVolume() { - return settings_.getInt("Audio", "Volume", 80); - } - - void setVolume(int volume) { - settings_.setInt("Audio", "Volume", volume); - } - - bool isFullscreen() { - return settings_.getBool("Video", "Fullscreen", false); - } - - void setFullscreen(bool fullscreen) { - settings_.setBool("Video", "Fullscreen", fullscreen); - } -}; -``` - ---- - -## 注意事项 - -### Switch 平台 - -1. **必须提交存档**:修改存档数据后,必须调用 `commitSaveData()` 或 `saveToSave()`,否则更改不会持久化 - -2. **用户ID管理**: - - `Account` 类型存档需要有效的用户ID - - 可以使用 `getCurrentUserId()` 自动获取当前用户 - - 公共存档使用 `Common` 类型,不需要用户ID - -3. **存档挂载**: - - 每个挂载点需要唯一的名称 - - 应用退出时会自动卸载,但建议显式调用 `unmountSaveData()` - -4. **存档空间**: - - 注意存档空间限制 - - 大数据(如截图)建议使用 `Cache` 类型 - -### 通用 - -1. **事务使用**: - - 批量修改时使用事务提高性能 - - 事务中的错误可以通过 `rollback()` 恢复 - -2. **自动保存**: - - 事务外每次 `set` 操作都会触发自动保存 - - 频繁修改建议使用事务批量处理 - -3. **文件格式**: - - 使用标准 INI 格式 - - 支持注释(以 `;` 或 `#` 开头) - - Section 和 Key 不区分大小写 - ---- - -## 相关文件 - -- [data.h](file:///c:/Users/soulcoco/Desktop/Easy2D/Extra2D/Extra2D/include/extra2d/utils/data.h) - 头文件 -- [data.cpp](file:///c:/Users/soulcoco/Desktop/Easy2D/Extra2D/Extra2D/src/utils/data.cpp) - 实现文件 diff --git a/docs/INDEX.md b/docs/INDEX.md deleted file mode 100644 index 68c0e48..0000000 --- a/docs/INDEX.md +++ /dev/null @@ -1,225 +0,0 @@ -# Extra2D 文档索引 - -欢迎来到 Extra2D 文档中心!这里包含了使用 Extra2D 游戏引擎所需的所有文档。 - -## 📚 快速导航 - -### 入门指南 - -| 文档 | 描述 | -|------|------| -| [README.md](../README.md) | 项目概述和快速开始 | -| [Switch 构建指南](./SWITCH_BUILD_GUIDE.md) | Nintendo Switch 平台构建教程 | -| [PC 构建指南](./PC_BUILD_GUIDE.md) | Windows/Linux/macOS 构建教程 | - -### API 参考 - -| 文档 | 描述 | -|------|------| -| [API 参考文档](./API_REFERENCE.md) | 完整的 API 文档和示例 | - -### 开发文档 - -| 文档 | 描述 | -|------|------| -| [迁移完成记录](./SWITCH_MIGRATION_COMPLETE.md) | 项目迁移历史记录 | -| [数据存储文档](./DataStore.md) | 数据持久化系统文档 | - ---- - -## 🚀 快速开始 - -### 1. 选择平台 - -**Nintendo Switch:** -```bash -# 设置环境变量 -$env:DEVKITPRO = "C:/devkitPro" - -# 配置并构建 -xmake f --plat=switch -a arm64 -xmake -``` - -**Windows PC:** -```bash -# 设置环境变量 -$env:VCPKG_ROOT = "C:\vcpkg" - -# 配置并构建 -xmake f --plat=windows -a x64 -xmake -``` - -### 2. 运行示例 - -```bash -# Switch(生成 .nro 文件) -./build/switch/hello_world.nro - -# Windows -./build/windows/hello_world.exe -``` - -### 3. 开始开发 - -```cpp -#include - -using namespace extra2d; - -int main() { - // 初始化 - Logger::init(); - - AppConfig config; - config.title = "My Game"; - config.width = 1280; - config.height = 720; - - auto& app = Application::instance(); - app.init(config); - - // 创建场景 - auto scene = makePtr(); - - // 添加精灵 - auto sprite = Sprite::create("player.png"); - scene->addChild(sprite); - - // 运行动画 - sprite->runAction(makePtr(1.0f, Vec2(300, 200))); - - // 运行 - app.enterScene(scene); - app.run(); - - return 0; -} -``` - ---- - -## 📖 核心概念 - -### 应用生命周期 - -``` -main() - └── Application::init() - └── Scene::onEnter() - └── Node::onUpdate() [每帧] - └── Node::onRender() [每帧] - └── Scene::onExit() -``` - -### 场景图结构 - -``` -Scene (场景) - ├── Node (节点) - │ ├── Sprite (精灵) - │ ├── Text (文本) - │ └── CustomNode (自定义节点) - └── Node - └── ... -``` - -### 坐标系统 - -- **原点**: 左上角 (0, 0) -- **X轴**: 向右为正 -- **Y轴**: 向下为正 -- **单位**: 像素 - ---- - -## 🛠️ 平台差异 - -| 功能 | Switch | PC | -|------|--------|-----| -| 窗口 | 固定全屏 | 可调整大小 | -| 输入 | 手柄/触摸 | 键盘/鼠标/手柄 | -| 资源路径 | `romfs:/` | `./assets/` | -| 渲染 | OpenGL ES | OpenGL ES (Angle) | - ---- - -## 💡 示例代码 - -### 基础示例 - -- [Hello World](../Extra2D/examples/hello_world/main.cpp) - 基础窗口和文本 -- [Collision Demo](../Extra2D/examples/collision_demo/main.cpp) - 碰撞检测 -- [Spatial Index Demo](../Extra2D/examples/spatial_index_demo/main.cpp) - 空间索引 - -### 常用模式 - -**场景切换:** -```cpp -auto newScene = makePtr(); -auto transition = makePtr(0.5f); -app.enterScene(newScene, transition); -``` - -**输入处理:** -```cpp -void onUpdate(float dt) { - auto& input = app.input(); - - if (input.isKeyPressed(Key::Space)) { - jump(); - } - - if (input.isButtonPressed(GamepadButton::A)) { - jump(); - } -} -``` - -**资源加载:** -```cpp -auto& resources = app.resources(); -auto texture = resources.loadTexture("player.png"); -auto font = resources.loadFont("font.ttf", 24); -auto sound = resources.loadSound("jump.wav"); -``` - ---- - -## 📦 项目结构 - -``` -Extra2D/ -├── docs/ # 文档 -├── Extra2D/ -│ ├── include/extra2d/ # 头文件 -│ ├── src/ # 源文件 -│ └── examples/ # 示例程序 -├── squirrel/ # Squirrel 脚本引擎 -├── xmake/ # xmake 配置 -│ ├── toolchains/ # 工具链定义 -│ └── targets/ # 构建目标 -├── xmake.lua # 主构建配置 -└── README.md # 项目说明 -``` - ---- - -## 🔗 相关链接 - -- **GitHub**: https://github.com/ChestnutYueyue/extra2d -- **Issues**: https://github.com/ChestnutYueyue/extra2d/issues -- **devkitPro**: https://devkitpro.org/ -- **Switch 开发**: https://switchbrew.org/ - ---- - -## 📝 许可证 - -Extra2D 使用 [MIT 许可证](../LICENSE)。 - ---- - -**最后更新**: 2026年2月10日 -**版本**: 3.1.0 diff --git a/docs/PC_BUILD_GUIDE.md b/docs/PC_BUILD_GUIDE.md deleted file mode 100644 index 20abe7c..0000000 --- a/docs/PC_BUILD_GUIDE.md +++ /dev/null @@ -1,262 +0,0 @@ -# Easy2D PC 端编译指南 - -本文档说明如何在 PC 端(Windows/Linux/macOS)编译和运行 Easy2D 引擎。 - -## 概述 - -Easy2D 现在支持多平台: -- **Nintendo Switch** (ARM64) - 原始平台 -- **Windows** (x64) - 新增 -- **Linux** (x64) - 新增 -- **macOS** (x64/ARM64) - 新增 - -PC 端使用 OpenGL ES 3.2(通过 Angle 或 Mesa)保持与 Switch 的代码兼容性。 - -## 前置条件 - -### Windows - -1. **Visual Studio 2019/2022** - 安装 C++ 桌面开发工作负载 -2. **xmake** - 构建系统 (https://xmake.io) -3. **SDL2** - 可以通过以下方式安装: - - vcpkg: `vcpkg install sdl2 sdl2-mixer` - - 手动下载:https://www.libsdl.org/download-2.0.php -4. **Angle** (可选) - Google 的 GLES 实现 - - 下载 Angle 二进制文件或从 Chromium 构建 - - 放置到 `third_party/angle/` 目录 - -### Linux (Ubuntu/Debian) - -```bash -# 安装依赖 -sudo apt-get update -sudo apt-get install -y build-essential -sudo apt-get install -y libsdl2-dev libsdl2-mixer-dev -sudo apt-get install -y libgles2-mesa-dev libegl1-mesa-dev - -# 安装 xmake -sudo add-apt-repository ppa:xmake-io/xmake -sudo apt-get update -sudo apt-get install xmake -``` - -### macOS - -```bash -# 安装 Homebrew (如果还没有) -/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - -# 安装依赖 -brew install sdl2 sdl2_mixer -brew install angle # 或 mesa - -# 安装 xmake -brew install xmake -``` - -## 编译步骤 - -### 1. 配置项目 - -```bash -# 进入项目目录 -cd c:\Users\soulcoco\Desktop\Easy2D\Extra2D - -# 配置 PC 平台构建 -xmake config -p pc -m release - -# 或使用环境变量 -set E2D_PLATFORM=pc # Windows -export E2D_PLATFORM=pc # Linux/macOS -xmake config -``` - -### 2. 编译引擎库 - -```bash -# 编译 Easy2D 静态库 -xmake build extra2d -``` - -### 3. 编译示例程序 - -```bash -# 编译 Hello World 示例 -xmake build hello_world - -# 编译所有示例 -xmake build -a -``` - -### 4. 运行示例 - -```bash -# 运行 Hello World -xmake run hello_world - -# 或手动运行 -./build/windows/hello_world.exe # Windows -./build/linux/hello_world # Linux -./build/macos/hello_world # macOS -``` - -## 项目结构 - -``` -Extra2D/ -├── xmake.lua # 主构建配置 -├── xmake/ -│ ├── toolchains/ -│ │ ├── switch.lua # Switch 工具链 -│ │ └── pc.lua # PC 工具链 (新增) -│ └── targets/ -│ ├── extra2d.lua # 引擎库配置 -│ └── examples.lua # 示例程序配置 -├── Extra2D/ -│ ├── include/ -│ │ └── extra2d/ -│ │ └── platform/ -│ │ ├── platform_compat.h # 跨平台兼容性 (新增) -│ │ ├── file_system.h # 文件系统工具 (新增) -│ │ ├── window.h # 窗口系统 (修改) -│ │ └── input.h # 输入系统 (修改) -│ └── src/ -│ └── platform/ -│ ├── window.cpp # (修改) -│ ├── input.cpp # (修改) -│ └── file_system.cpp # (新增) -└── examples/ - └── hello_world/ - └── main.cpp # (修改,支持多平台) -``` - -## 平台差异 - -### 窗口系统 - -| 功能 | Switch | PC | -|------|--------|-----| -| 窗口模式 | 始终全屏 (1280x720) | 可配置全屏/窗口 | -| 窗口大小 | 固定 | 可调整 | -| DPI 缩放 | 1.0 | 自动检测 | -| 鼠标光标 | 无 | 支持多种形状 | - -### 输入系统 - -| 功能 | Switch | PC | -|------|--------|-----| -| 键盘 | 映射到手柄 | 原生支持 | -| 鼠标 | 映射到触摸 | 原生支持 | -| 手柄 | SDL GameController | SDL GameController | -| 触摸屏 | 原生 | 可选支持 | - -### 文件系统 - -| 功能 | Switch | PC | -|------|--------|-----| -| 资源路径 | `romfs:/assets/` | `./assets/` 或 exe 目录 | -| 文件访问 | RomFS | 标准文件系统 | - -## 开发指南 - -### 编写跨平台代码 - -```cpp -#include -#include - -// 检查平台 -if (platform::isSwitch()) { - // Switch 特定代码 -} else if (platform::isPC()) { - // PC 特定代码 -} - -// 解析资源路径(自动处理平台差异) -std::string fontPath = FileSystem::resolvePath("assets/font.ttf"); -// Switch: "romfs:/assets/font.ttf" -// PC: "./assets/font.ttf" - -// 条件编译 -#ifdef PLATFORM_SWITCH - // Switch 代码 -#elif defined(PLATFORM_PC) - // PC 代码 -#endif -``` - -### 输入处理 - -```cpp -// 跨平台输入(推荐) -auto& input = Application::instance().input(); - -// 键盘(PC 原生,Switch 映射到手柄) -if (input.isKeyPressed(Key::Space)) { - // 处理空格键 -} - -// 手柄(所有平台) -if (input.isButtonPressed(SDL_CONTROLLER_BUTTON_A)) { - // 处理 A 按钮 -} - -// 鼠标(PC 原生,Switch 映射到触摸) -if (input.isMouseDown(MouseButton::Left)) { - // 处理鼠标左键 -} -``` - -## 故障排除 - -### 找不到 SDL2 - -**Windows:** -```bash -# 设置 SDL2 路径 -set SDL2_DIR=C:\SDL2-2.28.0 -xmake config -``` - -**Linux:** -```bash -# 安装 SDL2 开发库 -sudo apt-get install libsdl2-dev libsdl2-mixer-dev -``` - -### 找不到 GLES - -**Windows (Angle):** -```bash -# 下载 Angle 并设置路径 -set ANGLE_DIR=C:\angle -xmake config -``` - -**Linux (Mesa):** -```bash -# 安装 Mesa GLES -sudo apt-get install libgles2-mesa-dev libegl1-mesa-dev -``` - -### 编译错误 - -1. 确保使用 C++17 或更高版本 -2. 检查 xmake 版本是否最新:`xmake --version` -3. 清理构建缓存:`xmake clean -a` - -## 下一步 - -1. 尝试编译和运行 `hello_world` 示例 -2. 阅读 `platform_compat.h` 了解平台 API -3. 使用 `FileSystem` 类处理跨平台文件路径 -4. 参考示例代码编写跨平台应用 - -## 许可证 - -Easy2D 采用 MIT 许可证。详见 LICENSE 文件。 - ---- - -**最后更新**: 2026年2月10日 -**Easy2D 版本**: 3.1.0 diff --git a/docs/SWITCH_BUILD_GUIDE.md b/docs/SWITCH_BUILD_GUIDE.md deleted file mode 100644 index 26883ff..0000000 --- a/docs/SWITCH_BUILD_GUIDE.md +++ /dev/null @@ -1,310 +0,0 @@ -# Easy2D Nintendo Switch 编译指南 - -## 概述 - -本文档说明如何使用 xmake 为 Nintendo Switch 编译 Easy2D 引擎及其示例程序。 - -## 前置条件 - -### 1. 必需工具 - -- **devkitPro** - Nintendo Switch 开发工具包 -- **xmake** - 跨平台构建系统(v3.0.6+) -- **devkitA64** - ARM64编译器工具链(devkitPro 的一部分) - -### 2. 安装 devkitPro - -#### Windows - -1. 从 https://devkitpro.org/wiki/Getting_Started/devkitPro_installer 下载 devkitPro 安装程序 -2. 运行安装程序,选择以下组件: - - devkitA64 (ARM64) - - libnx (Nintendo Switch库) - - mesa (OpenGL ES) - - tools (nacptool, elf2nro 等) -3. 默认安装路径:`C:\devkitPro` - -#### Linux/macOS - -请参考官方文档:https://devkitpro.org/wiki/Getting_Started - -### 3. 验证安装 - -```bash -# 检查devkitPro是否正确安装 -$env:DEVKITPRO = "C:\devkitPro" # Windows PowerShell -export DEVKITPRO=/opt/devkitpro # Linux/macOS - -# 检查工具链 -aarch64-none-elf-gcc --version # 应该显示 GCC 版本 - -# 检查xmake -xmake --version # 应该显示 v3.0.6 或更高 -``` - -## 编译步骤 - -### 1. 配置项目 - -```bash -cd C:\Users\soulcoco\Desktop\Easy2D\Easy2D-dev - -# 配置编译(使用Switch工具链) -xmake config -p switch -a arm64 - -# 或者使用默认配置 -xmake config -``` - -### 2. 编译核心库 - -编译 Easy2D 静态库: - -```bash -xmake build easy2d -``` - -**输出:** -- Release: `build/switch/libeasy2d.a` -- Debug: `build/switch/libeasy2dd.a` - -### 3. 编译示例程序 - -#### 编译音频演示 - -```bash -xmake build switch_audio_demo -``` - -**输出:** -- ELF: `build/switch/switch_audio_demo` -- NACP: `build/switch/switch_audio_demo.nacp` -- NRO: `build/switch/switch_audio_demo.nro` (Switch可执行文件) - -#### 编译动画演示 - -```bash -xmake build switch_animation_demo -``` - -**输出:** -- NRO: `build/switch/switch_animation_demo.nro` - -### 4. 一次编译所有目标 - -```bash -xmake build -a -``` - -## 项目结构 - -``` -Easy2D-dev/ -├── xmake.lua # 构建配置 -├── Easy2D/ -│ ├── include/ # 头文件 -│ │ ├── easy2d/ # 引擎头文件 -│ │ │ ├── app/ # 应用系统 -│ │ │ ├── platform/ # 平台层 -│ │ │ ├── graphics/ # 图形系统 -│ │ │ ├── audio/ # 音频系统 -│ │ │ ├── scene/ # 场景管理 -│ │ │ ├── resource/ # 资源管理 -│ │ │ └── utils/ # 工具类 -│ │ ├── glm/ # GLM数学库 -│ │ ├── stb/ # STB图像库 -│ │ └── pfd/ # 文件对话框库 -│ ├── src/ # 实现文件 -│ │ ├── app/ # 应用实现 -│ │ ├── platform/ # 平台实现(Switch优化) -│ │ │ └── switch/ # Switch特定代码 -│ │ ├── graphics/ # 图形实现 -│ │ ├── audio/ # 音频实现 -│ │ └── ... -│ └── examples/ # 示例程序 -│ ├── switch_audio_demo/ # Switch音频演示 -│ ├── switch_animation_demo/ # Switch动画演示 -│ └── ... -└── squirrel/ # Squirrel脚本引擎 -``` - -## 编译配置详解 - -### xmake.lua 中的关键配置 - -#### 1. Switch 工具链定义 (行 15-51) - -```lua -toolchain("switch") - set_kind("standalone") - set_description("Nintendo Switch devkitA64 toolchain") - - local devkitPro = "C:/devkitPro" - local devkitA64 = path.join(devkitPro, "devkitA64") - - -- 编译器 - set_toolset("cc", path.join(devkitA64, "bin/aarch64-none-elf-gcc.exe")) - set_toolset("cxx", path.join(devkitA64, "bin/aarch64-none-elf-g++.exe")) - - -- 架构标志 - local arch_flags = "-march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE" - - -- 链接 EGL 和 OpenGL ES (mesa) - add_syslinks("EGL", "GLESv2", "glapi", "drm_nouveau") -``` - -#### 2. Easy2D 静态库配置 (行 60-134) - -```lua -target("easy2d") - set_kind("static") - set_plat("switch") -- 平台 - set_arch("arm64") -- 架构 - set_toolchains("switch") -- 工具链 - - add_files(SRC_DIR .. "/**.cpp") -- 源文件 - add_files("squirrel/squirrel/*.cpp") -- 脚本引擎 - add_includedirs(INC_DIR) -- 头文件目录 -``` - -#### 3. Switch 示例程序配置 (行 139-257) - -xmake 自动处理: -- **编译** ELF 文件 -- **生成 NACP** 应用元数据 -- **转换为 NRO** (Switch 可执行格式) -- **打包 RomFS** (资源文件系统) - -## 故障排除 - -### 编译错误 - -#### 错误:找不到 Switch 工具链 - -``` -Error: toolchain 'switch' not found -``` - -**解决方案:** -1. 确认 `DEVKITPRO` 环境变量已设置 -2. 检查 devkitPro 安装路径:`C:\devkitPro` (Windows) 或 `/opt/devkitpro` (Linux) -3. 验证 `devkitA64/bin` 下的编译器存在 - -#### 错误:找不到 libnx 库 - -``` -Error: cannot find -lnx -``` - -**解决方案:** -1. 验证 devkitPro 安装了 libnx 包 -2. 检查 `DEVKITPRO/libnx` 目录是否存在 - -#### 错误:OpenGL ES 头文件缺失 - -``` -Error: GL/gl.h: No such file or directory -``` - -**解决方案:** -1. 验证 mesa 已安装:`DEVKITPRO/portlibs/switch/include` -2. 检查 xmake.lua 中的包含目录配置 - -### 链接错误 - -#### 未定义的引用到 EGL 函数 - -``` -undefined reference to 'eglInitialize' -``` - -**解决方案:** -- 确保 EGL 库链接顺序正确(xmake.lua 第 93 行) - -### 运行时错误 - -#### NRO 文件无法在 Switch 上运行 - -**检查清单:** -1. 确认 `DEVKITPRO` 环境变量设置正确 -2. 验证 RomFS 资源已正确打包(如果需要) -3. 检查应用元数据(NACP 文件)是否正确生成 - -## Switch 开发资源 - -- **官方文档**: https://switchbrew.org/wiki/Main_Page -- **libnx 文档**: https://libnx.readthedocs.io/ -- **devkitPro 论坛**: https://devkitpro.org/ -- **Easy2D 文档**: https://github.com/easy2d/Easy2D - -## 编译选项 - -### 编译模式 - -```bash -# Debug 模式(包含调试符号) -xmake config -m debug -xmake build easy2d - -# Release 模式(优化编译) -xmake config -m release -xmake build easy2d -``` - -### 并行编译 - -```bash -# 使用 8 个线程编译 -xmake build -j 8 -``` - -### 清理构建 - -```bash -# 清理所有构建文件 -xmake clean - -# 仅清理目标 -xmake clean easy2d -``` - -## 下一步 - -1. **修改示例程序** - 编辑 `Easy2D/examples/switch_*_demo/main.cpp` -2. **添加资源** - 将资源放在 `assets/` 目录 -3. **优化性能** - 使用 Release 模式编译 -4. **部署到 Switch** - 将 NRO 文件复制到 Switch SD 卡 - -## 常见问题 - -### Q: 如何调试 Switch 应用? - -A: 可以使用以下方法: -- 使用 `nxlink` 输出日志到 PC -- 在应用中使用 `E2D_LOG_INFO()` 宏输出调试信息 -- 使用支持 Switch 的调试器(如 GDB with nxlink) - -### Q: 如何部署资源到 Switch? - -A: -1. 将资源放在 `examples/switch_*_demo/assets/` 目录 -2. xmake 会自动将资源打包到 RomFS -3. 在代码中使用 `romfs:/` 前缀访问资源 - -### Q: 支持哪些音频格式? - -A: miniaudio 支持: -- WAV -- FLAC -- MP3 -- VORBIS - -## 许可证 - -Easy2D 采用 MIT 许可证。详见 LICENSE 文件。 - ---- - -**最后更新**: 2026年2月9日 -**Easy2D 版本**: 3.1.0 -**Switch 工具链**: devkitA64 (devkitPro) diff --git a/docs/SWITCH_MIGRATION_COMPLETE.md b/docs/SWITCH_MIGRATION_COMPLETE.md deleted file mode 100644 index 7f205cb..0000000 --- a/docs/SWITCH_MIGRATION_COMPLETE.md +++ /dev/null @@ -1,357 +0,0 @@ -# Easy2D Nintendo Switch 移植项目完成总结 - -## 项目概述 - -完成了 Easy2D v3.1.0 游戏引擎到 Nintendo Switch 平台的完整移植,包括所有核心系统、示例程序和编译配置。 - -## 完成的工作 - -### Phase 1: 核心平台系统重构 - -| 步骤 | 组件 | 状态 | 说明 | -|------|------|------|------| -| 1 | **Window/EGL系统** | ✅ 完成 | 从GLFW→EGL+libnx,支持Switch固定分辨率1280×720 | -| 2 | **输入系统** | ✅ 完成 | 从GLFW键鼠→libnx HID,支持手柄+触摸屏 | -| 3 | **图形后端** | ✅ 完成 | 从GLEW→mesa OpenGL ES,链接EGL/GLESv2 | -| 4 | **渲染初始化** | ✅ 完成 | 适配Switch OpenGL ES限制,帧缓冲配置 | -| 5 | **音频系统** | ✅ 完成 | 使用miniaudio替代SDL2_mixer,Switch优化 | -| 6 | **日志系统** | ✅ 完成 | 从spdlog→printf输出,支持nxlink调试 | - -### Phase 2: 应用生命周期与示例 - -| 步骤 | 组件 | 状态 | 说明 | -|------|------|------|------| -| 7 | **应用生命周期** | ✅ 完成 | 完整的Switch主循环、初始化、清理、RomFS支持 | -| 8.1 | **Switch音频演示** | ✅ 完成 | 创建switch_audio_demo示例程序 | -| 8.2 | **Switch动画演示** | ✅ 完成 | 创建switch_animation_demo示例程序 | -| 8.3 | **编译配置与文档** | ✅ 完成 | xmake配置、编译脚本、build guide文档 | - -## 关键文件变更 - -### 新创建的文件 - -``` -Easy2D-dev/ -├── SWITCH_BUILD_GUIDE.md # Switch编译指南(620行) -├── Easy2D/ -│ ├── include/easy2d/platform/ -│ │ └── switch_compat.h # Switch兼容性头文件(70行) -│ └── examples/ -│ ├── switch_audio_demo/ -│ │ ├── main.cpp # 音频演示程序(106行) -│ │ └── assets/ # 音频资源目录 -│ └── switch_animation_demo/ -│ ├── main.cpp # 动画演示程序(120行) -│ └── assets/ # 动画资源目录 -``` - -### 修改的文件(第1-6步) - -``` -Easy2D/src/ -├── app/application.cpp # Switch主循环、初始化、关闭 -├── platform/ -│ ├── window.cpp/window.h # EGL窗口管理 -│ ├── input.cpp/input.h # libnx HID输入 -│ └── switch/ # Switch特定实现 -├── graphics/opengl/gl_renderer.cpp # OpenGL ES渲染 -├── audio/audio_engine.cpp/sound.cpp # miniaudio系统 -├── resource/resource_manager.cpp # RomFS资源加载 -└── utils/logger.cpp # printf日志系统 -``` - -### xmake.lua 更新 - -**新增配置:** -1. **Switch工具链定义** (行15-51) - - devkitA64编译器配置 - - ARM64架构标志 - - libnx/EGL/OpenGL ES库链接 - -2. **Easy2D静态库** (行60-134) - - Platform选择:`set_plat("switch")` - - 编译标志优化 - - Squirrel脚本引擎集成 - -3. **Switch演示程序** (行139-257) - - switch_audio_demo目标 - - switch_animation_demo目标 - - 自动NACP生成 - - NRO格式转换 - - RomFS资源打包 - -## 技术亮点 - -### 1. 完整的平台抽象 - -```cpp -// 平台检测宏(switch_compat.h) -#ifdef __SWITCH__ - #include - #include - #include -#endif -``` - -### 2. Switch初始化流程 - -```cpp -// application.cpp 中的完整Switch初始化 -socketInitializeDefault(); // nxlink调试输出 -romfsInit(); // RomFS文件系统 -// ... 图形/音频初始化 ... -romfsExit(); // 清理 -socketExit(); -``` - -### 3. EGL上下文管理 - -```cpp -// window.cpp - Switch固定分辨率1280×720 -eglInitialize(display_, nullptr, nullptr); -eglBindAPI(EGL_OPENGL_ES_BIT); -eglCreateWindowSurface(display_, config_, window, nullptr); -``` - -### 4. libnx HID输入处理 - -```cpp -// input.cpp - Switch手柄+触摸屏 -hidScanInput(); -u32 kdown = hidKeyboardDown(0); -HidTouchScreenState touchState = {0}; -hidGetTouchScreenStates(&touchState, 1); -``` - -### 5. RomFS资源加载 - -```cpp -// 资源搜索路径配置 -resourceManager_->addSearchPath("romfs:/"); -auto tex = resourceManager_->loadTexture("romfs:/textures/sprite.png"); -``` - -## 编译状态 - -### 配置验证 ✅ - -- xmake配置识别三个目标: - - `easy2d` (静态库) - - `switch_audio_demo` (音频演示) - - `switch_animation_demo` (动画演示) - -### 构建准备就绪 ✅ - -编译命令已测试: -```bash -xmake config -p switch -a arm64 -xmake build -a # 编译所有目标 -``` - -## 性能优化考虑 - -1. **编译优化** - - Release模式:`-O2` 优化 - - Debug模式:保留符号用于调试 - -2. **内存优化** - - 预分配纹理缓存 - - 精灵批处理优化 - - 场景对象池管理 - -3. **渲染优化** - - OpenGL ES 2.0兼容性 - - VAO/VBO使用 - - 后处理管道支持 - -4. **音频优化** - - miniaudio支持硬件加速 - - 立体声输出支持 - - 低延迟播放 - -## Switch特定限制与处理 - -| 功能 | 限制 | 处理方案 | -|------|------|---------| -| 分辨率 | 固定1280×720 | 硬编码分辨率 | -| 输入 | 无鼠标 | 仅支持手柄+触摸 | -| 窗口 | 无标题栏、全屏 | WindowConfig强制全屏 | -| 光标 | 不可见 | 应用层隐藏光标 | -| 文件I/O | 仅RomFS | 使用"romfs:/"前缀 | -| 调试 | nxlink输出 | 集成nxlink支持 | - -## 测试清单 - -- [x] xmake配置正确识别Switch工具链 -- [x] 头文件包含路径正确配置 -- [x] 静态库编译配置完整 -- [x] 示例程序编译配置完整 -- [x] NRO后处理脚本配置完整 -- [x] 日志系统输出配置完整 -- [x] 音频系统配置完整 -- [x] 平台抽象层完整 -- [x] 编译文档完整 - -## 使用方法 - -### 快速开始 - -1. **设置环境** - ```bash - $env:DEVKITPRO = "C:\devkitPro" # Windows - cd C:\Users\soulcoco\Desktop\Easy2D\Easy2D-dev - ``` - -2. **配置项目** - ```bash - xmake config -p switch -a arm64 - ``` - -3. **编译核心库** - ```bash - xmake build easy2d - ``` - -4. **编译示例程序** - ```bash - xmake build switch_audio_demo - xmake build switch_animation_demo - ``` - -5. **生成NRO文件** - - 自动输出到 `build/switch/switch_*_demo.nro` - -### 部署到Switch - -1. 将 NRO 文件复制到 Switch SD 卡 -2. 在Switch主菜单中运行应用 - -### 开发工作流 - -1. 编辑源代码 -2. 运行 `xmake build -a` -3. 测试输出的NRO文件 -4. 迭代改进 - -## 后续改进建议 - -### 短期(1-2周) - -1. **添加更多示例** - - 物理系统演示 - - UI系统演示 - - 脚本系统演示 - -2. **性能优化** - - FPS显示优化 - - 内存使用分析 - - 渲染性能测试 - -3. **错误处理** - - Switch特定的异常处理 - - 内存不足处理 - - 文件I/O错误处理 - -### 中期(1个月) - -1. **功能扩展** - - 网络支持(Switch WiFi) - - 多人游戏支持 - - 存档系统 - -2. **工具链改进** - - CMake支持(可选) - - CI/CD集成 - - 自动化测试 - -3. **文档完善** - - API文档生成(Doxygen) - - 教程编写 - - 示例代码注释 - -### 长期(3个月+) - -1. **商业化支持** - - Nintendo Developer Program集成 - - 官方分发支持 - - 许可证管理 - -2. **社区建设** - - 示例库扩展 - - 插件系统 - - 社区论坛 - -## 项目统计 - -| 指标 | 数值 | -|------|------| -| 新增文件 | 5个 | -| 修改文件 | 8个+ | -| 代码行数(新增) | ~900行 | -| 文档行数 | ~620行 | -| 编译目标数 | 3个 | -| 示例程序数 | 2个 | -| Switch适配覆盖率 | ~95% | - -## 已知问题与解决方案 - -### 问题1: pfd库禁用 - -**原因**:portable-file-dialogs库与Switch不兼容 -**解决方案**:使用Switch原生文件选择器(future) -**状态**:xmake.lua中已注释禁用 - -### 问题2: 网络功能 - -**原因**:Switch网络需要特殊初始化 -**解决方案**:待实现 -**建议**:使用libnx网络API - -### 问题3: 光标支持 - -**原因**:Switch屏幕无光标 -**解决方案**:应用层自行绘制光标图形 -**建议**:使用精灵系统实现光标 - -## 许可证 - -- **Easy2D**: MIT License -- **devkitPro工具链**: GPL v2+ -- **libnx**: Zlib License -- **miniaudio**: 无许可(公开领域) - -## 致谢 - -- Easy2D 原作者与维护者 -- Nintendo 开发者社区 -- devkitPro 项目贡献者 - ---- - -## 总结 - -✨ **Easy2D Nintendo Switch 移植项目已成功完成!** - -这是一个完整、专业的游戏引擎移植项目,包括: -- 核心系统的完全适配 -- 两个功能完整的演示程序 -- 详细的编译指南和文档 -- 生产级别的构建配置 - -项目已准备好用于Nintendo Switch游戏开发! - -**项目版本**: v1.0 -**完成日期**: 2026年2月9日 -**状态**: ✅ 生产就绪 - ---- - -### 快速链接 - -- 📖 [Switch编译指南](./SWITCH_BUILD_GUIDE.md) -- 🎮 [音频演示源码](./Easy2D/examples/switch_audio_demo/main.cpp) -- 🎬 [动画演示源码](./Easy2D/examples/switch_animation_demo/main.cpp) -- ⚙️ [xmake配置](./xmake.lua) -- 🛠️ [平台兼容性头文件](./Easy2D/include/easy2d/platform/switch_compat.h) - -**问题与反馈**: 请提交至项目Issue追踪器 diff --git a/xmake.lua b/xmake.lua deleted file mode 100644 index 8684871..0000000 --- a/xmake.lua +++ /dev/null @@ -1,88 +0,0 @@ --- ============================================== --- Extra2D - Xmake Build Script --- Purpose: Build Extra2D static library and demo programs --- Platform: Nintendo Switch (ARM64) / PC (Windows/Linux/macOS) --- Graphics: OpenGL ES 3.2 via Mesa/Angle --- Audio: SDL2_mixer --- ============================================== - -set_project("Extra2D") -set_version("3.1.0") -set_languages("c++17") -set_encodings("utf-8") -add_rules("mode.debug", "mode.release") - --- ============================================== --- 平台检测与配置 (必须在 includes 之前) --- ============================================== - --- 检测目标平台 - 优先级:命令行 > 环境变量 > 默认值 -local target_platform = "switch" -- 默认 Switch 平台 - --- 方式1: 检查命令行传入的平台配置 (最高优先级) -local plat_config = get_config("plat") -if plat_config and plat_config ~= "" then - if plat_config == "windows" or plat_config == "linux" or plat_config == "macosx" then - target_platform = "pc" - elseif plat_config == "switch" then - target_platform = "switch" - end --- 方式2: 通过环境变量检测 PC 平台 -elseif os.getenv("E2D_PLATFORM") == "pc" then - target_platform = "pc" --- 方式3: 检查 platform 配置 -elseif has_config("platform") then - local platform_val = get_config("platform") - if platform_val == "pc" then - target_platform = "pc" - end -end - --- 设置默认平台和架构 (必须在 includes 之前调用) -if target_platform == "switch" then - set_config("plat", "switch") - set_config("arch", "arm64") -else - -- PC 平台:根据主机自动选择 - if is_host("windows") then - set_config("plat", "windows") - set_config("arch", "x64") - elseif is_host("linux") then - set_config("plat", "linux") - elseif is_host("macosx") then - set_config("plat", "macosx") - end -end - -print("Extra2D Build Configuration:") -print(" Platform: " .. target_platform) -print(" Mode: " .. (is_mode("debug") and "debug" or "release")) - --- ============================================== --- 包含子模块配置 --- ============================================== - --- 包含工具链定义 -includes("xmake/toolchains/switch.lua") -includes("xmake/toolchains/pc.lua") - --- 根据平台定义工具链 -if target_platform == "switch" then - define_switch_toolchain() -else - define_pc_toolchain() -end - --- 包含目标定义 -includes("xmake/targets/extra2d.lua") -includes("xmake/targets/examples.lua") - --- ============================================== --- 定义构建目标 --- ============================================== - --- Extra2D 引擎库 -define_extra2d_target() - --- 示例程序 -define_example_targets() diff --git a/xmake/targets/examples.lua b/xmake/targets/examples.lua deleted file mode 100644 index c8f8d1a..0000000 --- a/xmake/targets/examples.lua +++ /dev/null @@ -1,211 +0,0 @@ --- ============================================== --- Extra2D 示例程序构建目标 --- 支持平台: Nintendo Switch, Windows, Linux, macOS --- ============================================== - --- 获取 devkitPro 路径 -local function get_devkitpro_path() - return "C:/devkitPro" -end - --- 生成 Switch NRO 文件的通用后构建函数 --- @param target_name 目标名称 --- @param app_title 应用标题 --- @param app_author 应用作者 --- @param app_version 应用版本 --- @param romfs_dir RomFS 目录路径(相对于项目根目录) -local function generate_nro_after_build(target_name, app_title, app_author, app_version, romfs_dir) - after_build(function (target) - local devkitPro = get_devkitpro_path() - local elf_file = target:targetfile() - local output_dir = path.directory(elf_file) - local nacp_file = path.join(output_dir, target_name .. ".nacp") - local nro_file = path.join(output_dir, target_name .. ".nro") - local nacptool = path.join(devkitPro, "tools/bin/nacptool.exe") - local elf2nro = path.join(devkitPro, "tools/bin/elf2nro.exe") - - if not os.isfile(nacptool) then - print("Warning: nacptool not found at " .. nacptool) - return - end - if not os.isfile(elf2nro) then - print("Warning: elf2nro not found at " .. elf2nro) - return - end - - -- 生成 .nacp 文件 - os.vrunv(nacptool, {"--create", app_title, app_author, app_version, nacp_file}) - print("Built " .. path.filename(nacp_file)) - - -- 生成 .nro 文件(包含 RomFS) - local romfs_absolute = path.absolute(romfs_dir) - if os.isdir(romfs_absolute) then - print("Packing RomFS from: " .. romfs_absolute) - os.vrunv(elf2nro, {elf_file, nro_file, "--nacp=" .. nacp_file, "--romfsdir=" .. romfs_absolute}) - print("Built " .. path.filename(nro_file) .. " (with RomFS)") - else - os.vrunv(elf2nro, {elf_file, nro_file, "--nacp=" .. nacp_file}) - print("Built " .. path.filename(nro_file)) - end - end) -end - --- 定义 Switch 示例程序的通用配置 --- @param name 目标名称 --- @param options 配置选项表 -local function define_switch_example_target(name, options) - target(name) - set_kind("binary") - set_plat("switch") - set_arch("arm64") - set_toolchains("switch") - set_targetdir("build/switch") - - -- 添加源文件 - add_files(options.source_file or ("Extra2D/examples/" .. name .. "/main.cpp")) - - -- 添加头文件路径 - add_includedirs("Extra2D/include") - - -- 链接 extra2d 库 - add_deps("extra2d") - - -- Windows 控制台应用程序(仅 PC 平台) - if is_plat("windows") then - add_ldflags("-mconsole", {force = true}) - end - - -- 可选:添加链接器标志 - if options.ldflags then - add_ldflags(options.ldflags, {force = true}) - end - - -- 构建后生成 .nro 文件 - generate_nro_after_build( - name, - options.app_title or ("Extra2D " .. name), - options.app_author or "Extra2D Team", - options.app_version or "1.0.0", - options.romfs_dir or ("Extra2D/examples/" .. name .. "/romfs") - ) - target_end() -end - --- 定义 PC 示例程序的通用配置 --- @param name 目标名称 --- @param options 配置选项表 -local function define_pc_example_target(name, options) - target(name) - set_kind("binary") - set_toolchains("pc") - - -- 设置输出目录 - if is_host("windows") then - set_targetdir("build/windows") - elseif is_host("linux") then - set_targetdir("build/linux") - elseif is_host("macosx") then - set_targetdir("build/macos") - else - set_targetdir("build/pc") - end - - -- 添加源文件 - add_files(options.source_file or ("Extra2D/examples/" .. name .. "/main.cpp")) - - -- 添加头文件路径 - add_includedirs("Extra2D/include") - - -- 链接 extra2d 库 - add_deps("extra2d") - - -- 可选:添加链接器标志 - if options.ldflags then - add_ldflags(options.ldflags, {force = true}) - end - - -- PC 端构建后复制资源文件和 DLL - after_build(function (target) - local target_file = target:targetfile() - local output_dir = path.directory(target_file) - local romfs_dir = options.romfs_dir or ("Extra2D/examples/" .. name .. "/romfs") - local romfs_absolute = path.absolute(romfs_dir) - - -- 复制 vcpkg DLL 到输出目录 - local vcpkg_root = os.getenv("VCPKG_ROOT") - if vcpkg_root then - local triplet = is_arch("x64") and "x64-windows" or "x86-windows" - local vcpkg_bin = path.join(vcpkg_root, "installed", triplet, "bin") - if os.isdir(vcpkg_bin) then - -- 复制 SDL2 相关 DLL - local dlls = {"SDL2.dll", "SDL2_mixer.dll", "ogg.dll", "vorbis.dll", "vorbisfile.dll", "wavpackdll.dll"} - for _, dll in ipairs(dlls) do - local dll_path = path.join(vcpkg_bin, dll) - if os.isfile(dll_path) then - os.cp(dll_path, output_dir) - end - end - print("Copied DLLs from: " .. vcpkg_bin) - end - end - - -- 复制资源文件到输出目录 - if os.isdir(romfs_absolute) then - local assets_dir = path.join(output_dir, "assets") - os.mkdir(assets_dir) - - -- 复制 romfs 内容到 assets 目录 - local romfs_assets = path.join(romfs_absolute, "assets") - if os.isdir(romfs_assets) then - print("Copying assets from: " .. romfs_assets .. " to " .. assets_dir) - os.cp(romfs_assets .. "/*", assets_dir) - end - - print("Built " .. path.filename(target_file) .. " (with assets)") - else - print("Built " .. path.filename(target_file)) - end - end) - target_end() -end - --- 定义所有示例程序目标 -function define_example_targets() - -- 根据平台选择示例程序定义方式 - if is_plat("switch") then - -- ============================================ - -- Switch 示例程序 - -- ============================================ - define_switch_example_target("hello_world", { - app_title = "Extra2D hello_world", - app_author = "Extra2D hello_world", - app_version = "1.0.0" - }) - - define_switch_example_target("spatial_index_demo", { - app_title = "Extra2D Spatial Index Demo", - app_version = "1.0.0", - ldflags = "-Wl,-Map=build/switch/spatial_index_demo.map" - }) - - define_switch_example_target("collision_demo", { - app_title = "Extra2D Collision Demo", - app_version = "1.0.0" - }) - else - -- ============================================ - -- PC 示例程序 (Windows/Linux/macOS) - -- ============================================ - define_pc_example_target("hello_world", { - romfs_dir = "Extra2D/examples/hello_world/romfs" - }) - - define_pc_example_target("spatial_index_demo", { - romfs_dir = "Extra2D/examples/spatial_index_demo/romfs" - }) - - define_pc_example_target("collision_demo", { - romfs_dir = "Extra2D/examples/collision_demo/romfs" - }) - end -end diff --git a/xmake/targets/extra2d.lua b/xmake/targets/extra2d.lua deleted file mode 100644 index 875e286..0000000 --- a/xmake/targets/extra2d.lua +++ /dev/null @@ -1,109 +0,0 @@ --- ============================================== --- Extra2D 引擎库构建目标 --- 支持平台: Nintendo Switch, Windows, Linux, macOS --- ============================================== - --- 核心路径定义 -local SRC_DIR = "Extra2D/src" -local INC_DIR = "Extra2D/include" - --- 定义 Extra2D 引擎库目标 -function define_extra2d_target() - target("extra2d") - set_kind("static") - set_basename(is_mode("debug") and "libeasy2dd" or "libeasy2d") - - -- ============================================== - -- 源文件配置 - -- ============================================== - - -- 引擎源文件 - add_files(path.join(SRC_DIR, "**.cpp")) - add_files(path.join(SRC_DIR, "glad/glad.c")) - - -- Squirrel 3.2 源文件 - add_files("squirrel/squirrel/*.cpp") - add_files("squirrel/sqstdlib/*.cpp") - - -- ============================================== - -- 头文件路径配置 - -- ============================================== - - -- 公开头文件目录 - add_includedirs(INC_DIR, {public = true}) - - -- 第三方头文件目录 - add_includedirs("squirrel/include", {public = true}) - - -- 平台兼容性头文件路径 - add_includedirs(path.join(INC_DIR, "extra2d/platform"), {public = true}) - - -- ============================================== - -- 平台特定配置 - -- ============================================== - - if is_plat("switch") then - -- ============================================== - -- Nintendo Switch 平台配置 - -- ============================================== - set_plat("switch") - set_arch("arm64") - set_toolchains("switch") - - -- devkitPro mesa 路径(EGL + OpenGL ES) - local devkitPro = "C:/devkitPro" - add_includedirs(path.join(devkitPro, "portlibs/switch/include"), {public = true}) - add_linkdirs(path.join(devkitPro, "portlibs/switch/lib")) - - -- 链接 EGL、OpenGL ES 3.0(mesa)和 SDL2 音频 - -- 注意:链接顺序很重要!被依赖的库必须放在后面 - add_syslinks("SDL2_mixer", "SDL2", - "opusfile", "opus", "vorbisidec", "ogg", - "modplug", "mpg123", "FLAC", - "GLESv2", - "EGL", - "glapi", - "drm_nouveau", - {public = true}) - else - -- ============================================== - -- PC 平台配置 (Windows/Linux/macOS) - -- ============================================== - set_toolchains("pc") - - -- PC 平台使用标准 OpenGL (通过 MinGW) - -- 依赖库在 pc.lua 工具链中配置 (使用 vcpkg) - add_syslinks("SDL2_mixer", "SDL2", "opengl32", {public = true}) - end - - -- ============================================== - -- 编译器配置 - -- ============================================== - - -- ============================================== - -- 编译器标志 (MinGW GCC) - -- ============================================== - add_cxflags("-Wall", "-Wextra", {force = true}) - add_cxflags("-Wno-unused-variable", "-Wno-unused-function", {force = true}) - add_cxflags("-Wno-unused-parameter", {force = true}) - - -- Squirrel 第三方库警告抑制 - add_cxflags("-Wno-deprecated-copy", "-Wno-strict-aliasing", "-Wno-implicit-fallthrough", "-Wno-class-memaccess", {force = true}) - - -- 调试/发布模式配置 - if is_mode("debug") then - add_defines("E2D_DEBUG", "_DEBUG", {public = true}) - add_cxxflags("-O0", "-g", {force = true}) - else - add_defines("NDEBUG", {public = true}) - add_cxxflags("-O2", {force = true}) - end - - -- ============================================== - -- 头文件安装配置 - -- ============================================== - add_headerfiles(path.join(INC_DIR, "extra2d/**.h"), {prefixdir = "extra2d"}) - add_headerfiles(path.join(INC_DIR, "stb/**.h"), {prefixdir = "stb"}) - add_headerfiles(path.join(INC_DIR, "simpleini/**.h"), {prefixdir = "simpleini"}) - target_end() -end diff --git a/xmake/toolchains/pc.lua b/xmake/toolchains/pc.lua deleted file mode 100644 index d78a32e..0000000 --- a/xmake/toolchains/pc.lua +++ /dev/null @@ -1,150 +0,0 @@ --- ============================================== --- PC 平台工具链定义 (Windows/Linux/macOS) --- ============================================== - -function define_pc_toolchain() - toolchain("pc") - set_kind("standalone") - set_description("PC Platform Toolchain (Windows/Linux/macOS)") - - on_load(function (toolchain) - -- ============================================== - -- 平台检测与配置 - -- ============================================== - - if is_host("windows") then - -- Windows: 使用 MinGW - toolchain:set("toolset", "cc", "gcc") - toolchain:set("toolset", "cxx", "g++") - toolchain:set("toolset", "ld", "g++") - toolchain:set("toolset", "ar", "ar") - else - -- Linux/macOS: 使用 GCC/Clang - toolchain:set("toolset", "cc", "gcc") - toolchain:set("toolset", "cxx", "g++") - toolchain:set("toolset", "ld", "g++") - toolchain:set("toolset", "ar", "ar") - end - - -- ============================================== - -- PC 平台宏定义 - -- ============================================== - toolchain:add("defines", "__PC__") - - if is_host("windows") then - toolchain:add("defines", "_WIN32", "NOMINMAX", "WIN32_LEAN_AND_MEAN") - elseif is_host("linux") then - toolchain:add("defines", "__linux__") - elseif is_host("macosx") then - toolchain:add("defines", "__APPLE__", "__MACH__") - end - - -- SimpleIni 配置 - toolchain:add("defines", "SI_NO_CONVERSION") - - -- ============================================== - -- OpenGL 配置 - -- ============================================== - - if is_host("windows") then - -- Windows: 使用标准 OpenGL - toolchain:add("links", "opengl32") - else - -- Linux/macOS: 使用 Mesa OpenGL - toolchain:add("links", "GL") - end - - -- ============================================== - -- vcpkg 依赖配置 - -- ============================================== - - -- 获取 vcpkg 路径 - local vcpkg_root = os.getenv("VCPKG_ROOT") - if vcpkg_root then - local triplet = is_arch("x64") and "x64-windows" or "x86-windows" - local vcpkg_installed = path.join(vcpkg_root, "installed", triplet) - if os.isdir(vcpkg_installed) then - -- 添加头文件路径 - toolchain:add("includedirs", path.join(vcpkg_installed, "include")) - toolchain:add("includedirs", path.join(vcpkg_installed, "include", "SDL2")) - -- 添加库路径 - toolchain:add("linkdirs", path.join(vcpkg_installed, "lib")) - print("vcpkg packages: " .. vcpkg_installed) - end - end - - -- ============================================== - -- 链接库 - -- ============================================== - - -- SDL2 及其扩展 - toolchain:add("links", "SDL2_mixer", "SDL2") - - -- 音频编解码库 (vcpkg 中可用的) - toolchain:add("links", "ogg") - - -- OpenGL (Windows 使用标准 OpenGL) - toolchain:add("links", "opengl32") - - -- 系统库 - if is_host("windows") then - toolchain:add("syslinks", "gdi32", "user32", "shell32", "winmm", "imm32", "ole32", "oleaut32", "version", "uuid", "advapi32", "setupapi") - else - toolchain:add("syslinks", "m", "dl", "pthread") - if is_host("linux") then - toolchain:add("syslinks", "X11", "Xext") - end - end - - -- ============================================== - -- 编译器标志 (MinGW GCC) - -- ============================================== - toolchain:add("cxflags", "-Wall", "-Wextra", {force = true}) - toolchain:add("cxflags", "-Wno-unused-parameter", "-Wno-unused-variable", {force = true}) - - -- Windows 控制台应用程序 - toolchain:add("ldflags", "-mconsole", {force = true}) - - if is_mode("debug") then - toolchain:add("defines", "E2D_DEBUG", "_DEBUG") - toolchain:add("cxflags", "-O0", "-g", {force = true}) - else - toolchain:add("defines", "NDEBUG") - toolchain:add("cxflags", "-O2", {force = true}) - end - end) -end - --- 获取 PC 平台包含路径 -function get_pc_includedirs() - local dirs = {} - - -- Angle - local angle_dir = os.getenv("ANGLE_DIR") or "third_party/angle" - if os.isdir(angle_dir) then - table.insert(dirs, path.join(angle_dir, "include")) - end - - return dirs -end - --- 获取 PC 平台库路径 -function get_pc_linkdirs() - local dirs = {} - - -- Angle - local angle_dir = os.getenv("ANGLE_DIR") or "third_party/angle" - if os.isdir(angle_dir) then - table.insert(dirs, path.join(angle_dir, "lib")) - end - - return dirs -end - --- 获取 PC 平台系统链接库 -function get_pc_syslinks() - return { - "SDL2_mixer", "SDL2", - "opengl32" - } -end diff --git a/xmake/toolchains/switch.lua b/xmake/toolchains/switch.lua deleted file mode 100644 index 18333b6..0000000 --- a/xmake/toolchains/switch.lua +++ /dev/null @@ -1,83 +0,0 @@ --- ============================================== --- Nintendo Switch 工具链定义 --- ============================================== - -function define_switch_toolchain() - toolchain("switch") - set_kind("standalone") - set_description("Nintendo Switch devkitA64 toolchain") - - -- 检查 DEVKITPRO 环境变量(Windows 上使用 C:/devkitPro) - local devkitPro = "C:/devkitPro" - local devkitA64 = path.join(devkitPro, "devkitA64") - - -- 设置工具链路径 - set_toolset("cc", path.join(devkitA64, "bin/aarch64-none-elf-gcc.exe")) - set_toolset("cxx", path.join(devkitA64, "bin/aarch64-none-elf-g++.exe")) - set_toolset("ld", path.join(devkitA64, "bin/aarch64-none-elf-g++.exe")) - set_toolset("ar", path.join(devkitA64, "bin/aarch64-none-elf-gcc-ar.exe")) - set_toolset("strip", path.join(devkitA64, "bin/aarch64-none-elf-strip.exe")) - - -- 架构标志 - local arch_flags = "-march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE" - add_cxflags(arch_flags) - -- 使用 devkitPro 提供的 switch.specs 文件 - add_ldflags("-specs=" .. path.join(devkitPro, "libnx/switch.specs"), "-g", arch_flags) - - -- 定义 Switch 平台宏 - add_defines("__SWITCH__", "__NX__", "MA_SWITCH", "PFD_SWITCH") - - -- SimpleIni 配置:不使用 Windows API - add_defines("SI_NO_CONVERSION") - - -- libnx 路径 - 必须在工具链级别添加 - add_includedirs(path.join(devkitPro, "libnx/include")) - add_linkdirs(path.join(devkitPro, "libnx/lib")) - - -- portlibs 路径(EGL + 桌面 OpenGL + SDL2) - add_includedirs(path.join(devkitPro, "portlibs/switch/include")) - add_includedirs(path.join(devkitPro, "portlibs/switch/include/SDL2")) - add_linkdirs(path.join(devkitPro, "portlibs/switch/lib")) - - add_syslinks("nx", "m") -end - --- 获取 devkitPro 路径 -function get_devkitpro_path() - return "C:/devkitPro" -end - --- 获取 Switch 平台包含路径 -function get_switch_includedirs() - local devkitPro = get_devkitpro_path() - return { - path.join(devkitPro, "libnx/include"), - path.join(devkitPro, "portlibs/switch/include"), - path.join(devkitPro, "portlibs/switch/include/SDL2") - } -end - --- 获取 Switch 平台库路径 -function get_switch_linkdirs() - local devkitPro = get_devkitpro_path() - return { - path.join(devkitPro, "libnx/lib"), - path.join(devkitPro, "portlibs/switch/lib") - } -end - --- 获取 Switch 平台系统链接库 -function get_switch_syslinks() - -- 注意:链接顺序很重要!被依赖的库必须放在后面 - -- 依赖链:SDL2 -> EGL -> drm_nouveau - -- GLESv2 -> glapi -> drm_nouveau - return { - "SDL2_mixer", "SDL2", - "opusfile", "opus", "vorbisidec", "ogg", - "modplug", "mpg123", "FLAC", - "GLESv2", - "EGL", - "glapi", - "drm_nouveau" - } -end