feat(scene): 添加多种场景过渡效果实现
实现缩放、方块、滑动、翻页和淡入淡出五种场景过渡效果 新增 TransitionScene 基类作为过渡场景的公共父类 扩展 SceneManager 支持带过渡效果的场景切换操作
This commit is contained in:
parent
b55d279611
commit
6273f3235d
|
|
@ -12,6 +12,8 @@
|
|||
namespace extra2d {
|
||||
|
||||
struct RenderCommand;
|
||||
class TransitionScene;
|
||||
enum class TransitionType;
|
||||
|
||||
/**
|
||||
* @brief 场景管理器 - 管理场景的生命周期和切换
|
||||
|
|
@ -22,6 +24,9 @@ public:
|
|||
|
||||
static SceneManager &get();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 基本场景操作(无过渡效果)
|
||||
// ------------------------------------------------------------------------
|
||||
void runWithScene(Ptr<Scene> scene);
|
||||
void replaceScene(Ptr<Scene> scene);
|
||||
void pushScene(Ptr<Scene> scene);
|
||||
|
|
@ -29,6 +34,61 @@ public:
|
|||
void popToRootScene();
|
||||
void popToScene(const std::string &name);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 带过渡效果的场景操作
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief 替换当前场景(带过渡效果)
|
||||
* @param scene 新场景
|
||||
* @param transition 过渡类型
|
||||
* @param duration 过渡持续时间(秒)
|
||||
*/
|
||||
void replaceScene(Ptr<Scene> scene, TransitionType transition,
|
||||
float duration = 0.5f);
|
||||
|
||||
/**
|
||||
* @brief 压入新场景(带过渡效果)
|
||||
* @param scene 新场景
|
||||
* @param transition 过渡类型
|
||||
* @param duration 过渡持续时间(秒)
|
||||
*/
|
||||
void pushScene(Ptr<Scene> scene, TransitionType transition,
|
||||
float duration = 0.5f);
|
||||
|
||||
/**
|
||||
* @brief 弹出当前场景(带过渡效果)
|
||||
* @param transition 过渡类型
|
||||
* @param duration 过渡持续时间(秒)
|
||||
*/
|
||||
void popScene(TransitionType transition, float duration = 0.5f);
|
||||
|
||||
/**
|
||||
* @brief 弹出到根场景(带过渡效果)
|
||||
* @param transition 过渡类型
|
||||
* @param duration 过渡持续时间(秒)
|
||||
*/
|
||||
void popToRootScene(TransitionType transition, float duration = 0.5f);
|
||||
|
||||
/**
|
||||
* @brief 弹出到指定场景(带过渡效果)
|
||||
* @param name 目标场景名称
|
||||
* @param transition 过渡类型
|
||||
* @param duration 过渡持续时间(秒)
|
||||
*/
|
||||
void popToScene(const std::string &name, TransitionType transition,
|
||||
float duration = 0.5f);
|
||||
|
||||
/**
|
||||
* @brief 使用自定义过渡场景进入场景
|
||||
* @param scene 新场景
|
||||
* @param transitionScene 过渡场景
|
||||
*/
|
||||
void enterScene(Ptr<Scene> scene, Ptr<TransitionScene> transitionScene);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 场景查询
|
||||
// ------------------------------------------------------------------------
|
||||
Ptr<Scene> getCurrentScene() const;
|
||||
Ptr<Scene> getPreviousScene() const;
|
||||
Ptr<Scene> getRootScene() const;
|
||||
|
|
@ -38,10 +98,16 @@ public:
|
|||
bool isEmpty() const { return sceneStack_.empty(); }
|
||||
bool hasScene(const std::string &name) const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 更新和渲染
|
||||
// ------------------------------------------------------------------------
|
||||
void update(float dt);
|
||||
void render(RenderBackend &renderer);
|
||||
void collectRenderCommands(std::vector<RenderCommand> &commands);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 过渡状态
|
||||
// ------------------------------------------------------------------------
|
||||
bool isTransitioning() const { return isTransitioning_; }
|
||||
void setTransitionCallback(TransitionCallback callback) {
|
||||
transitionCallback_ = callback;
|
||||
|
|
@ -59,6 +125,32 @@ public:
|
|||
void enterScene(Ptr<Scene> scene);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 启动过渡
|
||||
* @param from 源场景
|
||||
* @param to 目标场景
|
||||
* @param type 过渡类型
|
||||
* @param duration 过渡持续时间
|
||||
* @param stackAction 过渡完成后的栈操作
|
||||
*/
|
||||
void startTransition(Ptr<Scene> from, Ptr<Scene> to, TransitionType type,
|
||||
float duration, std::function<void()> stackAction);
|
||||
|
||||
/**
|
||||
* @brief 创建过渡场景
|
||||
* @param type 过渡类型
|
||||
* @param duration 过渡持续时间
|
||||
* @param inScene 目标场景
|
||||
* @return 过渡场景智能指针
|
||||
*/
|
||||
Ptr<TransitionScene> createTransitionScene(TransitionType type, float duration,
|
||||
Ptr<Scene> inScene);
|
||||
|
||||
/**
|
||||
* @brief 完成过渡
|
||||
*/
|
||||
void finishTransition();
|
||||
|
||||
void doSceneSwitch();
|
||||
void dispatchPointerEvents(Scene &scene);
|
||||
|
||||
|
|
@ -71,6 +163,9 @@ private:
|
|||
Ptr<Scene> nextScene_;
|
||||
bool sendCleanupToScene_ = false;
|
||||
|
||||
Ptr<TransitionScene> activeTransitionScene_;
|
||||
std::function<void()> transitionStackAction_;
|
||||
|
||||
Node *hoverTarget_ = nullptr;
|
||||
Node *captureTarget_ = nullptr;
|
||||
Vec2 lastPointerWorld_ = Vec2::Zero();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/scene/transition_scene.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 方块/马赛克过渡场景
|
||||
// 实现原理:
|
||||
// 1. 将屏幕分成多个方块
|
||||
// 2. 方块逐个消失,显示新场景
|
||||
// ============================================================================
|
||||
class TransitionBoxScene : public TransitionScene {
|
||||
public:
|
||||
/**
|
||||
* @brief 创建方块过渡场景
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
* @param divisions 方块分割数(默认为 8,表示 8x8 网格)
|
||||
*/
|
||||
TransitionBoxScene(float duration, Ptr<Scene> inScene, int divisions = 8);
|
||||
|
||||
static Ptr<TransitionBoxScene> create(float duration, Ptr<Scene> inScene,
|
||||
int divisions = 8);
|
||||
|
||||
protected:
|
||||
void onTransitionStart() override;
|
||||
void renderContent(RenderBackend &renderer) override;
|
||||
|
||||
private:
|
||||
int divisions_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/scene/transition_scene.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 淡入淡出过渡场景
|
||||
// 实现原理:
|
||||
// 1. 创建一个纯色精灵作为遮罩层
|
||||
// 2. 第一阶段:遮罩从透明淡入到不透明(黑屏),同时显示旧场景
|
||||
// 3. 切换显示新场景
|
||||
// 4. 第二阶段:遮罩从不透明淡出到透明,显示新场景
|
||||
// ============================================================================
|
||||
class TransitionFadeScene : public TransitionScene {
|
||||
public:
|
||||
/**
|
||||
* @brief 创建淡入淡出过渡场景
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
* @param color 遮罩颜色(默认为黑色)
|
||||
*/
|
||||
TransitionFadeScene(float duration, Ptr<Scene> inScene,
|
||||
const Color &color = Colors::Black);
|
||||
|
||||
static Ptr<TransitionFadeScene> create(float duration, Ptr<Scene> inScene,
|
||||
const Color &color = Colors::Black);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief 启动过渡动画
|
||||
* 创建遮罩层并运行动作序列
|
||||
*/
|
||||
void onTransitionStart() override;
|
||||
|
||||
/**
|
||||
* @brief 渲染内容
|
||||
* 根据进度控制新旧场景的显示
|
||||
*/
|
||||
void renderContent(RenderBackend &renderer) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 隐藏退出场景,显示进入场景
|
||||
*/
|
||||
void hideOutShowIn();
|
||||
|
||||
Color maskColor_; // 遮罩颜色
|
||||
bool hasSwitched_ = false; // 是否已经切换场景
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/scene/transition_scene.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 翻页过渡场景
|
||||
// 实现原理:
|
||||
// 1. 前半段:旧场景翻转消失
|
||||
// 2. 后半段:新场景翻转出现
|
||||
// ============================================================================
|
||||
class TransitionFlipScene : public TransitionScene {
|
||||
public:
|
||||
enum class Axis { Horizontal, Vertical };
|
||||
|
||||
/**
|
||||
* @brief 创建翻页过渡场景
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
* @param axis 翻转轴(水平或垂直)
|
||||
*/
|
||||
TransitionFlipScene(float duration, Ptr<Scene> inScene,
|
||||
Axis axis = Axis::Horizontal);
|
||||
|
||||
static Ptr<TransitionFlipScene> create(float duration, Ptr<Scene> inScene,
|
||||
Axis axis = Axis::Horizontal);
|
||||
|
||||
protected:
|
||||
void onTransitionStart() override;
|
||||
void renderContent(RenderBackend &renderer) override;
|
||||
|
||||
private:
|
||||
Axis axis_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/scene/transition_scene.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 缩放过渡场景
|
||||
// 实现原理:
|
||||
// 1. 旧场景缩小消失
|
||||
// 2. 新场景放大出现
|
||||
// ============================================================================
|
||||
class TransitionScaleScene : public TransitionScene {
|
||||
public:
|
||||
/**
|
||||
* @brief 创建缩放过渡场景
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
*/
|
||||
TransitionScaleScene(float duration, Ptr<Scene> inScene);
|
||||
|
||||
static Ptr<TransitionScaleScene> create(float duration, Ptr<Scene> inScene);
|
||||
|
||||
protected:
|
||||
void onTransitionStart() override;
|
||||
void renderContent(RenderBackend &renderer) override;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/scene/scene.h>
|
||||
#include <functional>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 过渡方向
|
||||
// ============================================================================
|
||||
enum class TransitionDirection { Left, Right, Up, Down };
|
||||
|
||||
// ============================================================================
|
||||
// 过渡效果类型
|
||||
// ============================================================================
|
||||
enum class TransitionType {
|
||||
None,
|
||||
Fade,
|
||||
SlideLeft,
|
||||
SlideRight,
|
||||
SlideUp,
|
||||
SlideDown,
|
||||
Scale,
|
||||
Flip,
|
||||
Box
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 过渡场景基类 - 继承自 Scene,作为中介场景管理过渡效果
|
||||
// 设计参考 Cocos2d-x 的 TransitionScene
|
||||
// ============================================================================
|
||||
class TransitionScene : public Scene {
|
||||
public:
|
||||
using FinishCallback = std::function<void()>;
|
||||
|
||||
/**
|
||||
* @brief 创建过渡场景
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
*/
|
||||
TransitionScene(float duration, Ptr<Scene> inScene);
|
||||
~TransitionScene() override = default;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 场景管理
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief 获取要进入的场景
|
||||
*/
|
||||
Ptr<Scene> getInScene() const { return inScene_; }
|
||||
|
||||
/**
|
||||
* @brief 获取要退出的场景
|
||||
*/
|
||||
Ptr<Scene> getOutScene() const { return outScene_; }
|
||||
|
||||
/**
|
||||
* @brief 设置要退出的场景(由 SceneManager 调用)
|
||||
*/
|
||||
void setOutScene(Ptr<Scene> outScene) { outScene_ = outScene; }
|
||||
|
||||
/**
|
||||
* @brief 设置过渡完成回调
|
||||
*/
|
||||
void setFinishCallback(FinishCallback callback) { finishCallback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 获取过渡持续时间
|
||||
*/
|
||||
float getDuration() const { return duration_; }
|
||||
|
||||
/**
|
||||
* @brief 获取当前进度 [0, 1]
|
||||
*/
|
||||
float getProgress() const { return progress_; }
|
||||
|
||||
/**
|
||||
* @brief 是否已完成
|
||||
*/
|
||||
bool isFinished() const { return isFinished_; }
|
||||
|
||||
/**
|
||||
* @brief 完成过渡,通知 SceneManager 切换到目标场景
|
||||
*/
|
||||
void finish();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 渲染 - 在 TransitionScene 上渲染新旧两个子场景
|
||||
// ------------------------------------------------------------------------
|
||||
void renderContent(RenderBackend &renderer) override;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 生命周期
|
||||
// ------------------------------------------------------------------------
|
||||
void onEnter() override;
|
||||
void onExit() override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief 子类实现具体的过渡逻辑
|
||||
* 在 onEnter 中设置动画,动画完成后调用 finish()
|
||||
*/
|
||||
virtual void onTransitionStart() = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制源场景(旧场景)
|
||||
*/
|
||||
virtual void drawOutScene(RenderBackend &renderer);
|
||||
|
||||
/**
|
||||
* @brief 绘制目标场景(新场景)
|
||||
*/
|
||||
virtual void drawInScene(RenderBackend &renderer);
|
||||
|
||||
float duration_;
|
||||
float elapsed_ = 0.0f;
|
||||
float progress_ = 0.0f;
|
||||
bool isFinished_ = false;
|
||||
|
||||
Ptr<Scene> inScene_; // 要进入的场景
|
||||
Ptr<Scene> outScene_; // 要退出的场景
|
||||
|
||||
FinishCallback finishCallback_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/scene/transition_scene.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 滑动过渡场景
|
||||
// 实现原理:
|
||||
// 1. 旧场景向指定方向滑出
|
||||
// 2. 新场景从相反方向滑入
|
||||
// ============================================================================
|
||||
class TransitionSlideScene : public TransitionScene {
|
||||
public:
|
||||
/**
|
||||
* @brief 创建滑动过渡场景
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
* @param direction 滑动方向
|
||||
*/
|
||||
TransitionSlideScene(float duration, Ptr<Scene> inScene,
|
||||
TransitionDirection direction);
|
||||
|
||||
static Ptr<TransitionSlideScene> create(float duration, Ptr<Scene> inScene,
|
||||
TransitionDirection direction);
|
||||
|
||||
protected:
|
||||
void onTransitionStart() override;
|
||||
void renderContent(RenderBackend &renderer) override;
|
||||
|
||||
private:
|
||||
TransitionDirection direction_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -4,6 +4,12 @@
|
|||
#include <extra2d/graphics/render_command.h>
|
||||
#include <extra2d/platform/iinput.h>
|
||||
#include <extra2d/scene/scene_manager.h>
|
||||
#include <extra2d/scene/transition_box_scene.h>
|
||||
#include <extra2d/scene/transition_fade_scene.h>
|
||||
#include <extra2d/scene/transition_flip_scene.h>
|
||||
#include <extra2d/scene/transition_scale_scene.h>
|
||||
#include <extra2d/scene/transition_scene.h>
|
||||
#include <extra2d/scene/transition_slide_scene.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
|
@ -115,6 +121,48 @@ void SceneManager::replaceScene(Ptr<Scene> scene) {
|
|||
sceneStack_.push(scene);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 替换当前场景(带过渡效果)
|
||||
* @param scene 新场景
|
||||
* @param transition 过渡类型
|
||||
* @param duration 过渡持续时间
|
||||
*/
|
||||
void SceneManager::replaceScene(Ptr<Scene> scene, TransitionType transition,
|
||||
float duration) {
|
||||
if (!scene || isTransitioning_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sceneStack_.empty()) {
|
||||
runWithScene(scene);
|
||||
return;
|
||||
}
|
||||
|
||||
auto oldScene = sceneStack_.top();
|
||||
|
||||
startTransition(oldScene, scene, transition, duration, [this]() {
|
||||
if (!sceneStack_.empty() && activeTransitionScene_) {
|
||||
if (sceneStack_.top().get() == activeTransitionScene_.get()) {
|
||||
sceneStack_.pop();
|
||||
}
|
||||
|
||||
auto outScene = activeTransitionScene_->getOutScene();
|
||||
if (outScene) {
|
||||
outScene->onExit();
|
||||
outScene->onDetachFromScene();
|
||||
}
|
||||
}
|
||||
|
||||
if (activeTransitionScene_) {
|
||||
auto inScene = activeTransitionScene_->getInScene();
|
||||
if (inScene) {
|
||||
inScene->onAttachToScene(inScene.get());
|
||||
sceneStack_.push(inScene);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 进入场景
|
||||
* @param scene 要进入的场景智能指针
|
||||
|
|
@ -133,6 +181,67 @@ void SceneManager::enterScene(Ptr<Scene> scene) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 使用自定义过渡场景进入场景
|
||||
* @param scene 新场景
|
||||
* @param transitionScene 过渡场景
|
||||
*/
|
||||
void SceneManager::enterScene(Ptr<Scene> scene,
|
||||
Ptr<TransitionScene> transitionScene) {
|
||||
if (!scene || isTransitioning_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!transitionScene) {
|
||||
enterScene(scene);
|
||||
return;
|
||||
}
|
||||
|
||||
auto current = getCurrentScene();
|
||||
if (!current) {
|
||||
enterScene(scene);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hoverTarget_) {
|
||||
Event evt;
|
||||
evt.type = EventType::UIHoverExit;
|
||||
evt.data = CustomEvent{0, hoverTarget_};
|
||||
dispatchToNode(hoverTarget_, evt);
|
||||
hoverTarget_ = nullptr;
|
||||
}
|
||||
captureTarget_ = nullptr;
|
||||
hasLastPointerWorld_ = false;
|
||||
|
||||
transitionScene->setOutScene(current);
|
||||
transitionScene->setFinishCallback([this]() { finishTransition(); });
|
||||
|
||||
current->pause();
|
||||
|
||||
transitionScene->onEnter();
|
||||
transitionScene->onAttachToScene(transitionScene.get());
|
||||
sceneStack_.push(transitionScene);
|
||||
|
||||
isTransitioning_ = true;
|
||||
activeTransitionScene_ = transitionScene;
|
||||
transitionStackAction_ = [this, transitionScene]() {
|
||||
auto outScene = transitionScene->getOutScene();
|
||||
if (!sceneStack_.empty() && outScene) {
|
||||
if (sceneStack_.top().get() == transitionScene.get()) {
|
||||
sceneStack_.pop();
|
||||
}
|
||||
outScene->onExit();
|
||||
outScene->onDetachFromScene();
|
||||
}
|
||||
|
||||
auto inScene = transitionScene->getInScene();
|
||||
if (inScene) {
|
||||
inScene->onAttachToScene(inScene.get());
|
||||
sceneStack_.push(inScene);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 压入场景到栈顶
|
||||
* @param scene 要压入的场景智能指针
|
||||
|
|
@ -153,6 +262,44 @@ void SceneManager::pushScene(Ptr<Scene> scene) {
|
|||
sceneStack_.push(scene);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 压入场景到栈顶(带过渡效果)
|
||||
* @param scene 新场景
|
||||
* @param transition 过渡类型
|
||||
* @param duration 过渡持续时间
|
||||
*/
|
||||
void SceneManager::pushScene(Ptr<Scene> scene, TransitionType transition,
|
||||
float duration) {
|
||||
if (!scene || isTransitioning_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sceneStack_.empty()) {
|
||||
runWithScene(scene);
|
||||
return;
|
||||
}
|
||||
|
||||
sceneStack_.top()->pause();
|
||||
|
||||
auto currentScene = sceneStack_.top();
|
||||
|
||||
startTransition(currentScene, scene, transition, duration, [this]() {
|
||||
if (!sceneStack_.empty() && activeTransitionScene_) {
|
||||
if (sceneStack_.top().get() == activeTransitionScene_.get()) {
|
||||
sceneStack_.pop();
|
||||
}
|
||||
}
|
||||
|
||||
if (activeTransitionScene_) {
|
||||
auto inScene = activeTransitionScene_->getInScene();
|
||||
if (inScene) {
|
||||
inScene->onAttachToScene(inScene.get());
|
||||
sceneStack_.push(inScene);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 弹出当前场景
|
||||
*
|
||||
|
|
@ -173,6 +320,41 @@ void SceneManager::popScene() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 弹出当前场景(带过渡效果)
|
||||
* @param transition 过渡类型
|
||||
* @param duration 过渡持续时间
|
||||
*/
|
||||
void SceneManager::popScene(TransitionType transition, float duration) {
|
||||
if (sceneStack_.size() <= 1 || isTransitioning_) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto current = sceneStack_.top();
|
||||
auto previous = getPreviousScene();
|
||||
|
||||
startTransition(current, previous, transition, duration, [this]() {
|
||||
if (!sceneStack_.empty() && activeTransitionScene_) {
|
||||
if (sceneStack_.top().get() == activeTransitionScene_.get()) {
|
||||
sceneStack_.pop();
|
||||
}
|
||||
|
||||
auto outScene = activeTransitionScene_->getOutScene();
|
||||
if (outScene) {
|
||||
outScene->onExit();
|
||||
outScene->onDetachFromScene();
|
||||
}
|
||||
}
|
||||
|
||||
if (activeTransitionScene_) {
|
||||
auto inScene = activeTransitionScene_->getInScene();
|
||||
if (inScene && !sceneStack_.empty() && sceneStack_.top() == inScene) {
|
||||
inScene->resume();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 弹出到根场景
|
||||
*
|
||||
|
|
@ -193,6 +375,33 @@ void SceneManager::popToRootScene() {
|
|||
sceneStack_.top()->resume();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 弹出到根场景(带过渡效果)
|
||||
* @param transition 过渡类型
|
||||
* @param duration 过渡持续时间
|
||||
*/
|
||||
void SceneManager::popToRootScene(TransitionType transition, float duration) {
|
||||
if (sceneStack_.size() <= 1 || isTransitioning_) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto root = getRootScene();
|
||||
auto current = sceneStack_.top();
|
||||
|
||||
startTransition(current, root, transition, duration, [this, root]() {
|
||||
while (!sceneStack_.empty() && sceneStack_.top().get() != root.get()) {
|
||||
auto scene = sceneStack_.top();
|
||||
scene->onExit();
|
||||
scene->onDetachFromScene();
|
||||
sceneStack_.pop();
|
||||
}
|
||||
|
||||
if (!sceneStack_.empty() && sceneStack_.top().get() == root.get()) {
|
||||
root->resume();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 弹出到指定名称的场景
|
||||
* @param name 目标场景的名称
|
||||
|
|
@ -223,6 +432,37 @@ void SceneManager::popToScene(const std::string &name) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 弹出到指定名称的场景(带过渡效果)
|
||||
* @param name 目标场景名称
|
||||
* @param transition 过渡类型
|
||||
* @param duration 过渡持续时间
|
||||
*/
|
||||
void SceneManager::popToScene(const std::string &name,
|
||||
TransitionType transition, float duration) {
|
||||
if (isTransitioning_) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto target = getSceneByName(name);
|
||||
if (target && target != sceneStack_.top()) {
|
||||
auto current = sceneStack_.top();
|
||||
|
||||
startTransition(current, target, transition, duration, [this, target]() {
|
||||
while (!sceneStack_.empty() && sceneStack_.top() != target) {
|
||||
auto scene = sceneStack_.top();
|
||||
scene->onExit();
|
||||
scene->onDetachFromScene();
|
||||
sceneStack_.pop();
|
||||
}
|
||||
|
||||
if (!sceneStack_.empty() && sceneStack_.top() == target) {
|
||||
target->resume();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取当前场景
|
||||
* @return 当前栈顶场景的智能指针,栈为空时返回nullptr
|
||||
|
|
@ -381,6 +621,124 @@ void SceneManager::end() {
|
|||
*/
|
||||
void SceneManager::purgeCachedScenes() { namedScenes_.clear(); }
|
||||
|
||||
/**
|
||||
* @brief 启动过渡
|
||||
* @param from 源场景
|
||||
* @param to 目标场景
|
||||
* @param type 过渡类型
|
||||
* @param duration 过渡持续时间
|
||||
* @param stackAction 过渡完成后的栈操作
|
||||
*/
|
||||
void SceneManager::startTransition(Ptr<Scene> from, Ptr<Scene> to,
|
||||
TransitionType type, float duration,
|
||||
std::function<void()> stackAction) {
|
||||
if (!from || !to) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto transitionScene = createTransitionScene(type, duration, to);
|
||||
if (!transitionScene) {
|
||||
replaceScene(to);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hoverTarget_) {
|
||||
Event evt;
|
||||
evt.type = EventType::UIHoverExit;
|
||||
evt.data = CustomEvent{0, hoverTarget_};
|
||||
dispatchToNode(hoverTarget_, evt);
|
||||
hoverTarget_ = nullptr;
|
||||
}
|
||||
captureTarget_ = nullptr;
|
||||
hasLastPointerWorld_ = false;
|
||||
|
||||
transitionScene->setOutScene(from);
|
||||
transitionScene->setFinishCallback([this]() { finishTransition(); });
|
||||
|
||||
from->pause();
|
||||
|
||||
transitionScene->onEnter();
|
||||
transitionScene->onAttachToScene(transitionScene.get());
|
||||
sceneStack_.push(transitionScene);
|
||||
|
||||
isTransitioning_ = true;
|
||||
activeTransitionScene_ = transitionScene;
|
||||
transitionStackAction_ = std::move(stackAction);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建过渡场景
|
||||
* @param type 过渡类型
|
||||
* @param duration 过渡持续时间
|
||||
* @param inScene 目标场景
|
||||
* @return 过渡场景智能指针
|
||||
*/
|
||||
Ptr<TransitionScene> SceneManager::createTransitionScene(TransitionType type,
|
||||
float duration,
|
||||
Ptr<Scene> inScene) {
|
||||
if (!inScene) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case TransitionType::Fade:
|
||||
return TransitionFadeScene::create(duration, inScene);
|
||||
case TransitionType::SlideLeft:
|
||||
return TransitionSlideScene::create(duration, inScene,
|
||||
TransitionDirection::Left);
|
||||
case TransitionType::SlideRight:
|
||||
return TransitionSlideScene::create(duration, inScene,
|
||||
TransitionDirection::Right);
|
||||
case TransitionType::SlideUp:
|
||||
return TransitionSlideScene::create(duration, inScene,
|
||||
TransitionDirection::Up);
|
||||
case TransitionType::SlideDown:
|
||||
return TransitionSlideScene::create(duration, inScene,
|
||||
TransitionDirection::Down);
|
||||
case TransitionType::Scale:
|
||||
return TransitionScaleScene::create(duration, inScene);
|
||||
case TransitionType::Flip:
|
||||
return TransitionFlipScene::create(duration, inScene);
|
||||
case TransitionType::Box:
|
||||
return TransitionBoxScene::create(duration, inScene);
|
||||
default:
|
||||
return TransitionFadeScene::create(duration, inScene);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 完成过渡
|
||||
*
|
||||
* 执行栈操作并清理过渡状态
|
||||
*/
|
||||
void SceneManager::finishTransition() {
|
||||
Node *lastHoverTarget = hoverTarget_;
|
||||
|
||||
isTransitioning_ = false;
|
||||
hoverTarget_ = nullptr;
|
||||
captureTarget_ = nullptr;
|
||||
hasLastPointerWorld_ = false;
|
||||
|
||||
if (transitionStackAction_) {
|
||||
transitionStackAction_();
|
||||
}
|
||||
|
||||
if (lastHoverTarget) {
|
||||
Event evt;
|
||||
evt.type = EventType::UIHoverExit;
|
||||
evt.data = CustomEvent{0, lastHoverTarget};
|
||||
dispatchToNode(lastHoverTarget, evt);
|
||||
}
|
||||
|
||||
activeTransitionScene_.reset();
|
||||
transitionStackAction_ = nullptr;
|
||||
|
||||
if (transitionCallback_) {
|
||||
transitionCallback_();
|
||||
transitionCallback_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 分发指针事件
|
||||
* @param scene 目标场景
|
||||
|
|
@ -472,4 +830,7 @@ void SceneManager::dispatchPointerEvents(Scene &scene) {
|
|||
lastPointerWorld_ = worldPos;
|
||||
}
|
||||
|
||||
void SceneManager::doSceneSwitch() {
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
#include <extra2d/scene/transition_box_scene.h>
|
||||
#include <extra2d/app/application.h>
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/graphics/render_backend.h>
|
||||
#include <algorithm>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 构造函数,初始化方块过渡场景
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
* @param divisions 方块分割数
|
||||
*/
|
||||
TransitionBoxScene::TransitionBoxScene(float duration, Ptr<Scene> inScene,
|
||||
int divisions)
|
||||
: TransitionScene(duration, inScene), divisions_(divisions) {}
|
||||
|
||||
/**
|
||||
* @brief 创建方块过渡场景的静态工厂方法
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
* @param divisions 方块分割数
|
||||
* @return 过渡场景智能指针
|
||||
*/
|
||||
Ptr<TransitionBoxScene> TransitionBoxScene::create(float duration,
|
||||
Ptr<Scene> inScene,
|
||||
int divisions) {
|
||||
return makePtr<TransitionBoxScene>(duration, inScene, divisions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 启动过渡动画
|
||||
*
|
||||
* 方块过渡不需要特殊的初始化
|
||||
*/
|
||||
void TransitionBoxScene::onTransitionStart() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 渲染过渡内容
|
||||
* @param renderer 渲染后端引用
|
||||
*
|
||||
* 先渲染新场景,然后绘制方块遮罩逐渐消失
|
||||
*/
|
||||
void TransitionBoxScene::renderContent(RenderBackend &renderer) {
|
||||
auto &app = Application::get();
|
||||
float windowWidth = static_cast<float>(app.window().width());
|
||||
float windowHeight = static_cast<float>(app.window().height());
|
||||
|
||||
elapsed_ += 1.0f / 60.0f;
|
||||
progress_ = duration_ > 0.0f ? std::min(1.0f, elapsed_ / duration_) : 1.0f;
|
||||
|
||||
if (inScene_) {
|
||||
inScene_->renderContent(renderer);
|
||||
} else if (outScene_) {
|
||||
outScene_->renderContent(renderer);
|
||||
}
|
||||
|
||||
renderer.setViewport(0, 0, static_cast<int>(windowWidth),
|
||||
static_cast<int>(windowHeight));
|
||||
|
||||
int div = std::max(1, divisions_);
|
||||
int total = div * div;
|
||||
int visible = std::clamp(static_cast<int>(total * progress_), 0, total);
|
||||
|
||||
float cellW = windowWidth / static_cast<float>(div);
|
||||
float cellH = windowHeight / static_cast<float>(div);
|
||||
|
||||
glm::mat4 overlayVP =
|
||||
glm::ortho(0.0f, windowWidth, windowHeight, 0.0f, -1.0f, 1.0f);
|
||||
renderer.setViewProjection(overlayVP);
|
||||
|
||||
for (int idx = visible; idx < total; ++idx) {
|
||||
int x = idx % div;
|
||||
int y = idx / div;
|
||||
renderer.fillRect(Rect(x * cellW, y * cellH, cellW + 1.0f, cellH + 1.0f),
|
||||
Colors::Black);
|
||||
}
|
||||
|
||||
if (progress_ >= 1.0f && !isFinished_) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
#include <extra2d/scene/transition_fade_scene.h>
|
||||
#include <extra2d/app/application.h>
|
||||
#include <extra2d/graphics/render_backend.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <algorithm>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 构造函数,初始化淡入淡出过渡场景
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
* @param color 遮罩颜色
|
||||
*/
|
||||
TransitionFadeScene::TransitionFadeScene(float duration, Ptr<Scene> inScene,
|
||||
const Color &color)
|
||||
: TransitionScene(duration, inScene), maskColor_(color) {}
|
||||
|
||||
/**
|
||||
* @brief 创建淡入淡出过渡场景的静态工厂方法
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
* @param color 遮罩颜色
|
||||
* @return 过渡场景智能指针
|
||||
*/
|
||||
Ptr<TransitionFadeScene> TransitionFadeScene::create(float duration,
|
||||
Ptr<Scene> inScene,
|
||||
const Color &color) {
|
||||
return makePtr<TransitionFadeScene>(duration, inScene, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 启动过渡动画
|
||||
*
|
||||
* 使用定时器来更新进度,实际进度更新由 SceneManager 的 update 驱动
|
||||
*/
|
||||
void TransitionFadeScene::onTransitionStart() {
|
||||
E2D_LOG_DEBUG("TransitionFadeScene::onTransitionStart - 启动淡入淡出过渡");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 渲染过渡内容
|
||||
* @param renderer 渲染后端引用
|
||||
*
|
||||
* 根据进度渲染新旧场景,并绘制遮罩层
|
||||
*/
|
||||
void TransitionFadeScene::renderContent(RenderBackend &renderer) {
|
||||
auto &app = Application::get();
|
||||
float windowWidth = static_cast<float>(app.window().width());
|
||||
float windowHeight = static_cast<float>(app.window().height());
|
||||
|
||||
elapsed_ += 1.0f / 60.0f;
|
||||
progress_ = duration_ > 0.0f ? std::min(1.0f, elapsed_ / duration_) : 1.0f;
|
||||
|
||||
if (!hasSwitched_ && progress_ >= 0.5f) {
|
||||
hideOutShowIn();
|
||||
}
|
||||
|
||||
if (progress_ < 0.5f) {
|
||||
drawOutScene(renderer);
|
||||
} else {
|
||||
drawInScene(renderer);
|
||||
}
|
||||
|
||||
float maskAlpha;
|
||||
if (progress_ < 0.5f) {
|
||||
maskAlpha = progress_ * 2.0f;
|
||||
} else {
|
||||
maskAlpha = (1.0f - progress_) * 2.0f;
|
||||
}
|
||||
|
||||
renderer.setViewport(0, 0, static_cast<int>(windowWidth),
|
||||
static_cast<int>(windowHeight));
|
||||
|
||||
glm::mat4 overlayVP =
|
||||
glm::ortho(0.0f, windowWidth, windowHeight, 0.0f, -1.0f, 1.0f);
|
||||
renderer.setViewProjection(overlayVP);
|
||||
|
||||
Color maskColor = maskColor_;
|
||||
maskColor.a = maskAlpha;
|
||||
renderer.fillRect(Rect(0.0f, 0.0f, windowWidth, windowHeight), maskColor);
|
||||
|
||||
if (progress_ >= 1.0f && !isFinished_) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 切换场景显示
|
||||
*
|
||||
* 标记已切换场景
|
||||
*/
|
||||
void TransitionFadeScene::hideOutShowIn() {
|
||||
hasSwitched_ = true;
|
||||
E2D_LOG_DEBUG("TransitionFadeScene::hideOutShowIn - 切换场景显示");
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
#include <extra2d/scene/transition_flip_scene.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/graphics/camera.h>
|
||||
#include <extra2d/graphics/render_backend.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 构造函数,初始化翻页过渡场景
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
* @param axis 翻转轴
|
||||
*/
|
||||
TransitionFlipScene::TransitionFlipScene(float duration, Ptr<Scene> inScene,
|
||||
Axis axis)
|
||||
: TransitionScene(duration, inScene), axis_(axis) {}
|
||||
|
||||
/**
|
||||
* @brief 创建翻页过渡场景的静态工厂方法
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
* @param axis 翻转轴
|
||||
* @return 过渡场景智能指针
|
||||
*/
|
||||
Ptr<TransitionFlipScene> TransitionFlipScene::create(float duration,
|
||||
Ptr<Scene> inScene,
|
||||
Axis axis) {
|
||||
return makePtr<TransitionFlipScene>(duration, inScene, axis);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 启动过渡动画
|
||||
*
|
||||
* 翻页过渡不需要特殊的初始化
|
||||
*/
|
||||
void TransitionFlipScene::onTransitionStart() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 渲染过渡内容
|
||||
* @param renderer 渲染后端引用
|
||||
*
|
||||
* 根据进度控制新旧场景的翻转角度
|
||||
*/
|
||||
void TransitionFlipScene::renderContent(RenderBackend &renderer) {
|
||||
elapsed_ += 1.0f / 60.0f;
|
||||
progress_ = duration_ > 0.0f ? std::min(1.0f, elapsed_ / duration_) : 1.0f;
|
||||
|
||||
float easeProgress = progress_ < 0.5f ? 2.0f * progress_ * progress_
|
||||
: -1.0f + (4.0f - 2.0f * progress_) * progress_;
|
||||
|
||||
float angle = easeProgress * PI_F;
|
||||
|
||||
if (progress_ < 0.5f) {
|
||||
if (outScene_) {
|
||||
float currentAngle = angle;
|
||||
|
||||
Camera *camera = outScene_->getActiveCamera();
|
||||
float originalRotation = camera ? camera->getRotation() : 0.0f;
|
||||
|
||||
if (axis_ == Axis::Horizontal) {
|
||||
if (camera) {
|
||||
camera->setRotation(originalRotation + currentAngle * RAD_TO_DEG);
|
||||
}
|
||||
} else {
|
||||
if (camera) {
|
||||
camera->setRotation(originalRotation - currentAngle * RAD_TO_DEG);
|
||||
}
|
||||
}
|
||||
|
||||
outScene_->renderContent(renderer);
|
||||
|
||||
if (camera) {
|
||||
camera->setRotation(originalRotation);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (inScene_) {
|
||||
float currentAngle = angle - PI_F;
|
||||
|
||||
Camera *camera = inScene_->getActiveCamera();
|
||||
float originalRotation = camera ? camera->getRotation() : 0.0f;
|
||||
|
||||
if (axis_ == Axis::Horizontal) {
|
||||
if (camera) {
|
||||
camera->setRotation(originalRotation + currentAngle * RAD_TO_DEG);
|
||||
}
|
||||
} else {
|
||||
if (camera) {
|
||||
camera->setRotation(originalRotation - currentAngle * RAD_TO_DEG);
|
||||
}
|
||||
}
|
||||
|
||||
inScene_->renderContent(renderer);
|
||||
|
||||
if (camera) {
|
||||
camera->setRotation(originalRotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (progress_ >= 1.0f && !isFinished_) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
#include <extra2d/scene/transition_scale_scene.h>
|
||||
#include <extra2d/graphics/camera.h>
|
||||
#include <extra2d/graphics/render_backend.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 构造函数,初始化缩放过渡场景
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
*/
|
||||
TransitionScaleScene::TransitionScaleScene(float duration, Ptr<Scene> inScene)
|
||||
: TransitionScene(duration, inScene) {}
|
||||
|
||||
/**
|
||||
* @brief 创建缩放过渡场景的静态工厂方法
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
* @return 过渡场景智能指针
|
||||
*/
|
||||
Ptr<TransitionScaleScene> TransitionScaleScene::create(float duration,
|
||||
Ptr<Scene> inScene) {
|
||||
return makePtr<TransitionScaleScene>(duration, inScene);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 启动过渡动画
|
||||
*
|
||||
* 缩放过渡不需要特殊的初始化
|
||||
*/
|
||||
void TransitionScaleScene::onTransitionStart() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 渲染过渡内容
|
||||
* @param renderer 渲染后端引用
|
||||
*
|
||||
* 根据进度控制新旧场景的缩放比例
|
||||
*/
|
||||
void TransitionScaleScene::renderContent(RenderBackend &renderer) {
|
||||
elapsed_ += 1.0f / 60.0f;
|
||||
progress_ = duration_ > 0.0f ? std::min(1.0f, elapsed_ / duration_) : 1.0f;
|
||||
|
||||
float easeProgress = progress_ < 0.5f ? 2.0f * progress_ * progress_
|
||||
: -1.0f + (4.0f - 2.0f * progress_) * progress_;
|
||||
|
||||
if (outScene_) {
|
||||
float scale = std::max(0.01f, 1.0f - easeProgress);
|
||||
|
||||
Camera *camera = outScene_->getActiveCamera();
|
||||
float originalZoom = camera ? camera->getZoom() : 1.0f;
|
||||
|
||||
if (camera) {
|
||||
camera->setZoom(originalZoom * scale);
|
||||
}
|
||||
|
||||
outScene_->renderContent(renderer);
|
||||
|
||||
if (camera) {
|
||||
camera->setZoom(originalZoom);
|
||||
}
|
||||
}
|
||||
|
||||
if (inScene_) {
|
||||
float scale = std::max(0.01f, easeProgress);
|
||||
|
||||
Camera *camera = inScene_->getActiveCamera();
|
||||
float originalZoom = camera ? camera->getZoom() : 1.0f;
|
||||
|
||||
if (camera) {
|
||||
camera->setZoom(originalZoom * scale);
|
||||
}
|
||||
|
||||
inScene_->renderContent(renderer);
|
||||
|
||||
if (camera) {
|
||||
camera->setZoom(originalZoom);
|
||||
}
|
||||
}
|
||||
|
||||
if (progress_ >= 1.0f && !isFinished_) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
#include <extra2d/scene/transition_scene.h>
|
||||
#include <extra2d/graphics/render_backend.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 构造函数,初始化过渡场景
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
*/
|
||||
TransitionScene::TransitionScene(float duration, Ptr<Scene> inScene)
|
||||
: duration_(duration), inScene_(inScene) {}
|
||||
|
||||
/**
|
||||
* @brief 场景进入时的回调
|
||||
*
|
||||
* 调用退出场景的过渡开始回调,初始化进入场景,并启动过渡
|
||||
*/
|
||||
void TransitionScene::onEnter() {
|
||||
Scene::onEnter();
|
||||
|
||||
if (outScene_) {
|
||||
outScene_->onExitTransitionDidStart();
|
||||
}
|
||||
|
||||
if (inScene_) {
|
||||
inScene_->onEnter();
|
||||
inScene_->onAttachToScene(inScene_.get());
|
||||
}
|
||||
|
||||
onTransitionStart();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 场景退出时的回调
|
||||
*
|
||||
* 调用退出场景的 onExit 和进入场景的过渡完成回调
|
||||
*/
|
||||
void TransitionScene::onExit() {
|
||||
if (outScene_) {
|
||||
outScene_->onExit();
|
||||
outScene_->onDetachFromScene();
|
||||
}
|
||||
|
||||
if (inScene_) {
|
||||
inScene_->onEnterTransitionDidFinish();
|
||||
}
|
||||
|
||||
Scene::onExit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 完成过渡
|
||||
*
|
||||
* 标记过渡完成并调用完成回调
|
||||
*/
|
||||
void TransitionScene::finish() {
|
||||
if (isFinished_) {
|
||||
return;
|
||||
}
|
||||
|
||||
isFinished_ = true;
|
||||
|
||||
E2D_LOG_DEBUG("TransitionScene::finish - 过渡完成,切换到目标场景");
|
||||
|
||||
if (finishCallback_) {
|
||||
finishCallback_();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 渲染过渡内容
|
||||
* @param renderer 渲染后端引用
|
||||
*
|
||||
* 默认先渲染退出场景,再渲染进入场景
|
||||
*/
|
||||
void TransitionScene::renderContent(RenderBackend &renderer) {
|
||||
drawOutScene(renderer);
|
||||
drawInScene(renderer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制退出场景
|
||||
* @param renderer 渲染后端引用
|
||||
*/
|
||||
void TransitionScene::drawOutScene(RenderBackend &renderer) {
|
||||
if (outScene_) {
|
||||
outScene_->renderContent(renderer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制进入场景
|
||||
* @param renderer 渲染后端引用
|
||||
*/
|
||||
void TransitionScene::drawInScene(RenderBackend &renderer) {
|
||||
if (inScene_) {
|
||||
inScene_->renderContent(renderer);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
#include <extra2d/scene/transition_slide_scene.h>
|
||||
#include <extra2d/graphics/camera.h>
|
||||
#include <extra2d/graphics/render_backend.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 构造函数,初始化滑动过渡场景
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
* @param direction 滑动方向
|
||||
*/
|
||||
TransitionSlideScene::TransitionSlideScene(float duration, Ptr<Scene> inScene,
|
||||
TransitionDirection direction)
|
||||
: TransitionScene(duration, inScene), direction_(direction) {}
|
||||
|
||||
/**
|
||||
* @brief 创建滑动过渡场景的静态工厂方法
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
* @param direction 滑动方向
|
||||
* @return 过渡场景智能指针
|
||||
*/
|
||||
Ptr<TransitionSlideScene> TransitionSlideScene::create(
|
||||
float duration, Ptr<Scene> inScene, TransitionDirection direction) {
|
||||
return makePtr<TransitionSlideScene>(duration, inScene, direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 启动过渡动画
|
||||
*
|
||||
* 滑动过渡不需要特殊的初始化
|
||||
*/
|
||||
void TransitionSlideScene::onTransitionStart() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 渲染过渡内容
|
||||
* @param renderer 渲染后端引用
|
||||
*
|
||||
* 根据进度控制新旧场景的滑动位置
|
||||
*/
|
||||
void TransitionSlideScene::renderContent(RenderBackend &renderer) {
|
||||
float screenWidth = 800.0f;
|
||||
float screenHeight = 600.0f;
|
||||
|
||||
if (outScene_) {
|
||||
Size viewportSize = outScene_->getViewportSize();
|
||||
if (viewportSize.width > 0 && viewportSize.height > 0) {
|
||||
screenWidth = viewportSize.width;
|
||||
screenHeight = viewportSize.height;
|
||||
}
|
||||
} else if (inScene_) {
|
||||
Size viewportSize = inScene_->getViewportSize();
|
||||
if (viewportSize.width > 0 && viewportSize.height > 0) {
|
||||
screenWidth = viewportSize.width;
|
||||
screenHeight = viewportSize.height;
|
||||
}
|
||||
}
|
||||
|
||||
elapsed_ += 1.0f / 60.0f;
|
||||
progress_ = duration_ > 0.0f ? std::min(1.0f, elapsed_ / duration_) : 1.0f;
|
||||
|
||||
float easeProgress = progress_ < 0.5f ? 2.0f * progress_ * progress_
|
||||
: -1.0f + (4.0f - 2.0f * progress_) * progress_;
|
||||
|
||||
if (outScene_) {
|
||||
float offsetX = 0.0f;
|
||||
float offsetY = 0.0f;
|
||||
|
||||
switch (direction_) {
|
||||
case TransitionDirection::Left:
|
||||
offsetX = -screenWidth * easeProgress;
|
||||
break;
|
||||
case TransitionDirection::Right:
|
||||
offsetX = screenWidth * easeProgress;
|
||||
break;
|
||||
case TransitionDirection::Up:
|
||||
offsetY = -screenHeight * easeProgress;
|
||||
break;
|
||||
case TransitionDirection::Down:
|
||||
offsetY = screenHeight * easeProgress;
|
||||
break;
|
||||
}
|
||||
|
||||
Camera *camera = outScene_->getActiveCamera();
|
||||
Vec2 originalPos = camera ? camera->getPosition() : Vec2::Zero();
|
||||
|
||||
if (camera) {
|
||||
camera->setPos(originalPos.x + offsetX, originalPos.y + offsetY);
|
||||
}
|
||||
|
||||
outScene_->renderContent(renderer);
|
||||
|
||||
if (camera) {
|
||||
camera->setPos(originalPos);
|
||||
}
|
||||
}
|
||||
|
||||
if (inScene_) {
|
||||
float offsetX = 0.0f;
|
||||
float offsetY = 0.0f;
|
||||
|
||||
switch (direction_) {
|
||||
case TransitionDirection::Left:
|
||||
offsetX = screenWidth * (1.0f - easeProgress);
|
||||
break;
|
||||
case TransitionDirection::Right:
|
||||
offsetX = -screenWidth * (1.0f - easeProgress);
|
||||
break;
|
||||
case TransitionDirection::Up:
|
||||
offsetY = screenHeight * (1.0f - easeProgress);
|
||||
break;
|
||||
case TransitionDirection::Down:
|
||||
offsetY = -screenHeight * (1.0f - easeProgress);
|
||||
break;
|
||||
}
|
||||
|
||||
Camera *camera = inScene_->getActiveCamera();
|
||||
Vec2 originalPos = camera ? camera->getPosition() : Vec2::Zero();
|
||||
|
||||
if (camera) {
|
||||
camera->setPos(originalPos.x + offsetX, originalPos.y + offsetY);
|
||||
}
|
||||
|
||||
inScene_->renderContent(renderer);
|
||||
|
||||
if (camera) {
|
||||
camera->setPos(originalPos);
|
||||
}
|
||||
}
|
||||
|
||||
if (progress_ >= 1.0f && !isFinished_) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
Loading…
Reference in New Issue