refactor(action): 重构动作系统架构并添加新功能
重构动作系统核心架构,主要变更包括: 1. 将动作系统拆分为多个模块化头文件 2. 新增动作管理器实现集中管理 3. 添加瞬时动作、间隔动作和特殊动作类 4. 实现完整的缓动动画系统 5. 优化节点动作接口与性能 新增功能: 1. 支持颜色和翻转动画 2. 添加回调动作和节点管理动作 3. 实现跟随和速度控制等特殊动作 4. 提供30+种缓动函数支持 BREAKING CHANGE: 动作系统API不兼容旧版本,需更新相关调用代码
This commit is contained in:
parent
3ffcd692b6
commit
f02b368dc9
|
|
@ -1,76 +1,172 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <extra2d/core/types.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
class Node;
|
class Node;
|
||||||
|
|
||||||
enum class ActionState { Idle, Running, Paused, Completed };
|
/**
|
||||||
|
* @brief 动作状态枚举
|
||||||
class Action {
|
*/
|
||||||
public:
|
enum class ActionState {
|
||||||
using ProgressCallback = std::function<void(float)>;
|
Idle,
|
||||||
using CompletionCallback = std::function<void()>;
|
Running,
|
||||||
|
Paused,
|
||||||
Action();
|
Completed
|
||||||
virtual ~Action() = default;
|
};
|
||||||
|
|
||||||
Action(const Action &) = delete;
|
/**
|
||||||
Action &operator=(const Action &) = delete;
|
* @brief 动作基类
|
||||||
Action(Action &&) = default;
|
*
|
||||||
Action &operator=(Action &&) = default;
|
* 所有动作的基类,定义了动作的核心接口。
|
||||||
|
* 动作用于修改 Node 的属性,实现动画效果。
|
||||||
virtual void start(Node *target);
|
*/
|
||||||
virtual void stop();
|
class Action {
|
||||||
virtual void update(float dt);
|
public:
|
||||||
virtual void step(float dt);
|
using CompletionCallback = std::function<void()>;
|
||||||
|
|
||||||
virtual bool isDone() const = 0;
|
Action();
|
||||||
virtual Action *clone() const = 0;
|
virtual ~Action() = default;
|
||||||
virtual Action *reverse() const = 0;
|
|
||||||
|
Action(const Action&) = delete;
|
||||||
void pause();
|
Action& operator=(const Action&) = delete;
|
||||||
void resume();
|
Action(Action&&) = default;
|
||||||
void restart();
|
Action& operator=(Action&&) = default;
|
||||||
|
|
||||||
ActionState getState() const { return state_; }
|
/**
|
||||||
float getElapsed() const { return elapsed_; }
|
* @brief 检查动作是否完成
|
||||||
float getDuration() const { return duration_; }
|
* @return true 如果动作已完成
|
||||||
Node *getTarget() const { return target_; }
|
*/
|
||||||
Node *getOriginalTarget() const { return originalTarget_; }
|
virtual bool isDone() const;
|
||||||
|
|
||||||
void setDuration(float duration) { duration_ = duration; }
|
/**
|
||||||
void setSpeed(float speed) { speed_ = speed; }
|
* @brief 使用目标节点启动动作
|
||||||
float getSpeed() const { return speed_; }
|
* @param target 目标节点
|
||||||
|
*/
|
||||||
void setProgressCallback(ProgressCallback callback) {
|
virtual void startWithTarget(Node* target);
|
||||||
progressCallback_ = std::move(callback);
|
|
||||||
}
|
/**
|
||||||
void setCompletionCallback(CompletionCallback callback) {
|
* @brief 停止动作
|
||||||
completionCallback_ = std::move(callback);
|
*/
|
||||||
}
|
virtual void stop();
|
||||||
|
|
||||||
void setTag(int tag) { tag_ = tag; }
|
/**
|
||||||
int getTag() const { return tag_; }
|
* @brief 每帧调用的步进函数
|
||||||
|
* @param dt 帧时间间隔
|
||||||
protected:
|
*/
|
||||||
virtual void onStart() {}
|
virtual void step(float dt);
|
||||||
virtual void onUpdate(float progress) = 0;
|
|
||||||
virtual void onComplete() {}
|
/**
|
||||||
|
* @brief 更新动作状态
|
||||||
void setDone() { state_ = ActionState::Completed; }
|
* @param time 归一化时间 [0, 1]
|
||||||
|
*/
|
||||||
Node *target_ = nullptr;
|
virtual void update(float time);
|
||||||
Node *originalTarget_ = nullptr;
|
|
||||||
ActionState state_ = ActionState::Idle;
|
/**
|
||||||
float elapsed_ = 0.0f;
|
* @brief 克隆动作
|
||||||
float duration_ = 0.0f;
|
* @return 动作的深拷贝
|
||||||
float speed_ = 1.0f;
|
*/
|
||||||
int tag_ = -1;
|
virtual Action* clone() const = 0;
|
||||||
ProgressCallback progressCallback_;
|
|
||||||
CompletionCallback completionCallback_;
|
/**
|
||||||
|
* @brief 创建反向动作
|
||||||
|
* @return 反向动作
|
||||||
|
*/
|
||||||
|
virtual Action* reverse() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 暂停动作
|
||||||
|
*/
|
||||||
|
void pause();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 恢复动作
|
||||||
|
*/
|
||||||
|
void resume();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 重启动作
|
||||||
|
*/
|
||||||
|
void restart();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置完成回调
|
||||||
|
* @param callback 回调函数
|
||||||
|
*/
|
||||||
|
void setCompletionCallback(const CompletionCallback& callback) {
|
||||||
|
completionCallback_ = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取目标节点
|
||||||
|
* @return 目标节点指针
|
||||||
|
*/
|
||||||
|
Node* getTarget() const { return target_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取原始目标节点
|
||||||
|
* @return 原始目标节点指针
|
||||||
|
*/
|
||||||
|
Node* getOriginalTarget() const { return originalTarget_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取动作状态
|
||||||
|
* @return 当前状态
|
||||||
|
*/
|
||||||
|
ActionState getState() const { return state_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取标签
|
||||||
|
* @return 标签值
|
||||||
|
*/
|
||||||
|
int getTag() const { return tag_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置标签
|
||||||
|
* @param tag 标签值
|
||||||
|
*/
|
||||||
|
void setTag(int tag) { tag_ = tag; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取标志位
|
||||||
|
* @return 标志位
|
||||||
|
*/
|
||||||
|
unsigned int getFlags() const { return flags_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置标志位
|
||||||
|
* @param flags 标志位
|
||||||
|
*/
|
||||||
|
void setFlags(unsigned int flags) { flags_ = flags; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* @brief 动作开始时调用
|
||||||
|
*/
|
||||||
|
virtual void onStart() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 动作完成时调用
|
||||||
|
*/
|
||||||
|
virtual void onComplete() {
|
||||||
|
if (completionCallback_) {
|
||||||
|
completionCallback_();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置动作完成状态
|
||||||
|
*/
|
||||||
|
void setDone() { state_ = ActionState::Completed; }
|
||||||
|
|
||||||
|
Node* target_ = nullptr;
|
||||||
|
Node* originalTarget_ = nullptr;
|
||||||
|
ActionState state_ = ActionState::Idle;
|
||||||
|
int tag_ = -1;
|
||||||
|
unsigned int flags_ = 0;
|
||||||
|
CompletionCallback completionCallback_;
|
||||||
};
|
};
|
||||||
|
|
||||||
using ActionPtr = std::unique_ptr<Action>;
|
|
||||||
} // namespace extra2d
|
} // namespace extra2d
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,344 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <extra2d/action/action_interval.h>
|
||||||
|
#include <extra2d/action/ease.h>
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 缓动动作基类
|
||||||
|
*
|
||||||
|
* 使用装饰器模式包装其他动作,实现缓动效果。
|
||||||
|
*/
|
||||||
|
class ActionEase : public ActionInterval {
|
||||||
|
public:
|
||||||
|
virtual ~ActionEase();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取内部动作
|
||||||
|
* @return 内部动作指针
|
||||||
|
*/
|
||||||
|
ActionInterval* getInnerAction() const { return innerAction_; }
|
||||||
|
|
||||||
|
void startWithTarget(Node* target) override;
|
||||||
|
void stop() override;
|
||||||
|
void update(float time) override;
|
||||||
|
ActionInterval* clone() const override = 0;
|
||||||
|
ActionInterval* reverse() const override = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ActionEase() = default;
|
||||||
|
bool initWithAction(ActionInterval* action);
|
||||||
|
void onUpdate(float progress) override {}
|
||||||
|
|
||||||
|
ActionInterval* innerAction_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 指数缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
class EaseExponentialIn : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseExponentialIn* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EaseExponentialOut : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseExponentialOut* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EaseExponentialInOut : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseExponentialInOut* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 正弦缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
class EaseSineIn : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseSineIn* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EaseSineOut : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseSineOut* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EaseSineInOut : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseSineInOut* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 弹性缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
class EaseElasticIn : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseElasticIn* create(ActionInterval* action, float period = 0.3f);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
float period_ = 0.3f;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EaseElasticOut : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseElasticOut* create(ActionInterval* action, float period = 0.3f);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
float period_ = 0.3f;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EaseElasticInOut : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseElasticInOut* create(ActionInterval* action, float period = 0.3f);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
float period_ = 0.3f;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 弹跳缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
class EaseBounceIn : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseBounceIn* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EaseBounceOut : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseBounceOut* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EaseBounceInOut : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseBounceInOut* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 回震缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
class EaseBackIn : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseBackIn* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EaseBackOut : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseBackOut* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EaseBackInOut : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseBackInOut* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 二次缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
class EaseQuadIn : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseQuadIn* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EaseQuadOut : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseQuadOut* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EaseQuadInOut : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseQuadInOut* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 三次缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
class EaseCubicIn : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseCubicIn* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EaseCubicOut : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseCubicOut* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EaseCubicInOut : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseCubicInOut* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 四次缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
class EaseQuartIn : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseQuartIn* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EaseQuartOut : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseQuartOut* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EaseQuartInOut : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseQuartInOut* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 五次缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
class EaseQuintIn : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseQuintIn* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EaseQuintOut : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseQuintOut* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EaseQuintInOut : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseQuintInOut* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 圆形缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
class EaseCircleIn : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseCircleIn* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EaseCircleOut : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseCircleOut* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EaseCircleInOut : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseCircleInOut* create(ActionInterval* action);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 自定义缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 自定义缓动动作
|
||||||
|
*/
|
||||||
|
class EaseCustom : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseCustom* create(ActionInterval* action, EaseFunction easeFunc);
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
void update(float time) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
EaseFunction easeFunc_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <extra2d/action/finite_time_action.h>
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 瞬时动作基类
|
||||||
|
*
|
||||||
|
* 瞬间完成的动作,中间没有任何动画效果。
|
||||||
|
* 继承自 FiniteTimeAction,持续时间为 0。
|
||||||
|
*/
|
||||||
|
class ActionInstant : public FiniteTimeAction {
|
||||||
|
public:
|
||||||
|
ActionInstant();
|
||||||
|
virtual ~ActionInstant() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检查动作是否完成
|
||||||
|
* @return 总是返回 true
|
||||||
|
*/
|
||||||
|
bool isDone() const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 使用目标节点启动动作
|
||||||
|
* @param target 目标节点
|
||||||
|
*/
|
||||||
|
void startWithTarget(Node* target) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 每帧调用的步进函数
|
||||||
|
* @param dt 帧时间间隔
|
||||||
|
*/
|
||||||
|
void step(float dt) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 克隆动作
|
||||||
|
* @return 动作的深拷贝
|
||||||
|
*/
|
||||||
|
ActionInstant* clone() const override = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 创建反向动作
|
||||||
|
* @return 反向动作
|
||||||
|
*/
|
||||||
|
ActionInstant* reverse() const override = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* @brief 执行瞬时动作
|
||||||
|
*/
|
||||||
|
virtual void execute() = 0;
|
||||||
|
|
||||||
|
bool done_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -0,0 +1,169 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <extra2d/action/action_instant.h>
|
||||||
|
#include <extra2d/core/math_types.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 回调动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 无参数回调动作
|
||||||
|
*/
|
||||||
|
class CallFunc : public ActionInstant {
|
||||||
|
public:
|
||||||
|
using Callback = std::function<void()>;
|
||||||
|
|
||||||
|
static CallFunc* create(const Callback& callback);
|
||||||
|
|
||||||
|
ActionInstant* clone() const override;
|
||||||
|
ActionInstant* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void execute() override;
|
||||||
|
|
||||||
|
Callback callback_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 带节点参数的回调动作
|
||||||
|
*/
|
||||||
|
class CallFuncN : public ActionInstant {
|
||||||
|
public:
|
||||||
|
using Callback = std::function<void(Node*)>;
|
||||||
|
|
||||||
|
static CallFuncN* create(const Callback& callback);
|
||||||
|
|
||||||
|
ActionInstant* clone() const override;
|
||||||
|
ActionInstant* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void execute() override;
|
||||||
|
|
||||||
|
Callback callback_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 位置动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 瞬间放置到指定位置
|
||||||
|
*/
|
||||||
|
class Place : public ActionInstant {
|
||||||
|
public:
|
||||||
|
static Place* create(const Vec2& position);
|
||||||
|
|
||||||
|
ActionInstant* clone() const override;
|
||||||
|
ActionInstant* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void execute() override;
|
||||||
|
|
||||||
|
Vec2 position_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 翻转动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief X轴翻转动作
|
||||||
|
*/
|
||||||
|
class FlipX : public ActionInstant {
|
||||||
|
public:
|
||||||
|
static FlipX* create(bool flipX);
|
||||||
|
|
||||||
|
ActionInstant* clone() const override;
|
||||||
|
ActionInstant* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void execute() override;
|
||||||
|
|
||||||
|
bool flipX_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Y轴翻转动作
|
||||||
|
*/
|
||||||
|
class FlipY : public ActionInstant {
|
||||||
|
public:
|
||||||
|
static FlipY* create(bool flipY);
|
||||||
|
|
||||||
|
ActionInstant* clone() const override;
|
||||||
|
ActionInstant* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void execute() override;
|
||||||
|
|
||||||
|
bool flipY_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 可见性动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 显示动作
|
||||||
|
*/
|
||||||
|
class Show : public ActionInstant {
|
||||||
|
public:
|
||||||
|
static Show* create();
|
||||||
|
|
||||||
|
ActionInstant* clone() const override;
|
||||||
|
ActionInstant* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void execute() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 隐藏动作
|
||||||
|
*/
|
||||||
|
class Hide : public ActionInstant {
|
||||||
|
public:
|
||||||
|
static Hide* create();
|
||||||
|
|
||||||
|
ActionInstant* clone() const override;
|
||||||
|
ActionInstant* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void execute() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 切换可见性动作
|
||||||
|
*/
|
||||||
|
class ToggleVisibility : public ActionInstant {
|
||||||
|
public:
|
||||||
|
static ToggleVisibility* create();
|
||||||
|
|
||||||
|
ActionInstant* clone() const override;
|
||||||
|
ActionInstant* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void execute() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 节点管理动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 移除自身动作
|
||||||
|
*/
|
||||||
|
class RemoveSelf : public ActionInstant {
|
||||||
|
public:
|
||||||
|
static RemoveSelf* create();
|
||||||
|
|
||||||
|
ActionInstant* clone() const override;
|
||||||
|
ActionInstant* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void execute() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <extra2d/action/finite_time_action.h>
|
||||||
|
#include <extra2d/action/ease.h>
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 时间间隔动作基类
|
||||||
|
*
|
||||||
|
* 在指定时间内完成的动作,中间会有动画效果。
|
||||||
|
* 继承自 FiniteTimeAction。
|
||||||
|
*/
|
||||||
|
class ActionInterval : public FiniteTimeAction {
|
||||||
|
public:
|
||||||
|
ActionInterval() = default;
|
||||||
|
explicit ActionInterval(float duration);
|
||||||
|
virtual ~ActionInterval() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取已流逝时间
|
||||||
|
* @return 已流逝时间(秒)
|
||||||
|
*/
|
||||||
|
float getElapsed() const { return elapsed_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检查动作是否完成
|
||||||
|
* @return true 如果动作已完成
|
||||||
|
*/
|
||||||
|
bool isDone() const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 使用目标节点启动动作
|
||||||
|
* @param target 目标节点
|
||||||
|
*/
|
||||||
|
void startWithTarget(Node* target) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 停止动作
|
||||||
|
*/
|
||||||
|
void stop() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 每帧调用的步进函数
|
||||||
|
* @param dt 帧时间间隔
|
||||||
|
*/
|
||||||
|
void step(float dt) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置振幅比率(用于缓动)
|
||||||
|
* @param amp 振幅比率
|
||||||
|
*/
|
||||||
|
void setAmplitudeRate(float amp) { amplitudeRate_ = amp; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取振幅比率
|
||||||
|
* @return 振幅比率
|
||||||
|
*/
|
||||||
|
float getAmplitudeRate() const { return amplitudeRate_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置内置缓动函数
|
||||||
|
* @param easeFunc 缓动函数
|
||||||
|
*/
|
||||||
|
void setEaseFunction(EaseFunction easeFunc) { easeFunc_ = easeFunc; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取内置缓动函数
|
||||||
|
* @return 缓动函数
|
||||||
|
*/
|
||||||
|
EaseFunction getEaseFunction() const { return easeFunc_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 克隆动作
|
||||||
|
* @return 动作的深拷贝
|
||||||
|
*/
|
||||||
|
ActionInterval* clone() const override = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 创建反向动作
|
||||||
|
* @return 反向动作
|
||||||
|
*/
|
||||||
|
ActionInterval* reverse() const override = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* @brief 动作开始时调用
|
||||||
|
*/
|
||||||
|
virtual void onStart() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 动作更新时调用
|
||||||
|
* @param progress 归一化进度 [0, 1]
|
||||||
|
*/
|
||||||
|
virtual void onUpdate(float progress) = 0;
|
||||||
|
|
||||||
|
float elapsed_ = 0.0f;
|
||||||
|
bool firstTick_ = true;
|
||||||
|
float amplitudeRate_ = 1.0f;
|
||||||
|
EaseFunction easeFunc_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -0,0 +1,469 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <extra2d/action/action_interval.h>
|
||||||
|
#include <extra2d/core/math_types.h>
|
||||||
|
#include <extra2d/core/color.h>
|
||||||
|
#include <functional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 移动动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 相对移动动作
|
||||||
|
*/
|
||||||
|
class MoveBy : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static MoveBy* create(float duration, const Vec2& delta);
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onStart() override;
|
||||||
|
void onUpdate(float progress) override;
|
||||||
|
|
||||||
|
Vec2 delta_;
|
||||||
|
Vec2 startPosition_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 绝对移动动作
|
||||||
|
*/
|
||||||
|
class MoveTo : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static MoveTo* create(float duration, const Vec2& position);
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onStart() override;
|
||||||
|
void onUpdate(float progress) override;
|
||||||
|
|
||||||
|
Vec2 endPosition_;
|
||||||
|
Vec2 startPosition_;
|
||||||
|
Vec2 delta_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 跳跃动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 相对跳跃动作
|
||||||
|
*/
|
||||||
|
class JumpBy : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static JumpBy* create(float duration, const Vec2& position, float height, int jumps);
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onStart() override;
|
||||||
|
void onUpdate(float progress) override;
|
||||||
|
|
||||||
|
Vec2 startPosition_;
|
||||||
|
Vec2 delta_;
|
||||||
|
float height_ = 0.0f;
|
||||||
|
int jumps_ = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 绝对跳跃动作
|
||||||
|
*/
|
||||||
|
class JumpTo : public JumpBy {
|
||||||
|
public:
|
||||||
|
static JumpTo* create(float duration, const Vec2& position, float height, int jumps);
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onStart() override;
|
||||||
|
|
||||||
|
Vec2 endPosition_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 贝塞尔曲线动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 贝塞尔曲线配置
|
||||||
|
*/
|
||||||
|
struct BezierConfig {
|
||||||
|
Vec2 controlPoint1;
|
||||||
|
Vec2 controlPoint2;
|
||||||
|
Vec2 endPosition;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 相对贝塞尔曲线动作
|
||||||
|
*/
|
||||||
|
class BezierBy : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static BezierBy* create(float duration, const BezierConfig& config);
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onStart() override;
|
||||||
|
void onUpdate(float progress) override;
|
||||||
|
static float bezierat(float a, float b, float c, float d, float t);
|
||||||
|
|
||||||
|
BezierConfig config_;
|
||||||
|
Vec2 startPosition_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 绝对贝塞尔曲线动作
|
||||||
|
*/
|
||||||
|
class BezierTo : public BezierBy {
|
||||||
|
public:
|
||||||
|
static BezierTo* create(float duration, const BezierConfig& config);
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onStart() override;
|
||||||
|
|
||||||
|
BezierConfig originalConfig_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 缩放动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 相对缩放动作
|
||||||
|
*/
|
||||||
|
class ScaleBy : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static ScaleBy* create(float duration, float scale);
|
||||||
|
static ScaleBy* create(float duration, float scaleX, float scaleY);
|
||||||
|
static ScaleBy* create(float duration, const Vec2& scale);
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onStart() override;
|
||||||
|
void onUpdate(float progress) override;
|
||||||
|
|
||||||
|
Vec2 deltaScale_;
|
||||||
|
Vec2 startScale_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 绝对缩放动作
|
||||||
|
*/
|
||||||
|
class ScaleTo : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static ScaleTo* create(float duration, float scale);
|
||||||
|
static ScaleTo* create(float duration, float scaleX, float scaleY);
|
||||||
|
static ScaleTo* create(float duration, const Vec2& scale);
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onStart() override;
|
||||||
|
void onUpdate(float progress) override;
|
||||||
|
|
||||||
|
Vec2 endScale_;
|
||||||
|
Vec2 startScale_;
|
||||||
|
Vec2 delta_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 旋转动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 相对旋转动作
|
||||||
|
*/
|
||||||
|
class RotateBy : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static RotateBy* create(float duration, float deltaAngle);
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onStart() override;
|
||||||
|
void onUpdate(float progress) override;
|
||||||
|
|
||||||
|
float deltaAngle_ = 0.0f;
|
||||||
|
float startAngle_ = 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 绝对旋转动作
|
||||||
|
*/
|
||||||
|
class RotateTo : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static RotateTo* create(float duration, float angle);
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onStart() override;
|
||||||
|
void onUpdate(float progress) override;
|
||||||
|
|
||||||
|
float endAngle_ = 0.0f;
|
||||||
|
float startAngle_ = 0.0f;
|
||||||
|
float deltaAngle_ = 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 淡入淡出动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 淡入动作
|
||||||
|
*/
|
||||||
|
class FadeIn : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static FadeIn* create(float duration);
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onStart() override;
|
||||||
|
void onUpdate(float progress) override;
|
||||||
|
|
||||||
|
float startOpacity_ = 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 淡出动作
|
||||||
|
*/
|
||||||
|
class FadeOut : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static FadeOut* create(float duration);
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onStart() override;
|
||||||
|
void onUpdate(float progress) override;
|
||||||
|
|
||||||
|
float startOpacity_ = 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 淡入到指定透明度动作
|
||||||
|
*/
|
||||||
|
class FadeTo : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static FadeTo* create(float duration, float opacity);
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onStart() override;
|
||||||
|
void onUpdate(float progress) override;
|
||||||
|
|
||||||
|
float endOpacity_ = 0.0f;
|
||||||
|
float startOpacity_ = 0.0f;
|
||||||
|
float deltaOpacity_ = 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 闪烁动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 闪烁动作
|
||||||
|
*/
|
||||||
|
class Blink : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static Blink* create(float duration, int times);
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onStart() override;
|
||||||
|
void onUpdate(float progress) override;
|
||||||
|
|
||||||
|
int times_ = 1;
|
||||||
|
int currentTimes_ = 0;
|
||||||
|
bool originalVisible_ = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 色调动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 色调变化动作
|
||||||
|
*/
|
||||||
|
class TintTo : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static TintTo* create(float duration, uint8_t red, uint8_t green, uint8_t blue);
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onStart() override;
|
||||||
|
void onUpdate(float progress) override;
|
||||||
|
|
||||||
|
Color3B startColor_;
|
||||||
|
Color3B endColor_;
|
||||||
|
Color3B deltaColor_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 相对色调变化动作
|
||||||
|
*/
|
||||||
|
class TintBy : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static TintBy* create(float duration, int16_t deltaRed, int16_t deltaGreen, int16_t deltaBlue);
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onStart() override;
|
||||||
|
void onUpdate(float progress) override;
|
||||||
|
|
||||||
|
Color3B startColor_;
|
||||||
|
int16_t deltaR_ = 0;
|
||||||
|
int16_t deltaG_ = 0;
|
||||||
|
int16_t deltaB_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 组合动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 序列动作
|
||||||
|
*/
|
||||||
|
class Sequence : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static Sequence* create(ActionInterval* action1, ...);
|
||||||
|
static Sequence* create(const std::vector<ActionInterval*>& actions);
|
||||||
|
|
||||||
|
~Sequence();
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onStart() override;
|
||||||
|
void onUpdate(float progress) override;
|
||||||
|
|
||||||
|
std::vector<ActionInterval*> actions_;
|
||||||
|
size_t currentIndex_ = 0;
|
||||||
|
float split_ = 0.0f;
|
||||||
|
float last_ = -1.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 并行动作
|
||||||
|
*/
|
||||||
|
class Spawn : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static Spawn* create(ActionInterval* action1, ...);
|
||||||
|
static Spawn* create(const std::vector<ActionInterval*>& actions);
|
||||||
|
|
||||||
|
~Spawn();
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onStart() override;
|
||||||
|
void onUpdate(float progress) override;
|
||||||
|
|
||||||
|
std::vector<ActionInterval*> actions_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 重复动作
|
||||||
|
*/
|
||||||
|
class Repeat : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static Repeat* create(ActionInterval* action, int times);
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
bool isDone() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onStart() override;
|
||||||
|
void onUpdate(float progress) override;
|
||||||
|
|
||||||
|
ActionInterval* innerAction_ = nullptr;
|
||||||
|
int times_ = 1;
|
||||||
|
int currentTimes_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 永久重复动作
|
||||||
|
*/
|
||||||
|
class RepeatForever : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static RepeatForever* create(ActionInterval* action);
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
bool isDone() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onStart() override;
|
||||||
|
void onUpdate(float progress) override;
|
||||||
|
|
||||||
|
ActionInterval* innerAction_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 延时动作
|
||||||
|
*/
|
||||||
|
class DelayTime : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static DelayTime* create(float duration);
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onUpdate(float progress) override {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 反向时间动作
|
||||||
|
*/
|
||||||
|
class ReverseTime : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static ReverseTime* create(ActionInterval* action);
|
||||||
|
|
||||||
|
~ReverseTime();
|
||||||
|
|
||||||
|
ActionInterval* clone() const override;
|
||||||
|
ActionInterval* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onStart() override;
|
||||||
|
void onUpdate(float progress) override;
|
||||||
|
|
||||||
|
ActionInterval* innerAction_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -0,0 +1,130 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <extra2d/action/action.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 动作管理器
|
||||||
|
*
|
||||||
|
* 单例模式,集中管理所有动作的调度和生命周期。
|
||||||
|
* 负责动作的添加、移除、暂停、恢复和更新。
|
||||||
|
*/
|
||||||
|
class ActionManager {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief 获取单例实例
|
||||||
|
* @return ActionManager 实例指针
|
||||||
|
*/
|
||||||
|
static ActionManager* getInstance();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 销毁单例实例
|
||||||
|
*/
|
||||||
|
static void destroyInstance();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 添加动作到管理器
|
||||||
|
* @param action 动作指针
|
||||||
|
* @param target 目标节点
|
||||||
|
* @param paused 是否暂停
|
||||||
|
*/
|
||||||
|
void addAction(Action* action, Node* target, bool paused = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 移除指定动作
|
||||||
|
* @param action 动作指针
|
||||||
|
*/
|
||||||
|
void removeAction(Action* action);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 根据标签移除动作
|
||||||
|
* @param tag 标签值
|
||||||
|
* @param target 目标节点
|
||||||
|
*/
|
||||||
|
void removeActionByTag(int tag, Node* target);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 根据标志位移除动作
|
||||||
|
* @param flags 标志位
|
||||||
|
* @param target 目标节点
|
||||||
|
*/
|
||||||
|
void removeActionsByFlags(unsigned int flags, Node* target);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 移除目标节点的所有动作
|
||||||
|
* @param target 目标节点
|
||||||
|
*/
|
||||||
|
void removeAllActionsFromTarget(Node* target);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 移除所有动作
|
||||||
|
*/
|
||||||
|
void removeAllActions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 根据标签获取动作
|
||||||
|
* @param tag 标签值
|
||||||
|
* @param target 目标节点
|
||||||
|
* @return 动作指针,未找到返回 nullptr
|
||||||
|
*/
|
||||||
|
Action* getActionByTag(int tag, Node* target);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取目标节点的动作数量
|
||||||
|
* @param target 目标节点
|
||||||
|
* @return 动作数量
|
||||||
|
*/
|
||||||
|
size_t getActionCount(Node* target) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 暂停目标节点的所有动作
|
||||||
|
* @param target 目标节点
|
||||||
|
*/
|
||||||
|
void pauseTarget(Node* target);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 恢复目标节点的所有动作
|
||||||
|
* @param target 目标节点
|
||||||
|
*/
|
||||||
|
void resumeTarget(Node* target);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检查目标节点是否暂停
|
||||||
|
* @param target 目标节点
|
||||||
|
* @return true 如果暂停
|
||||||
|
*/
|
||||||
|
bool isPaused(Node* target) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 更新所有动作(每帧调用)
|
||||||
|
* @param dt 帧时间间隔
|
||||||
|
*/
|
||||||
|
void update(float dt);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ActionManager();
|
||||||
|
~ActionManager();
|
||||||
|
|
||||||
|
struct ActionElement {
|
||||||
|
std::vector<Action*> actions;
|
||||||
|
Node* target = nullptr;
|
||||||
|
bool paused = false;
|
||||||
|
int actionIndex = 0;
|
||||||
|
Action* currentAction = nullptr;
|
||||||
|
bool currentActionSalvaged = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
using ActionMap = std::unordered_map<Node*, ActionElement>;
|
||||||
|
|
||||||
|
void removeActionAt(size_t index, ActionElement& element);
|
||||||
|
void deleteAction(Action* action);
|
||||||
|
|
||||||
|
ActionMap targets_;
|
||||||
|
static ActionManager* instance_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -0,0 +1,166 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <extra2d/action/action.h>
|
||||||
|
#include <extra2d/action/action_interval.h>
|
||||||
|
#include <extra2d/core/math_types.h>
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 速度控制动作
|
||||||
|
*
|
||||||
|
* 包装其他动作,实现动态速度控制。
|
||||||
|
* 可以在运行时调整动作的播放速度。
|
||||||
|
*/
|
||||||
|
class Speed : public Action {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief 创建速度控制动作
|
||||||
|
* @param action 内部动作
|
||||||
|
* @param speed 速度倍率(1.0 为正常速度)
|
||||||
|
* @return 动作指针
|
||||||
|
*/
|
||||||
|
static Speed* create(ActionInterval* action, float speed);
|
||||||
|
|
||||||
|
~Speed();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取速度倍率
|
||||||
|
* @return 速度倍率
|
||||||
|
*/
|
||||||
|
float getSpeed() const { return speed_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置速度倍率
|
||||||
|
* @param speed 速度倍率
|
||||||
|
*/
|
||||||
|
void setSpeed(float speed) { speed_ = speed; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取内部动作
|
||||||
|
* @return 内部动作指针
|
||||||
|
*/
|
||||||
|
ActionInterval* getInnerAction() const { return innerAction_; }
|
||||||
|
|
||||||
|
void startWithTarget(Node* target) override;
|
||||||
|
void stop() override;
|
||||||
|
void step(float dt) override;
|
||||||
|
bool isDone() const override;
|
||||||
|
Action* clone() const override;
|
||||||
|
Action* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Speed() = default;
|
||||||
|
|
||||||
|
ActionInterval* innerAction_ = nullptr;
|
||||||
|
float speed_ = 1.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 跟随动作
|
||||||
|
*
|
||||||
|
* 使节点跟随另一个节点移动。
|
||||||
|
* 常用于相机跟随玩家。
|
||||||
|
*/
|
||||||
|
class Follow : public Action {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief 创建跟随动作
|
||||||
|
* @param followedNode 被跟随的节点
|
||||||
|
* @return 动作指针
|
||||||
|
*/
|
||||||
|
static Follow* create(Node* followedNode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 创建带边界的跟随动作
|
||||||
|
* @param followedNode 被跟随的节点
|
||||||
|
* @param boundary 边界矩形
|
||||||
|
* @return 动作指针
|
||||||
|
*/
|
||||||
|
static Follow* create(Node* followedNode, const Rect& boundary);
|
||||||
|
|
||||||
|
~Follow();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取被跟随的节点
|
||||||
|
* @return 被跟随的节点指针
|
||||||
|
*/
|
||||||
|
Node* getFollowedNode() const { return followedNode_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检查是否设置了边界
|
||||||
|
* @return true 如果设置了边界
|
||||||
|
*/
|
||||||
|
bool isBoundarySet() const { return boundarySet_; }
|
||||||
|
|
||||||
|
void startWithTarget(Node* target) override;
|
||||||
|
void stop() override;
|
||||||
|
void step(float dt) override;
|
||||||
|
bool isDone() const override;
|
||||||
|
Action* clone() const override;
|
||||||
|
Action* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Follow() = default;
|
||||||
|
|
||||||
|
Node* followedNode_ = nullptr;
|
||||||
|
Rect boundary_;
|
||||||
|
bool boundarySet_ = false;
|
||||||
|
Vec2 halfScreenSize_;
|
||||||
|
Vec2 fullScreenSize_;
|
||||||
|
Vec2 leftBoundary_;
|
||||||
|
Vec2 rightBoundary_;
|
||||||
|
Vec2 topBoundary_;
|
||||||
|
Vec2 bottomBoundary_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 目标动作
|
||||||
|
*
|
||||||
|
* 允许在一个节点上运行动作,但目标为另一个节点。
|
||||||
|
*/
|
||||||
|
class TargetedAction : public Action {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief 创建目标动作
|
||||||
|
* @param target 目标节点
|
||||||
|
* @param action 要运行的动作
|
||||||
|
* @return 动作指针
|
||||||
|
*/
|
||||||
|
static TargetedAction* create(Node* target, FiniteTimeAction* action);
|
||||||
|
|
||||||
|
~TargetedAction();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取目标节点
|
||||||
|
* @return 目标节点指针
|
||||||
|
*/
|
||||||
|
Node* getTargetNode() const { return targetNode_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置目标节点
|
||||||
|
* @param target 目标节点
|
||||||
|
*/
|
||||||
|
void setTargetNode(Node* target) { targetNode_ = target; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取内部动作
|
||||||
|
* @return 内部动作指针
|
||||||
|
*/
|
||||||
|
FiniteTimeAction* getAction() const { return innerAction_; }
|
||||||
|
|
||||||
|
void startWithTarget(Node* target) override;
|
||||||
|
void stop() override;
|
||||||
|
void step(float dt) override;
|
||||||
|
bool isDone() const override;
|
||||||
|
Action* clone() const override;
|
||||||
|
Action* reverse() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TargetedAction() = default;
|
||||||
|
|
||||||
|
Node* targetNode_ = nullptr;
|
||||||
|
FiniteTimeAction* innerAction_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -1,278 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "extra2d/action/action.h"
|
|
||||||
#include "extra2d/core/math_types.h"
|
|
||||||
#include <functional>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
// Interval Action Base
|
|
||||||
class IntervalAction : public Action {
|
|
||||||
public:
|
|
||||||
explicit IntervalAction(float duration);
|
|
||||||
bool isDone() const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Instant Action Base
|
|
||||||
class InstantAction : public Action {
|
|
||||||
public:
|
|
||||||
InstantAction();
|
|
||||||
bool isDone() const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Move Actions
|
|
||||||
class MoveBy : public IntervalAction {
|
|
||||||
public:
|
|
||||||
MoveBy(float duration, const Vec2 &delta);
|
|
||||||
|
|
||||||
Action *clone() const override;
|
|
||||||
Action *reverse() const override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void onStart() override;
|
|
||||||
void onUpdate(float progress) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Vec2 delta_;
|
|
||||||
Vec2 startPosition_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MoveTo : public IntervalAction {
|
|
||||||
public:
|
|
||||||
MoveTo(float duration, const Vec2 &position);
|
|
||||||
|
|
||||||
Action *clone() const override;
|
|
||||||
Action *reverse() const override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void onStart() override;
|
|
||||||
void onUpdate(float progress) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Vec2 endPosition_;
|
|
||||||
Vec2 startPosition_;
|
|
||||||
Vec2 delta_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Scale Actions
|
|
||||||
class ScaleBy : public IntervalAction {
|
|
||||||
public:
|
|
||||||
ScaleBy(float duration, float scale);
|
|
||||||
ScaleBy(float duration, float scaleX, float scaleY);
|
|
||||||
ScaleBy(float duration, const Vec2 &scale);
|
|
||||||
|
|
||||||
Action *clone() const override;
|
|
||||||
Action *reverse() const override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void onStart() override;
|
|
||||||
void onUpdate(float progress) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Vec2 deltaScale_;
|
|
||||||
Vec2 startScale_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ScaleTo : public IntervalAction {
|
|
||||||
public:
|
|
||||||
ScaleTo(float duration, float scale);
|
|
||||||
ScaleTo(float duration, float scaleX, float scaleY);
|
|
||||||
ScaleTo(float duration, const Vec2 &scale);
|
|
||||||
|
|
||||||
Action *clone() const override;
|
|
||||||
Action *reverse() const override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void onStart() override;
|
|
||||||
void onUpdate(float progress) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Vec2 endScale_;
|
|
||||||
Vec2 startScale_;
|
|
||||||
Vec2 delta_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Rotate Actions
|
|
||||||
class RotateBy : public IntervalAction {
|
|
||||||
public:
|
|
||||||
RotateBy(float duration, float deltaAngle);
|
|
||||||
RotateBy(float duration, float deltaAngleX, float deltaAngleY);
|
|
||||||
|
|
||||||
Action *clone() const override;
|
|
||||||
Action *reverse() const override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void onStart() override;
|
|
||||||
void onUpdate(float progress) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
float deltaAngle_ = 0.0f;
|
|
||||||
float startAngle_ = 0.0f;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RotateTo : public IntervalAction {
|
|
||||||
public:
|
|
||||||
RotateTo(float duration, float angle);
|
|
||||||
RotateTo(float duration, float angleX, float angleY);
|
|
||||||
|
|
||||||
Action *clone() const override;
|
|
||||||
Action *reverse() const override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void onStart() override;
|
|
||||||
void onUpdate(float progress) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
float endAngle_ = 0.0f;
|
|
||||||
float startAngle_ = 0.0f;
|
|
||||||
float deltaAngle_ = 0.0f;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Fade Actions
|
|
||||||
class FadeIn : public IntervalAction {
|
|
||||||
public:
|
|
||||||
explicit FadeIn(float duration);
|
|
||||||
|
|
||||||
Action *clone() const override;
|
|
||||||
Action *reverse() const override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void onStart() override;
|
|
||||||
void onUpdate(float progress) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
float startOpacity_ = 0.0f;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FadeOut : public IntervalAction {
|
|
||||||
public:
|
|
||||||
explicit FadeOut(float duration);
|
|
||||||
|
|
||||||
Action *clone() const override;
|
|
||||||
Action *reverse() const override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void onStart() override;
|
|
||||||
void onUpdate(float progress) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
float startOpacity_ = 0.0f;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FadeTo : public IntervalAction {
|
|
||||||
public:
|
|
||||||
FadeTo(float duration, float opacity);
|
|
||||||
|
|
||||||
Action *clone() const override;
|
|
||||||
Action *reverse() const override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void onStart() override;
|
|
||||||
void onUpdate(float progress) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
float endOpacity_ = 0.0f;
|
|
||||||
float startOpacity_ = 0.0f;
|
|
||||||
float deltaOpacity_ = 0.0f;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Composite Actions
|
|
||||||
class Sequence : public IntervalAction {
|
|
||||||
public:
|
|
||||||
Sequence(const std::vector<Action *> &actions);
|
|
||||||
~Sequence();
|
|
||||||
|
|
||||||
Action *clone() const override;
|
|
||||||
Action *reverse() const override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void onStart() override;
|
|
||||||
void onUpdate(float progress) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<Action *> actions_;
|
|
||||||
int currentIndex_ = 0;
|
|
||||||
float split_ = 0.0f;
|
|
||||||
float last_ = 0.0f;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Spawn : public IntervalAction {
|
|
||||||
public:
|
|
||||||
Spawn(const std::vector<Action *> &actions);
|
|
||||||
~Spawn();
|
|
||||||
|
|
||||||
Action *clone() const override;
|
|
||||||
Action *reverse() const override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void onStart() override;
|
|
||||||
void onUpdate(float progress) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<Action *> actions_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Loop Action
|
|
||||||
class Loop : public Action {
|
|
||||||
public:
|
|
||||||
Loop(Action *action, int times = -1);
|
|
||||||
~Loop();
|
|
||||||
|
|
||||||
bool isDone() const override;
|
|
||||||
Action *clone() const override;
|
|
||||||
Action *reverse() const override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void onStart() override;
|
|
||||||
void onUpdate(float progress) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Action *action_ = nullptr;
|
|
||||||
int times_ = 1;
|
|
||||||
int currentTimes_ = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Delay Action
|
|
||||||
class Delay : public IntervalAction {
|
|
||||||
public:
|
|
||||||
explicit Delay(float duration);
|
|
||||||
|
|
||||||
Action *clone() const override;
|
|
||||||
Action *reverse() const override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void onUpdate(float progress) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
// CallFunc Action
|
|
||||||
class CallFunc : public InstantAction {
|
|
||||||
public:
|
|
||||||
using Callback = std::function<void()>;
|
|
||||||
|
|
||||||
explicit CallFunc(Callback callback);
|
|
||||||
|
|
||||||
Action *clone() const override;
|
|
||||||
Action *reverse() const override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void onUpdate(float progress) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Callback callback_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper functions
|
|
||||||
inline Sequence *sequence(const std::vector<Action *> &actions) {
|
|
||||||
return new Sequence(actions);
|
|
||||||
}
|
|
||||||
inline Spawn *spawn(const std::vector<Action *> &actions) {
|
|
||||||
return new Spawn(actions);
|
|
||||||
}
|
|
||||||
inline Loop *loop(Action *action, int times = -1) {
|
|
||||||
return new Loop(action, times);
|
|
||||||
}
|
|
||||||
inline Delay *delay(float duration) { return new Delay(duration); }
|
|
||||||
inline CallFunc *callFunc(CallFunc::Callback callback) {
|
|
||||||
return new CallFunc(std::move(callback));
|
|
||||||
}
|
|
||||||
} // namespace extra2d
|
|
||||||
|
|
@ -1,67 +1,101 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
// Easing function type
|
|
||||||
|
/**
|
||||||
|
* @brief 缓动函数类型
|
||||||
|
*/
|
||||||
using EaseFunction = float (*)(float);
|
using EaseFunction = float (*)(float);
|
||||||
|
|
||||||
// Linear (no easing)
|
// ============================================================================
|
||||||
|
// 线性缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 线性缓动(无缓动)
|
||||||
|
* @param t 归一化时间 [0, 1]
|
||||||
|
* @return 缓动后的值
|
||||||
|
*/
|
||||||
float easeLinear(float t);
|
float easeLinear(float t);
|
||||||
|
|
||||||
// Quadratic
|
// ============================================================================
|
||||||
|
// 二次缓动 (Quad)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
float easeInQuad(float t);
|
float easeInQuad(float t);
|
||||||
float easeOutQuad(float t);
|
float easeOutQuad(float t);
|
||||||
float easeInOutQuad(float t);
|
float easeInOutQuad(float t);
|
||||||
|
|
||||||
// Cubic
|
// ============================================================================
|
||||||
|
// 三次缓动 (Cubic)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
float easeInCubic(float t);
|
float easeInCubic(float t);
|
||||||
float easeOutCubic(float t);
|
float easeOutCubic(float t);
|
||||||
float easeInOutCubic(float t);
|
float easeInOutCubic(float t);
|
||||||
|
|
||||||
// Quartic
|
// ============================================================================
|
||||||
|
// 四次缓动 (Quart)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
float easeInQuart(float t);
|
float easeInQuart(float t);
|
||||||
float easeOutQuart(float t);
|
float easeOutQuart(float t);
|
||||||
float easeInOutQuart(float t);
|
float easeInOutQuart(float t);
|
||||||
|
|
||||||
// Quintic
|
// ============================================================================
|
||||||
|
// 五次缓动 (Quint)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
float easeInQuint(float t);
|
float easeInQuint(float t);
|
||||||
float easeOutQuint(float t);
|
float easeOutQuint(float t);
|
||||||
float easeInOutQuint(float t);
|
float easeInOutQuint(float t);
|
||||||
|
|
||||||
// Sine
|
// ============================================================================
|
||||||
|
// 正弦缓动 (Sine)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
float easeInSine(float t);
|
float easeInSine(float t);
|
||||||
float easeOutSine(float t);
|
float easeOutSine(float t);
|
||||||
float easeInOutSine(float t);
|
float easeInOutSine(float t);
|
||||||
|
|
||||||
// Exponential
|
// ============================================================================
|
||||||
|
// 指数缓动 (Exponential)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
float easeInExpo(float t);
|
float easeInExpo(float t);
|
||||||
float easeOutExpo(float t);
|
float easeOutExpo(float t);
|
||||||
float easeInOutExpo(float t);
|
float easeInOutExpo(float t);
|
||||||
|
|
||||||
// Circular
|
// ============================================================================
|
||||||
|
// 圆形缓动 (Circular)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
float easeInCirc(float t);
|
float easeInCirc(float t);
|
||||||
float easeOutCirc(float t);
|
float easeOutCirc(float t);
|
||||||
float easeInOutCirc(float t);
|
float easeInOutCirc(float t);
|
||||||
|
|
||||||
// Back
|
// ============================================================================
|
||||||
|
// 回震缓动 (Back)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
float easeInBack(float t);
|
float easeInBack(float t);
|
||||||
float easeOutBack(float t);
|
float easeOutBack(float t);
|
||||||
float easeInOutBack(float t);
|
float easeInOutBack(float t);
|
||||||
|
|
||||||
// Elastic
|
// ============================================================================
|
||||||
|
// 弹性缓动 (Elastic)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
float easeInElastic(float t);
|
float easeInElastic(float t);
|
||||||
float easeOutElastic(float t);
|
float easeOutElastic(float t);
|
||||||
float easeInOutElastic(float t);
|
float easeInOutElastic(float t);
|
||||||
|
|
||||||
// Bounce
|
// ============================================================================
|
||||||
|
// 弹跳缓动 (Bounce)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
float easeInBounce(float t);
|
float easeInBounce(float t);
|
||||||
float easeOutBounce(float t);
|
float easeOutBounce(float t);
|
||||||
float easeInOutBounce(float t);
|
float easeInOutBounce(float t);
|
||||||
|
|
||||||
// Ease Action wrapper
|
|
||||||
class Action;
|
|
||||||
|
|
||||||
class EaseAction {
|
|
||||||
public:
|
|
||||||
static Action *create(Action *action, EaseFunction easeFunc);
|
|
||||||
};
|
|
||||||
} // namespace extra2d
|
} // namespace extra2d
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <extra2d/action/action.h>
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 有限时间动作基类
|
||||||
|
*
|
||||||
|
* 所有具有持续时间的动作的基类。
|
||||||
|
* 继承自 Action,添加了持续时间属性。
|
||||||
|
*/
|
||||||
|
class FiniteTimeAction : public Action {
|
||||||
|
public:
|
||||||
|
FiniteTimeAction() = default;
|
||||||
|
explicit FiniteTimeAction(float duration);
|
||||||
|
virtual ~FiniteTimeAction() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取动作持续时间
|
||||||
|
* @return 持续时间(秒)
|
||||||
|
*/
|
||||||
|
float getDuration() const { return duration_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置动作持续时间
|
||||||
|
* @param duration 持续时间(秒)
|
||||||
|
*/
|
||||||
|
void setDuration(float duration) { duration_ = duration; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 克隆动作
|
||||||
|
* @return 动作的深拷贝
|
||||||
|
*/
|
||||||
|
FiniteTimeAction* clone() const override = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 创建反向动作
|
||||||
|
* @return 反向动作
|
||||||
|
*/
|
||||||
|
FiniteTimeAction* reverse() const override = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
float duration_ = 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -6,6 +6,40 @@
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
|
/// RGB 颜色(字节,每通道 0-255)
|
||||||
|
struct Color3B {
|
||||||
|
uint8_t r = 255;
|
||||||
|
uint8_t g = 255;
|
||||||
|
uint8_t b = 255;
|
||||||
|
|
||||||
|
constexpr Color3B() = default;
|
||||||
|
constexpr Color3B(uint8_t r, uint8_t g, uint8_t b) : r(r), g(g), b(b) {}
|
||||||
|
|
||||||
|
constexpr bool operator==(const Color3B& other) const {
|
||||||
|
return r == other.r && g == other.g && b == other.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator!=(const Color3B& other) const {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color3B operator+(const Color3B& other) const {
|
||||||
|
return Color3B(
|
||||||
|
static_cast<uint8_t>(std::min(255, static_cast<int>(r) + other.r)),
|
||||||
|
static_cast<uint8_t>(std::min(255, static_cast<int>(g) + other.g)),
|
||||||
|
static_cast<uint8_t>(std::min(255, static_cast<int>(b) + other.b))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color3B operator-(const Color3B& other) const {
|
||||||
|
return Color3B(
|
||||||
|
static_cast<uint8_t>(std::max(0, static_cast<int>(r) - other.r)),
|
||||||
|
static_cast<uint8_t>(std::max(0, static_cast<int>(g) - other.g)),
|
||||||
|
static_cast<uint8_t>(std::max(0, static_cast<int>(b) - other.b))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// RGBA 颜色(浮点数,每通道 0.0 - 1.0)
|
/// RGBA 颜色(浮点数,每通道 0.0 - 1.0)
|
||||||
struct Color {
|
struct Color {
|
||||||
float r = 0.0f;
|
float r = 0.0f;
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,14 @@
|
||||||
|
|
||||||
// Action
|
// Action
|
||||||
#include <extra2d/action/action.h>
|
#include <extra2d/action/action.h>
|
||||||
#include <extra2d/action/actions.h>
|
#include <extra2d/action/finite_time_action.h>
|
||||||
|
#include <extra2d/action/action_interval.h>
|
||||||
|
#include <extra2d/action/action_instant.h>
|
||||||
|
#include <extra2d/action/action_interval_actions.h>
|
||||||
|
#include <extra2d/action/action_instant_actions.h>
|
||||||
|
#include <extra2d/action/action_ease.h>
|
||||||
|
#include <extra2d/action/action_special.h>
|
||||||
|
#include <extra2d/action/action_manager.h>
|
||||||
#include <extra2d/action/ease.h>
|
#include <extra2d/action/ease.h>
|
||||||
|
|
||||||
// Event
|
// Event
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,25 @@ public:
|
||||||
void setVisible(bool visible);
|
void setVisible(bool visible);
|
||||||
bool isVisible() const { return visible_; }
|
bool isVisible() const { return visible_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置颜色
|
||||||
|
* @param color RGB颜色
|
||||||
|
*/
|
||||||
|
void setColor(const Color3B& color);
|
||||||
|
Color3B getColor() const { return color_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置X轴翻转
|
||||||
|
*/
|
||||||
|
void setFlipX(bool flipX);
|
||||||
|
bool isFlipX() const { return flipX_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置Y轴翻转
|
||||||
|
*/
|
||||||
|
void setFlipY(bool flipY);
|
||||||
|
bool isFlipY() const { return flipY_; }
|
||||||
|
|
||||||
void setZOrder(int zOrder);
|
void setZOrder(int zOrder);
|
||||||
int getZOrder() const { return zOrder_; }
|
int getZOrder() const { return zOrder_; }
|
||||||
|
|
||||||
|
|
@ -139,12 +158,54 @@ public:
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// 动作系统
|
// 动作系统
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
void runAction(Ptr<Action> action);
|
/**
|
||||||
|
* @brief 运行动作
|
||||||
|
* @param action 动作指针(所有权转移)
|
||||||
|
* @return 动作指针
|
||||||
|
*/
|
||||||
|
Action* runAction(Action* action);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 停止所有动作
|
||||||
|
*/
|
||||||
void stopAllActions();
|
void stopAllActions();
|
||||||
void stopAction(Ptr<Action> action);
|
|
||||||
|
/**
|
||||||
|
* @brief 停止指定动作
|
||||||
|
* @param action 动作指针
|
||||||
|
*/
|
||||||
|
void stopAction(Action* action);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 根据标签停止动作
|
||||||
|
* @param tag 标签值
|
||||||
|
*/
|
||||||
void stopActionByTag(int tag);
|
void stopActionByTag(int tag);
|
||||||
Ptr<Action> getActionByTag(int tag) const;
|
|
||||||
size_t getActionCount() const { return actions_.size(); }
|
/**
|
||||||
|
* @brief 根据标志位停止动作
|
||||||
|
* @param flags 标志位
|
||||||
|
*/
|
||||||
|
void stopActionsByFlags(unsigned int flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 根据标签获取动作
|
||||||
|
* @param tag 标签值
|
||||||
|
* @return 动作指针,未找到返回 nullptr
|
||||||
|
*/
|
||||||
|
Action* getActionByTag(int tag);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取运行中的动作数量
|
||||||
|
* @return 动作数量
|
||||||
|
*/
|
||||||
|
size_t getActionCount() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检查是否有动作在运行
|
||||||
|
* @return true 如果有动作在运行
|
||||||
|
*/
|
||||||
|
bool isRunningActions() const;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// 事件系统
|
// 事件系统
|
||||||
|
|
@ -198,14 +259,10 @@ private:
|
||||||
std::unordered_map<std::string, WeakPtr<Node>> nameIndex_; // 56 bytes
|
std::unordered_map<std::string, WeakPtr<Node>> nameIndex_; // 56 bytes
|
||||||
std::unordered_map<int, WeakPtr<Node>> tagIndex_; // 56 bytes
|
std::unordered_map<int, WeakPtr<Node>> tagIndex_; // 56 bytes
|
||||||
|
|
||||||
// 4. 动作系统(使用 unordered_map 加速 tag 查找)
|
// 4. 事件分发器
|
||||||
std::unordered_map<int, Ptr<Action>> actionByTag_; // 56 bytes
|
|
||||||
std::vector<Ptr<Action>> actions_; // 24 bytes(无 tag 的 Action)
|
|
||||||
|
|
||||||
// 5. 事件分发器
|
|
||||||
EventDispatcher eventDispatcher_; // 大小取决于实现
|
EventDispatcher eventDispatcher_; // 大小取决于实现
|
||||||
|
|
||||||
// 6. 父节点引用
|
// 5. 父节点引用
|
||||||
WeakPtr<Node> parent_; // 16 bytes
|
WeakPtr<Node> parent_; // 16 bytes
|
||||||
|
|
||||||
// 7. 变换属性(按访问频率分组)
|
// 7. 变换属性(按访问频率分组)
|
||||||
|
|
@ -221,10 +278,17 @@ private:
|
||||||
float rotation_ = 0.0f; // 4 bytes
|
float rotation_ = 0.0f; // 4 bytes
|
||||||
float opacity_ = 1.0f; // 4 bytes
|
float opacity_ = 1.0f; // 4 bytes
|
||||||
|
|
||||||
// 10. 整数属性
|
// 10. 颜色属性
|
||||||
|
Color3B color_ = Color3B(255, 255, 255); // 3 bytes
|
||||||
|
|
||||||
|
// 11. 整数属性
|
||||||
int zOrder_ = 0; // 4 bytes
|
int zOrder_ = 0; // 4 bytes
|
||||||
int tag_ = -1; // 4 bytes
|
int tag_ = -1; // 4 bytes
|
||||||
|
|
||||||
|
// 12. 布尔属性
|
||||||
|
bool flipX_ = false; // 1 byte
|
||||||
|
bool flipY_ = false; // 1 byte
|
||||||
|
|
||||||
// 11. 场景指针
|
// 11. 场景指针
|
||||||
Scene *scene_ = nullptr; // 8 bytes
|
Scene *scene_ = nullptr; // 8 bytes
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,67 +2,48 @@
|
||||||
#include "extra2d/scene/node.h"
|
#include "extra2d/scene/node.h"
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
Action::Action() : elapsed_(0.0f), duration_(0.0f), speed_(1.0f), tag_(-1) {}
|
|
||||||
|
|
||||||
void Action::start(Node *target) {
|
Action::Action() : tag_(-1), flags_(0) {}
|
||||||
target_ = target;
|
|
||||||
originalTarget_ = target;
|
bool Action::isDone() const {
|
||||||
elapsed_ = 0.0f;
|
return state_ == ActionState::Completed;
|
||||||
state_ = ActionState::Running;
|
}
|
||||||
onStart();
|
|
||||||
|
void Action::startWithTarget(Node* target) {
|
||||||
|
target_ = target;
|
||||||
|
originalTarget_ = target;
|
||||||
|
state_ = ActionState::Running;
|
||||||
|
onStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Action::stop() {
|
void Action::stop() {
|
||||||
target_ = nullptr;
|
target_ = nullptr;
|
||||||
state_ = ActionState::Completed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Action::update(float dt) {
|
|
||||||
if (state_ != ActionState::Running)
|
|
||||||
return;
|
|
||||||
|
|
||||||
step(dt);
|
|
||||||
|
|
||||||
if (isDone()) {
|
|
||||||
state_ = ActionState::Completed;
|
state_ = ActionState::Completed;
|
||||||
onComplete();
|
|
||||||
if (completionCallback_)
|
|
||||||
completionCallback_();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Action::step(float dt) {
|
void Action::step(float dt) {
|
||||||
if (state_ != ActionState::Running)
|
(void)dt;
|
||||||
return;
|
}
|
||||||
|
|
||||||
elapsed_ += dt * speed_;
|
void Action::update(float time) {
|
||||||
|
(void)time;
|
||||||
float progress = 0.0f;
|
|
||||||
if (duration_ > 0.0f) {
|
|
||||||
progress = std::min(1.0f, elapsed_ / duration_);
|
|
||||||
} else {
|
|
||||||
progress = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (progressCallback_)
|
|
||||||
progressCallback_(progress);
|
|
||||||
|
|
||||||
onUpdate(progress);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Action::pause() {
|
void Action::pause() {
|
||||||
if (state_ == ActionState::Running)
|
if (state_ == ActionState::Running) {
|
||||||
state_ = ActionState::Paused;
|
state_ = ActionState::Paused;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Action::resume() {
|
void Action::resume() {
|
||||||
if (state_ == ActionState::Paused)
|
if (state_ == ActionState::Paused) {
|
||||||
state_ = ActionState::Running;
|
state_ = ActionState::Running;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Action::restart() {
|
void Action::restart() {
|
||||||
elapsed_ = 0.0f;
|
state_ = ActionState::Running;
|
||||||
state_ = ActionState::Running;
|
onStart();
|
||||||
onStart();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace extra2d
|
} // namespace extra2d
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,683 @@
|
||||||
|
#include "extra2d/action/action_ease.h"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#ifndef M_PI
|
||||||
|
#define M_PI 3.14159265358979323846f
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// ActionEase 基类
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
ActionEase::~ActionEase() {
|
||||||
|
delete innerAction_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ActionEase::initWithAction(ActionInterval* action) {
|
||||||
|
if (!action) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
innerAction_ = action;
|
||||||
|
duration_ = action->getDuration();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionEase::startWithTarget(Node* target) {
|
||||||
|
ActionInterval::startWithTarget(target);
|
||||||
|
innerAction_->startWithTarget(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionEase::stop() {
|
||||||
|
innerAction_->stop();
|
||||||
|
ActionInterval::stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionEase::update(float time) {
|
||||||
|
innerAction_->update(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 指数缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
EaseExponentialIn* EaseExponentialIn::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseExponentialIn();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseExponentialIn::update(float time) {
|
||||||
|
innerAction_->update(easeInExpo(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseExponentialIn::clone() const {
|
||||||
|
return EaseExponentialIn::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseExponentialIn::reverse() const {
|
||||||
|
return EaseExponentialOut::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
EaseExponentialOut* EaseExponentialOut::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseExponentialOut();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseExponentialOut::update(float time) {
|
||||||
|
innerAction_->update(easeOutExpo(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseExponentialOut::clone() const {
|
||||||
|
return EaseExponentialOut::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseExponentialOut::reverse() const {
|
||||||
|
return EaseExponentialIn::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
EaseExponentialInOut* EaseExponentialInOut::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseExponentialInOut();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseExponentialInOut::update(float time) {
|
||||||
|
innerAction_->update(easeInOutExpo(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseExponentialInOut::clone() const {
|
||||||
|
return EaseExponentialInOut::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseExponentialInOut::reverse() const {
|
||||||
|
return EaseExponentialInOut::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 正弦缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
EaseSineIn* EaseSineIn::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseSineIn();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseSineIn::update(float time) {
|
||||||
|
innerAction_->update(easeInSine(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseSineIn::clone() const {
|
||||||
|
return EaseSineIn::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseSineIn::reverse() const {
|
||||||
|
return EaseSineOut::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
EaseSineOut* EaseSineOut::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseSineOut();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseSineOut::update(float time) {
|
||||||
|
innerAction_->update(easeOutSine(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseSineOut::clone() const {
|
||||||
|
return EaseSineOut::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseSineOut::reverse() const {
|
||||||
|
return EaseSineIn::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
EaseSineInOut* EaseSineInOut::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseSineInOut();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseSineInOut::update(float time) {
|
||||||
|
innerAction_->update(easeInOutSine(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseSineInOut::clone() const {
|
||||||
|
return EaseSineInOut::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseSineInOut::reverse() const {
|
||||||
|
return EaseSineInOut::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 弹性缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
EaseElasticIn* EaseElasticIn::create(ActionInterval* action, float period) {
|
||||||
|
auto* ease = new EaseElasticIn();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
ease->period_ = period;
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseElasticIn::update(float time) {
|
||||||
|
float newT = 0.0f;
|
||||||
|
if (time == 0.0f || time == 1.0f) {
|
||||||
|
newT = time;
|
||||||
|
} else {
|
||||||
|
float s = period_ / 4.0f;
|
||||||
|
time = time - 1.0f;
|
||||||
|
newT = -std::pow(2.0f, 10.0f * time) * std::sin((time - s) * M_PI * 2.0f / period_);
|
||||||
|
}
|
||||||
|
innerAction_->update(newT);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseElasticIn::clone() const {
|
||||||
|
return EaseElasticIn::create(innerAction_->clone(), period_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseElasticIn::reverse() const {
|
||||||
|
return EaseElasticOut::create(innerAction_->reverse(), period_);
|
||||||
|
}
|
||||||
|
|
||||||
|
EaseElasticOut* EaseElasticOut::create(ActionInterval* action, float period) {
|
||||||
|
auto* ease = new EaseElasticOut();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
ease->period_ = period;
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseElasticOut::update(float time) {
|
||||||
|
float newT = 0.0f;
|
||||||
|
if (time == 0.0f || time == 1.0f) {
|
||||||
|
newT = time;
|
||||||
|
} else {
|
||||||
|
float s = period_ / 4.0f;
|
||||||
|
newT = std::pow(2.0f, -10.0f * time) * std::sin((time - s) * M_PI * 2.0f / period_) + 1.0f;
|
||||||
|
}
|
||||||
|
innerAction_->update(newT);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseElasticOut::clone() const {
|
||||||
|
return EaseElasticOut::create(innerAction_->clone(), period_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseElasticOut::reverse() const {
|
||||||
|
return EaseElasticIn::create(innerAction_->reverse(), period_);
|
||||||
|
}
|
||||||
|
|
||||||
|
EaseElasticInOut* EaseElasticInOut::create(ActionInterval* action, float period) {
|
||||||
|
auto* ease = new EaseElasticInOut();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
ease->period_ = period;
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseElasticInOut::update(float time) {
|
||||||
|
float newT = 0.0f;
|
||||||
|
if (time == 0.0f || time == 1.0f) {
|
||||||
|
newT = time;
|
||||||
|
} else {
|
||||||
|
time = time * 2.0f;
|
||||||
|
if (period_ == 0.0f) {
|
||||||
|
period_ = 0.3f * 1.5f;
|
||||||
|
}
|
||||||
|
float s = period_ / 4.0f;
|
||||||
|
if (time < 1.0f) {
|
||||||
|
time -= 1.0f;
|
||||||
|
newT = -0.5f * std::pow(2.0f, 10.0f * time) * std::sin((time - s) * M_PI * 2.0f / period_);
|
||||||
|
} else {
|
||||||
|
time -= 1.0f;
|
||||||
|
newT = std::pow(2.0f, -10.0f * time) * std::sin((time - s) * M_PI * 2.0f / period_) * 0.5f + 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
innerAction_->update(newT);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseElasticInOut::clone() const {
|
||||||
|
return EaseElasticInOut::create(innerAction_->clone(), period_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseElasticInOut::reverse() const {
|
||||||
|
return EaseElasticInOut::create(innerAction_->reverse(), period_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 弹跳缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
EaseBounceIn* EaseBounceIn::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseBounceIn();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseBounceIn::update(float time) {
|
||||||
|
innerAction_->update(easeInBounce(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseBounceIn::clone() const {
|
||||||
|
return EaseBounceIn::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseBounceIn::reverse() const {
|
||||||
|
return EaseBounceOut::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
EaseBounceOut* EaseBounceOut::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseBounceOut();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseBounceOut::update(float time) {
|
||||||
|
innerAction_->update(easeOutBounce(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseBounceOut::clone() const {
|
||||||
|
return EaseBounceOut::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseBounceOut::reverse() const {
|
||||||
|
return EaseBounceIn::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
EaseBounceInOut* EaseBounceInOut::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseBounceInOut();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseBounceInOut::update(float time) {
|
||||||
|
innerAction_->update(easeInOutBounce(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseBounceInOut::clone() const {
|
||||||
|
return EaseBounceInOut::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseBounceInOut::reverse() const {
|
||||||
|
return EaseBounceInOut::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 回震缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
EaseBackIn* EaseBackIn::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseBackIn();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseBackIn::update(float time) {
|
||||||
|
innerAction_->update(easeInBack(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseBackIn::clone() const {
|
||||||
|
return EaseBackIn::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseBackIn::reverse() const {
|
||||||
|
return EaseBackOut::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
EaseBackOut* EaseBackOut::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseBackOut();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseBackOut::update(float time) {
|
||||||
|
innerAction_->update(easeOutBack(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseBackOut::clone() const {
|
||||||
|
return EaseBackOut::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseBackOut::reverse() const {
|
||||||
|
return EaseBackIn::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
EaseBackInOut* EaseBackInOut::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseBackInOut();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseBackInOut::update(float time) {
|
||||||
|
innerAction_->update(easeInOutBack(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseBackInOut::clone() const {
|
||||||
|
return EaseBackInOut::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseBackInOut::reverse() const {
|
||||||
|
return EaseBackInOut::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 二次缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
EaseQuadIn* EaseQuadIn::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseQuadIn();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseQuadIn::update(float time) {
|
||||||
|
innerAction_->update(easeInQuad(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseQuadIn::clone() const {
|
||||||
|
return EaseQuadIn::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseQuadIn::reverse() const {
|
||||||
|
return EaseQuadOut::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
EaseQuadOut* EaseQuadOut::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseQuadOut();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseQuadOut::update(float time) {
|
||||||
|
innerAction_->update(easeOutQuad(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseQuadOut::clone() const {
|
||||||
|
return EaseQuadOut::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseQuadOut::reverse() const {
|
||||||
|
return EaseQuadIn::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
EaseQuadInOut* EaseQuadInOut::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseQuadInOut();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseQuadInOut::update(float time) {
|
||||||
|
innerAction_->update(easeInOutQuad(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseQuadInOut::clone() const {
|
||||||
|
return EaseQuadInOut::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseQuadInOut::reverse() const {
|
||||||
|
return EaseQuadInOut::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 三次缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
EaseCubicIn* EaseCubicIn::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseCubicIn();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseCubicIn::update(float time) {
|
||||||
|
innerAction_->update(easeInCubic(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseCubicIn::clone() const {
|
||||||
|
return EaseCubicIn::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseCubicIn::reverse() const {
|
||||||
|
return EaseCubicOut::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
EaseCubicOut* EaseCubicOut::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseCubicOut();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseCubicOut::update(float time) {
|
||||||
|
innerAction_->update(easeOutCubic(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseCubicOut::clone() const {
|
||||||
|
return EaseCubicOut::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseCubicOut::reverse() const {
|
||||||
|
return EaseCubicIn::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
EaseCubicInOut* EaseCubicInOut::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseCubicInOut();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseCubicInOut::update(float time) {
|
||||||
|
innerAction_->update(easeInOutCubic(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseCubicInOut::clone() const {
|
||||||
|
return EaseCubicInOut::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseCubicInOut::reverse() const {
|
||||||
|
return EaseCubicInOut::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 四次缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
EaseQuartIn* EaseQuartIn::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseQuartIn();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseQuartIn::update(float time) {
|
||||||
|
innerAction_->update(easeInQuart(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseQuartIn::clone() const {
|
||||||
|
return EaseQuartIn::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseQuartIn::reverse() const {
|
||||||
|
return EaseQuartOut::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
EaseQuartOut* EaseQuartOut::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseQuartOut();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseQuartOut::update(float time) {
|
||||||
|
innerAction_->update(easeOutQuart(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseQuartOut::clone() const {
|
||||||
|
return EaseQuartOut::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseQuartOut::reverse() const {
|
||||||
|
return EaseQuartIn::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
EaseQuartInOut* EaseQuartInOut::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseQuartInOut();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseQuartInOut::update(float time) {
|
||||||
|
innerAction_->update(easeInOutQuart(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseQuartInOut::clone() const {
|
||||||
|
return EaseQuartInOut::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseQuartInOut::reverse() const {
|
||||||
|
return EaseQuartInOut::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 五次缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
EaseQuintIn* EaseQuintIn::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseQuintIn();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseQuintIn::update(float time) {
|
||||||
|
innerAction_->update(easeInQuint(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseQuintIn::clone() const {
|
||||||
|
return EaseQuintIn::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseQuintIn::reverse() const {
|
||||||
|
return EaseQuintOut::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
EaseQuintOut* EaseQuintOut::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseQuintOut();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseQuintOut::update(float time) {
|
||||||
|
innerAction_->update(easeOutQuint(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseQuintOut::clone() const {
|
||||||
|
return EaseQuintOut::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseQuintOut::reverse() const {
|
||||||
|
return EaseQuintIn::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
EaseQuintInOut* EaseQuintInOut::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseQuintInOut();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseQuintInOut::update(float time) {
|
||||||
|
innerAction_->update(easeInOutQuint(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseQuintInOut::clone() const {
|
||||||
|
return EaseQuintInOut::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseQuintInOut::reverse() const {
|
||||||
|
return EaseQuintInOut::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 圆形缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
EaseCircleIn* EaseCircleIn::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseCircleIn();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseCircleIn::update(float time) {
|
||||||
|
innerAction_->update(easeInCirc(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseCircleIn::clone() const {
|
||||||
|
return EaseCircleIn::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseCircleIn::reverse() const {
|
||||||
|
return EaseCircleOut::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
EaseCircleOut* EaseCircleOut::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseCircleOut();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseCircleOut::update(float time) {
|
||||||
|
innerAction_->update(easeOutCirc(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseCircleOut::clone() const {
|
||||||
|
return EaseCircleOut::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseCircleOut::reverse() const {
|
||||||
|
return EaseCircleIn::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
EaseCircleInOut* EaseCircleInOut::create(ActionInterval* action) {
|
||||||
|
auto* ease = new EaseCircleInOut();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseCircleInOut::update(float time) {
|
||||||
|
innerAction_->update(easeInOutCirc(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseCircleInOut::clone() const {
|
||||||
|
return EaseCircleInOut::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseCircleInOut::reverse() const {
|
||||||
|
return EaseCircleInOut::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 自定义缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
EaseCustom* EaseCustom::create(ActionInterval* action, EaseFunction easeFunc) {
|
||||||
|
auto* ease = new EaseCustom();
|
||||||
|
ease->initWithAction(action);
|
||||||
|
ease->easeFunc_ = easeFunc;
|
||||||
|
return ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EaseCustom::update(float time) {
|
||||||
|
if (easeFunc_) {
|
||||||
|
innerAction_->update(easeFunc_(time));
|
||||||
|
} else {
|
||||||
|
innerAction_->update(time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseCustom::clone() const {
|
||||||
|
return EaseCustom::create(innerAction_->clone(), easeFunc_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* EaseCustom::reverse() const {
|
||||||
|
return EaseCustom::create(innerAction_->reverse(), easeFunc_);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
#include "extra2d/action/action_instant.h"
|
||||||
|
#include "extra2d/scene/node.h"
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
ActionInstant::ActionInstant() {
|
||||||
|
duration_ = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ActionInstant::isDone() const {
|
||||||
|
return done_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionInstant::startWithTarget(Node* target) {
|
||||||
|
FiniteTimeAction::startWithTarget(target);
|
||||||
|
done_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionInstant::step(float dt) {
|
||||||
|
(void)dt;
|
||||||
|
if (state_ != ActionState::Running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
execute();
|
||||||
|
done_ = true;
|
||||||
|
state_ = ActionState::Completed;
|
||||||
|
onComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -0,0 +1,202 @@
|
||||||
|
#include "extra2d/action/action_instant_actions.h"
|
||||||
|
#include "extra2d/scene/node.h"
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 回调动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
CallFunc* CallFunc::create(const Callback& callback) {
|
||||||
|
auto* action = new CallFunc();
|
||||||
|
action->callback_ = callback;
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CallFunc::execute() {
|
||||||
|
if (callback_) {
|
||||||
|
callback_();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInstant* CallFunc::clone() const {
|
||||||
|
return CallFunc::create(callback_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInstant* CallFunc::reverse() const {
|
||||||
|
return CallFunc::create(callback_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// CallFuncN
|
||||||
|
CallFuncN* CallFuncN::create(const Callback& callback) {
|
||||||
|
auto* action = new CallFuncN();
|
||||||
|
action->callback_ = callback;
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CallFuncN::execute() {
|
||||||
|
if (callback_ && target_) {
|
||||||
|
callback_(target_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInstant* CallFuncN::clone() const {
|
||||||
|
return CallFuncN::create(callback_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInstant* CallFuncN::reverse() const {
|
||||||
|
return CallFuncN::create(callback_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 位置动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
Place* Place::create(const Vec2& position) {
|
||||||
|
auto* action = new Place();
|
||||||
|
action->position_ = position;
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Place::execute() {
|
||||||
|
if (target_) {
|
||||||
|
target_->setPosition(position_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInstant* Place::clone() const {
|
||||||
|
return Place::create(position_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInstant* Place::reverse() const {
|
||||||
|
return Place::create(position_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 翻转动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
FlipX* FlipX::create(bool flipX) {
|
||||||
|
auto* action = new FlipX();
|
||||||
|
action->flipX_ = flipX;
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlipX::execute() {
|
||||||
|
if (target_) {
|
||||||
|
target_->setFlipX(flipX_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInstant* FlipX::clone() const {
|
||||||
|
return FlipX::create(flipX_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInstant* FlipX::reverse() const {
|
||||||
|
return FlipX::create(!flipX_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FlipY
|
||||||
|
FlipY* FlipY::create(bool flipY) {
|
||||||
|
auto* action = new FlipY();
|
||||||
|
action->flipY_ = flipY;
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlipY::execute() {
|
||||||
|
if (target_) {
|
||||||
|
target_->setFlipY(flipY_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInstant* FlipY::clone() const {
|
||||||
|
return FlipY::create(flipY_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInstant* FlipY::reverse() const {
|
||||||
|
return FlipY::create(!flipY_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 可见性动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
Show* Show::create() {
|
||||||
|
return new Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Show::execute() {
|
||||||
|
if (target_) {
|
||||||
|
target_->setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInstant* Show::clone() const {
|
||||||
|
return Show::create();
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInstant* Show::reverse() const {
|
||||||
|
return Hide::create();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide
|
||||||
|
Hide* Hide::create() {
|
||||||
|
return new Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hide::execute() {
|
||||||
|
if (target_) {
|
||||||
|
target_->setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInstant* Hide::clone() const {
|
||||||
|
return Hide::create();
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInstant* Hide::reverse() const {
|
||||||
|
return Show::create();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToggleVisibility
|
||||||
|
ToggleVisibility* ToggleVisibility::create() {
|
||||||
|
return new ToggleVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToggleVisibility::execute() {
|
||||||
|
if (target_) {
|
||||||
|
target_->setVisible(!target_->isVisible());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInstant* ToggleVisibility::clone() const {
|
||||||
|
return ToggleVisibility::create();
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInstant* ToggleVisibility::reverse() const {
|
||||||
|
return ToggleVisibility::create();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 节点管理动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
RemoveSelf* RemoveSelf::create() {
|
||||||
|
return new RemoveSelf();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveSelf::execute() {
|
||||||
|
if (target_) {
|
||||||
|
target_->removeFromParent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInstant* RemoveSelf::clone() const {
|
||||||
|
return RemoveSelf::create();
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInstant* RemoveSelf::reverse() const {
|
||||||
|
return RemoveSelf::create();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
#include "extra2d/action/action_interval.h"
|
||||||
|
#include "extra2d/scene/node.h"
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
ActionInterval::ActionInterval(float duration)
|
||||||
|
: FiniteTimeAction(duration) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ActionInterval::isDone() const {
|
||||||
|
return elapsed_ >= duration_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionInterval::startWithTarget(Node* target) {
|
||||||
|
FiniteTimeAction::startWithTarget(target);
|
||||||
|
elapsed_ = 0.0f;
|
||||||
|
firstTick_ = true;
|
||||||
|
onStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionInterval::stop() {
|
||||||
|
FiniteTimeAction::stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionInterval::step(float dt) {
|
||||||
|
if (state_ != ActionState::Running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstTick_) {
|
||||||
|
firstTick_ = false;
|
||||||
|
elapsed_ = 0.0f;
|
||||||
|
} else {
|
||||||
|
elapsed_ += dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
float progress = 0.0f;
|
||||||
|
if (duration_ > 0.0f) {
|
||||||
|
progress = std::min(1.0f, elapsed_ / duration_);
|
||||||
|
} else {
|
||||||
|
progress = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (easeFunc_) {
|
||||||
|
progress = easeFunc_(progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
onUpdate(progress);
|
||||||
|
|
||||||
|
if (progress >= 1.0f) {
|
||||||
|
state_ = ActionState::Completed;
|
||||||
|
onComplete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -0,0 +1,787 @@
|
||||||
|
#include "extra2d/action/action_interval_actions.h"
|
||||||
|
#include "extra2d/scene/node.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdarg>
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 移动动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
MoveBy* MoveBy::create(float duration, const Vec2& delta) {
|
||||||
|
auto* action = new MoveBy();
|
||||||
|
action->duration_ = duration;
|
||||||
|
action->delta_ = delta;
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoveBy::onStart() {
|
||||||
|
startPosition_ = target_->getPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoveBy::onUpdate(float progress) {
|
||||||
|
Vec2 newPos = startPosition_ + delta_ * progress;
|
||||||
|
target_->setPosition(newPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* MoveBy::clone() const {
|
||||||
|
return MoveBy::create(duration_, delta_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* MoveBy::reverse() const {
|
||||||
|
return MoveBy::create(duration_, -delta_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// MoveTo
|
||||||
|
MoveTo* MoveTo::create(float duration, const Vec2& position) {
|
||||||
|
auto* action = new MoveTo();
|
||||||
|
action->duration_ = duration;
|
||||||
|
action->endPosition_ = position;
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoveTo::onStart() {
|
||||||
|
startPosition_ = target_->getPosition();
|
||||||
|
delta_ = endPosition_ - startPosition_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoveTo::onUpdate(float progress) {
|
||||||
|
Vec2 newPos = startPosition_ + delta_ * progress;
|
||||||
|
target_->setPosition(newPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* MoveTo::clone() const {
|
||||||
|
return MoveTo::create(duration_, endPosition_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* MoveTo::reverse() const {
|
||||||
|
return MoveTo::create(duration_, startPosition_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 跳跃动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
JumpBy* JumpBy::create(float duration, const Vec2& position, float height, int jumps) {
|
||||||
|
auto* action = new JumpBy();
|
||||||
|
action->duration_ = duration;
|
||||||
|
action->delta_ = position;
|
||||||
|
action->height_ = height;
|
||||||
|
action->jumps_ = jumps;
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JumpBy::onStart() {
|
||||||
|
startPosition_ = target_->getPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JumpBy::onUpdate(float progress) {
|
||||||
|
float frac = (progress * jumps_) - static_cast<int>(progress * jumps_);
|
||||||
|
float y = height_ * 4.0f * frac * (1.0f - frac);
|
||||||
|
y += delta_.y * progress;
|
||||||
|
float x = delta_.x * progress;
|
||||||
|
target_->setPosition(startPosition_ + Vec2(x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* JumpBy::clone() const {
|
||||||
|
return JumpBy::create(duration_, delta_, height_, jumps_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* JumpBy::reverse() const {
|
||||||
|
return JumpBy::create(duration_, -delta_, height_, jumps_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// JumpTo
|
||||||
|
JumpTo* JumpTo::create(float duration, const Vec2& position, float height, int jumps) {
|
||||||
|
auto* action = new JumpTo();
|
||||||
|
action->duration_ = duration;
|
||||||
|
action->endPosition_ = position;
|
||||||
|
action->height_ = height;
|
||||||
|
action->jumps_ = jumps;
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JumpTo::onStart() {
|
||||||
|
JumpBy::onStart();
|
||||||
|
delta_ = endPosition_ - startPosition_;
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* JumpTo::clone() const {
|
||||||
|
return JumpTo::create(duration_, endPosition_, height_, jumps_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* JumpTo::reverse() const {
|
||||||
|
return JumpTo::create(duration_, startPosition_, height_, jumps_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 贝塞尔曲线动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
BezierBy* BezierBy::create(float duration, const BezierConfig& config) {
|
||||||
|
auto* action = new BezierBy();
|
||||||
|
action->duration_ = duration;
|
||||||
|
action->config_ = config;
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BezierBy::onStart() {
|
||||||
|
startPosition_ = target_->getPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BezierBy::onUpdate(float progress) {
|
||||||
|
float xa = startPosition_.x;
|
||||||
|
float xb = config_.controlPoint1.x;
|
||||||
|
float xc = config_.controlPoint2.x;
|
||||||
|
float xd = config_.endPosition.x;
|
||||||
|
|
||||||
|
float ya = startPosition_.y;
|
||||||
|
float yb = config_.controlPoint1.y;
|
||||||
|
float yc = config_.controlPoint2.y;
|
||||||
|
float yd = config_.endPosition.y;
|
||||||
|
|
||||||
|
float x = bezierat(xa, xb, xc, xd, progress);
|
||||||
|
float y = bezierat(ya, yb, yc, yd, progress);
|
||||||
|
|
||||||
|
target_->setPosition(Vec2(x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* BezierBy::clone() const {
|
||||||
|
return BezierBy::create(duration_, config_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* BezierBy::reverse() const {
|
||||||
|
BezierConfig rev;
|
||||||
|
rev.controlPoint1 = config_.controlPoint2 + config_.endPosition;
|
||||||
|
rev.controlPoint2 = config_.controlPoint1 + config_.endPosition;
|
||||||
|
rev.endPosition = config_.endPosition;
|
||||||
|
return BezierBy::create(duration_, rev);
|
||||||
|
}
|
||||||
|
|
||||||
|
float BezierBy::bezierat(float a, float b, float c, float d, float t) {
|
||||||
|
return (powf(1 - t, 3) * a +
|
||||||
|
3.0f * t * powf(1 - t, 2) * b +
|
||||||
|
3.0f * t * t * (1 - t) * c +
|
||||||
|
t * t * t * d);
|
||||||
|
}
|
||||||
|
|
||||||
|
// BezierTo
|
||||||
|
BezierTo* BezierTo::create(float duration, const BezierConfig& config) {
|
||||||
|
auto* action = new BezierTo();
|
||||||
|
action->duration_ = duration;
|
||||||
|
action->originalConfig_ = config;
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BezierTo::onStart() {
|
||||||
|
BezierBy::onStart();
|
||||||
|
config_.controlPoint1 = originalConfig_.controlPoint1 - startPosition_;
|
||||||
|
config_.controlPoint2 = originalConfig_.controlPoint2 - startPosition_;
|
||||||
|
config_.endPosition = originalConfig_.endPosition - startPosition_;
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* BezierTo::clone() const {
|
||||||
|
return BezierTo::create(duration_, originalConfig_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* BezierTo::reverse() const {
|
||||||
|
BezierConfig rev;
|
||||||
|
rev.controlPoint1 = originalConfig_.controlPoint2;
|
||||||
|
rev.controlPoint2 = originalConfig_.controlPoint1;
|
||||||
|
rev.endPosition = startPosition_;
|
||||||
|
return BezierTo::create(duration_, rev);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 缩放动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
ScaleBy* ScaleBy::create(float duration, float scale) {
|
||||||
|
return create(duration, scale, scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScaleBy* ScaleBy::create(float duration, float scaleX, float scaleY) {
|
||||||
|
auto* action = new ScaleBy();
|
||||||
|
action->duration_ = duration;
|
||||||
|
action->deltaScale_ = Vec2(scaleX - 1.0f, scaleY - 1.0f);
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScaleBy* ScaleBy::create(float duration, const Vec2& scale) {
|
||||||
|
return create(duration, scale.x, scale.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScaleBy::onStart() {
|
||||||
|
startScale_ = target_->getScale();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScaleBy::onUpdate(float progress) {
|
||||||
|
Vec2 newScale = startScale_ + deltaScale_ * progress;
|
||||||
|
target_->setScale(newScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* ScaleBy::clone() const {
|
||||||
|
return ScaleBy::create(duration_, Vec2(startScale_.x + deltaScale_.x, startScale_.y + deltaScale_.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* ScaleBy::reverse() const {
|
||||||
|
return ScaleBy::create(duration_, Vec2(startScale_.x - deltaScale_.x, startScale_.y - deltaScale_.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScaleTo
|
||||||
|
ScaleTo* ScaleTo::create(float duration, float scale) {
|
||||||
|
return create(duration, scale, scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScaleTo* ScaleTo::create(float duration, float scaleX, float scaleY) {
|
||||||
|
auto* action = new ScaleTo();
|
||||||
|
action->duration_ = duration;
|
||||||
|
action->endScale_ = Vec2(scaleX, scaleY);
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScaleTo* ScaleTo::create(float duration, const Vec2& scale) {
|
||||||
|
return create(duration, scale.x, scale.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScaleTo::onStart() {
|
||||||
|
startScale_ = target_->getScale();
|
||||||
|
delta_ = endScale_ - startScale_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScaleTo::onUpdate(float progress) {
|
||||||
|
Vec2 newScale = startScale_ + delta_ * progress;
|
||||||
|
target_->setScale(newScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* ScaleTo::clone() const {
|
||||||
|
return ScaleTo::create(duration_, endScale_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* ScaleTo::reverse() const {
|
||||||
|
return ScaleTo::create(duration_, startScale_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 旋转动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
RotateBy* RotateBy::create(float duration, float deltaAngle) {
|
||||||
|
auto* action = new RotateBy();
|
||||||
|
action->duration_ = duration;
|
||||||
|
action->deltaAngle_ = deltaAngle;
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RotateBy::onStart() {
|
||||||
|
startAngle_ = target_->getRotation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RotateBy::onUpdate(float progress) {
|
||||||
|
float newAngle = startAngle_ + deltaAngle_ * progress;
|
||||||
|
target_->setRotation(newAngle);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* RotateBy::clone() const {
|
||||||
|
return RotateBy::create(duration_, deltaAngle_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* RotateBy::reverse() const {
|
||||||
|
return RotateBy::create(duration_, -deltaAngle_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// RotateTo
|
||||||
|
RotateTo* RotateTo::create(float duration, float angle) {
|
||||||
|
auto* action = new RotateTo();
|
||||||
|
action->duration_ = duration;
|
||||||
|
action->endAngle_ = angle;
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RotateTo::onStart() {
|
||||||
|
startAngle_ = target_->getRotation();
|
||||||
|
deltaAngle_ = endAngle_ - startAngle_;
|
||||||
|
|
||||||
|
if (deltaAngle_ > 180.0f) deltaAngle_ -= 360.0f;
|
||||||
|
if (deltaAngle_ < -180.0f) deltaAngle_ += 360.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RotateTo::onUpdate(float progress) {
|
||||||
|
float newAngle = startAngle_ + deltaAngle_ * progress;
|
||||||
|
target_->setRotation(newAngle);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* RotateTo::clone() const {
|
||||||
|
return RotateTo::create(duration_, endAngle_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* RotateTo::reverse() const {
|
||||||
|
return RotateTo::create(duration_, startAngle_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 淡入淡出动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
FadeIn* FadeIn::create(float duration) {
|
||||||
|
auto* action = new FadeIn();
|
||||||
|
action->duration_ = duration;
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FadeIn::onStart() {
|
||||||
|
startOpacity_ = target_->getOpacity();
|
||||||
|
target_->setOpacity(0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FadeIn::onUpdate(float progress) {
|
||||||
|
target_->setOpacity(progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* FadeIn::clone() const {
|
||||||
|
return FadeIn::create(duration_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* FadeIn::reverse() const {
|
||||||
|
return FadeOut::create(duration_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FadeOut
|
||||||
|
FadeOut* FadeOut::create(float duration) {
|
||||||
|
auto* action = new FadeOut();
|
||||||
|
action->duration_ = duration;
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FadeOut::onStart() {
|
||||||
|
startOpacity_ = target_->getOpacity();
|
||||||
|
target_->setOpacity(1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FadeOut::onUpdate(float progress) {
|
||||||
|
target_->setOpacity(1.0f - progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* FadeOut::clone() const {
|
||||||
|
return FadeOut::create(duration_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* FadeOut::reverse() const {
|
||||||
|
return FadeIn::create(duration_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FadeTo
|
||||||
|
FadeTo* FadeTo::create(float duration, float opacity) {
|
||||||
|
auto* action = new FadeTo();
|
||||||
|
action->duration_ = duration;
|
||||||
|
action->endOpacity_ = opacity;
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FadeTo::onStart() {
|
||||||
|
startOpacity_ = target_->getOpacity();
|
||||||
|
deltaOpacity_ = endOpacity_ - startOpacity_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FadeTo::onUpdate(float progress) {
|
||||||
|
target_->setOpacity(startOpacity_ + deltaOpacity_ * progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* FadeTo::clone() const {
|
||||||
|
return FadeTo::create(duration_, endOpacity_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* FadeTo::reverse() const {
|
||||||
|
return FadeTo::create(duration_, startOpacity_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 闪烁动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
Blink* Blink::create(float duration, int times) {
|
||||||
|
auto* action = new Blink();
|
||||||
|
action->duration_ = duration;
|
||||||
|
action->times_ = times;
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Blink::onStart() {
|
||||||
|
originalVisible_ = target_->isVisible();
|
||||||
|
currentTimes_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Blink::onUpdate(float progress) {
|
||||||
|
float slice = 1.0f / times_;
|
||||||
|
float m = fmodf(progress, slice);
|
||||||
|
target_->setVisible(m > slice / 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* Blink::clone() const {
|
||||||
|
return Blink::create(duration_, times_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* Blink::reverse() const {
|
||||||
|
return Blink::create(duration_, times_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 色调动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
TintTo* TintTo::create(float duration, uint8_t red, uint8_t green, uint8_t blue) {
|
||||||
|
auto* action = new TintTo();
|
||||||
|
action->duration_ = duration;
|
||||||
|
action->endColor_ = Color3B(red, green, blue);
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TintTo::onStart() {
|
||||||
|
startColor_ = target_->getColor();
|
||||||
|
deltaColor_ = Color3B(
|
||||||
|
static_cast<int16_t>(endColor_.r) - static_cast<int16_t>(startColor_.r),
|
||||||
|
static_cast<int16_t>(endColor_.g) - static_cast<int16_t>(startColor_.g),
|
||||||
|
static_cast<int16_t>(endColor_.b) - static_cast<int16_t>(startColor_.b)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TintTo::onUpdate(float progress) {
|
||||||
|
Color3B newColor(
|
||||||
|
static_cast<uint8_t>(startColor_.r + deltaColor_.r * progress),
|
||||||
|
static_cast<uint8_t>(startColor_.g + deltaColor_.g * progress),
|
||||||
|
static_cast<uint8_t>(startColor_.b + deltaColor_.b * progress)
|
||||||
|
);
|
||||||
|
target_->setColor(newColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* TintTo::clone() const {
|
||||||
|
return TintTo::create(duration_, endColor_.r, endColor_.g, endColor_.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* TintTo::reverse() const {
|
||||||
|
return TintTo::create(duration_, startColor_.r, startColor_.g, startColor_.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TintBy
|
||||||
|
TintBy* TintBy::create(float duration, int16_t deltaRed, int16_t deltaGreen, int16_t deltaBlue) {
|
||||||
|
auto* action = new TintBy();
|
||||||
|
action->duration_ = duration;
|
||||||
|
action->deltaR_ = deltaRed;
|
||||||
|
action->deltaG_ = deltaGreen;
|
||||||
|
action->deltaB_ = deltaBlue;
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TintBy::onStart() {
|
||||||
|
startColor_ = target_->getColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TintBy::onUpdate(float progress) {
|
||||||
|
Color3B newColor(
|
||||||
|
static_cast<uint8_t>(startColor_.r + deltaR_ * progress),
|
||||||
|
static_cast<uint8_t>(startColor_.g + deltaG_ * progress),
|
||||||
|
static_cast<uint8_t>(startColor_.b + deltaB_ * progress)
|
||||||
|
);
|
||||||
|
target_->setColor(newColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* TintBy::clone() const {
|
||||||
|
return TintBy::create(duration_, deltaR_, deltaG_, deltaB_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* TintBy::reverse() const {
|
||||||
|
return TintBy::create(duration_, -deltaR_, -deltaG_, -deltaB_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 组合动作
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
Sequence* Sequence::create(ActionInterval* action1, ...) {
|
||||||
|
std::vector<ActionInterval*> actions;
|
||||||
|
actions.push_back(action1);
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, action1);
|
||||||
|
ActionInterval* action = nullptr;
|
||||||
|
while ((action = va_arg(args, ActionInterval*)) != nullptr) {
|
||||||
|
actions.push_back(action);
|
||||||
|
}
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return create(actions);
|
||||||
|
}
|
||||||
|
|
||||||
|
Sequence* Sequence::create(const std::vector<ActionInterval*>& actions) {
|
||||||
|
auto* seq = new Sequence();
|
||||||
|
seq->duration_ = 0.0f;
|
||||||
|
|
||||||
|
for (auto* action : actions) {
|
||||||
|
if (action) {
|
||||||
|
seq->actions_.push_back(action);
|
||||||
|
seq->duration_ += action->getDuration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sequence::~Sequence() {
|
||||||
|
for (auto* action : actions_) {
|
||||||
|
delete action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sequence::onStart() {
|
||||||
|
currentIndex_ = 0;
|
||||||
|
split_ = 0.0f;
|
||||||
|
last_ = -1.0f;
|
||||||
|
|
||||||
|
if (!actions_.empty()) {
|
||||||
|
actions_[0]->startWithTarget(target_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sequence::onUpdate(float progress) {
|
||||||
|
float newTime = progress * duration_;
|
||||||
|
|
||||||
|
if (newTime < last_) {
|
||||||
|
for (auto* action : actions_) {
|
||||||
|
action->stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last_ = newTime;
|
||||||
|
|
||||||
|
float foundSplit = 0.0f;
|
||||||
|
size_t found = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < actions_.size(); ++i) {
|
||||||
|
foundSplit += actions_[i]->getDuration();
|
||||||
|
if (foundSplit > newTime) {
|
||||||
|
found = i;
|
||||||
|
break;
|
||||||
|
} else if (foundSplit == newTime) {
|
||||||
|
found = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found != currentIndex_) {
|
||||||
|
if (currentIndex_ < actions_.size()) {
|
||||||
|
actions_[currentIndex_]->update(1.0f);
|
||||||
|
}
|
||||||
|
if (found < actions_.size()) {
|
||||||
|
actions_[found]->startWithTarget(target_);
|
||||||
|
}
|
||||||
|
currentIndex_ = found;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentIndex_ < actions_.size()) {
|
||||||
|
float localTime = newTime - (foundSplit - actions_[currentIndex_]->getDuration());
|
||||||
|
float localProgress = actions_[currentIndex_]->getDuration() > 0.0f
|
||||||
|
? localTime / actions_[currentIndex_]->getDuration() : 1.0f;
|
||||||
|
actions_[currentIndex_]->update(localProgress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* Sequence::clone() const {
|
||||||
|
std::vector<ActionInterval*> cloned;
|
||||||
|
for (auto* action : actions_) {
|
||||||
|
cloned.push_back(action->clone());
|
||||||
|
}
|
||||||
|
return Sequence::create(cloned);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* Sequence::reverse() const {
|
||||||
|
std::vector<ActionInterval*> rev;
|
||||||
|
for (auto it = actions_.rbegin(); it != actions_.rend(); ++it) {
|
||||||
|
rev.push_back((*it)->reverse());
|
||||||
|
}
|
||||||
|
return Sequence::create(rev);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawn
|
||||||
|
Spawn* Spawn::create(ActionInterval* action1, ...) {
|
||||||
|
std::vector<ActionInterval*> actions;
|
||||||
|
actions.push_back(action1);
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, action1);
|
||||||
|
ActionInterval* action = nullptr;
|
||||||
|
while ((action = va_arg(args, ActionInterval*)) != nullptr) {
|
||||||
|
actions.push_back(action);
|
||||||
|
}
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return create(actions);
|
||||||
|
}
|
||||||
|
|
||||||
|
Spawn* Spawn::create(const std::vector<ActionInterval*>& actions) {
|
||||||
|
auto* spawn = new Spawn();
|
||||||
|
spawn->duration_ = 0.0f;
|
||||||
|
|
||||||
|
for (auto* action : actions) {
|
||||||
|
if (action) {
|
||||||
|
spawn->actions_.push_back(action);
|
||||||
|
spawn->duration_ = std::max(spawn->duration_, action->getDuration());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return spawn;
|
||||||
|
}
|
||||||
|
|
||||||
|
Spawn::~Spawn() {
|
||||||
|
for (auto* action : actions_) {
|
||||||
|
delete action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Spawn::onStart() {
|
||||||
|
for (auto* action : actions_) {
|
||||||
|
action->startWithTarget(target_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Spawn::onUpdate(float progress) {
|
||||||
|
for (auto* action : actions_) {
|
||||||
|
float localProgress = action->getDuration() > 0.0f
|
||||||
|
? std::min(1.0f, (progress * duration_) / action->getDuration())
|
||||||
|
: 1.0f;
|
||||||
|
action->update(localProgress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* Spawn::clone() const {
|
||||||
|
std::vector<ActionInterval*> cloned;
|
||||||
|
for (auto* action : actions_) {
|
||||||
|
cloned.push_back(action->clone());
|
||||||
|
}
|
||||||
|
return Spawn::create(cloned);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* Spawn::reverse() const {
|
||||||
|
std::vector<ActionInterval*> rev;
|
||||||
|
for (auto* action : actions_) {
|
||||||
|
rev.push_back(action->reverse());
|
||||||
|
}
|
||||||
|
return Spawn::create(rev);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repeat
|
||||||
|
Repeat* Repeat::create(ActionInterval* action, int times) {
|
||||||
|
auto* repeat = new Repeat();
|
||||||
|
repeat->innerAction_ = action;
|
||||||
|
repeat->times_ = times;
|
||||||
|
repeat->duration_ = action->getDuration() * times;
|
||||||
|
return repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* Repeat::clone() const {
|
||||||
|
return Repeat::create(innerAction_->clone(), times_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* Repeat::reverse() const {
|
||||||
|
return Repeat::create(innerAction_->reverse(), times_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Repeat::isDone() const {
|
||||||
|
return currentTimes_ >= times_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Repeat::onStart() {
|
||||||
|
currentTimes_ = 0;
|
||||||
|
innerAction_->startWithTarget(target_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Repeat::onUpdate(float progress) {
|
||||||
|
float t = progress * times_;
|
||||||
|
int current = static_cast<int>(t);
|
||||||
|
|
||||||
|
if (current > currentTimes_) {
|
||||||
|
innerAction_->update(1.0f);
|
||||||
|
currentTimes_++;
|
||||||
|
if (currentTimes_ < times_) {
|
||||||
|
innerAction_->startWithTarget(target_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentTimes_ < times_) {
|
||||||
|
innerAction_->update(t - current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepeatForever
|
||||||
|
RepeatForever* RepeatForever::create(ActionInterval* action) {
|
||||||
|
auto* repeat = new RepeatForever();
|
||||||
|
repeat->innerAction_ = action;
|
||||||
|
repeat->duration_ = action->getDuration();
|
||||||
|
return repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* RepeatForever::clone() const {
|
||||||
|
return RepeatForever::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* RepeatForever::reverse() const {
|
||||||
|
return RepeatForever::create(innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RepeatForever::isDone() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RepeatForever::onStart() {
|
||||||
|
innerAction_->startWithTarget(target_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RepeatForever::onUpdate(float progress) {
|
||||||
|
innerAction_->update(progress);
|
||||||
|
if (innerAction_->isDone()) {
|
||||||
|
innerAction_->startWithTarget(target_);
|
||||||
|
elapsed_ = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelayTime
|
||||||
|
DelayTime* DelayTime::create(float duration) {
|
||||||
|
auto* delay = new DelayTime();
|
||||||
|
delay->duration_ = duration;
|
||||||
|
return delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* DelayTime::clone() const {
|
||||||
|
return DelayTime::create(duration_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* DelayTime::reverse() const {
|
||||||
|
return DelayTime::create(duration_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReverseTime
|
||||||
|
ReverseTime* ReverseTime::create(ActionInterval* action) {
|
||||||
|
auto* rev = new ReverseTime();
|
||||||
|
rev->innerAction_ = action;
|
||||||
|
rev->duration_ = action->getDuration();
|
||||||
|
return rev;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReverseTime::~ReverseTime() {
|
||||||
|
delete innerAction_;
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* ReverseTime::clone() const {
|
||||||
|
return ReverseTime::create(innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionInterval* ReverseTime::reverse() const {
|
||||||
|
return innerAction_->clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReverseTime::onStart() {
|
||||||
|
innerAction_->startWithTarget(target_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReverseTime::onUpdate(float progress) {
|
||||||
|
innerAction_->update(1.0f - progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -0,0 +1,244 @@
|
||||||
|
#include "extra2d/action/action_manager.h"
|
||||||
|
#include "extra2d/scene/node.h"
|
||||||
|
#include "extra2d/utils/logger.h"
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
ActionManager* ActionManager::instance_ = nullptr;
|
||||||
|
|
||||||
|
ActionManager::ActionManager() {}
|
||||||
|
|
||||||
|
ActionManager::~ActionManager() {
|
||||||
|
removeAllActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionManager* ActionManager::getInstance() {
|
||||||
|
if (!instance_) {
|
||||||
|
instance_ = new ActionManager();
|
||||||
|
}
|
||||||
|
return instance_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::destroyInstance() {
|
||||||
|
if (instance_) {
|
||||||
|
delete instance_;
|
||||||
|
instance_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::addAction(Action* action, Node* target, bool paused) {
|
||||||
|
if (!action || !target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = targets_.find(target);
|
||||||
|
if (it == targets_.end()) {
|
||||||
|
ActionElement element;
|
||||||
|
element.target = target;
|
||||||
|
element.paused = paused;
|
||||||
|
targets_[target] = element;
|
||||||
|
it = targets_.find(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& element = it->second;
|
||||||
|
element.actions.push_back(action);
|
||||||
|
action->startWithTarget(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::removeAction(Action* action) {
|
||||||
|
if (!action) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* target = action->getOriginalTarget();
|
||||||
|
if (!target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = targets_.find(target);
|
||||||
|
if (it == targets_.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& element = it->second;
|
||||||
|
for (size_t i = 0; i < element.actions.size(); ++i) {
|
||||||
|
if (element.actions[i] == action) {
|
||||||
|
removeActionAt(i, element);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::removeActionByTag(int tag, Node* target) {
|
||||||
|
if (!target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = targets_.find(target);
|
||||||
|
if (it == targets_.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& element = it->second;
|
||||||
|
for (size_t i = 0; i < element.actions.size(); ++i) {
|
||||||
|
if (element.actions[i]->getTag() == tag) {
|
||||||
|
removeActionAt(i, element);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::removeActionsByFlags(unsigned int flags, Node* target) {
|
||||||
|
if (!target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = targets_.find(target);
|
||||||
|
if (it == targets_.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& element = it->second;
|
||||||
|
for (int i = static_cast<int>(element.actions.size()) - 1; i >= 0; --i) {
|
||||||
|
if (element.actions[i]->getFlags() & flags) {
|
||||||
|
removeActionAt(i, element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::removeAllActionsFromTarget(Node* target) {
|
||||||
|
if (!target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = targets_.find(target);
|
||||||
|
if (it == targets_.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& element = it->second;
|
||||||
|
for (auto* action : element.actions) {
|
||||||
|
action->stop();
|
||||||
|
deleteAction(action);
|
||||||
|
}
|
||||||
|
element.actions.clear();
|
||||||
|
targets_.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::removeAllActions() {
|
||||||
|
for (auto& pair : targets_) {
|
||||||
|
auto& element = pair.second;
|
||||||
|
for (auto* action : element.actions) {
|
||||||
|
action->stop();
|
||||||
|
deleteAction(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
targets_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Action* ActionManager::getActionByTag(int tag, Node* target) {
|
||||||
|
if (!target) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = targets_.find(target);
|
||||||
|
if (it == targets_.end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& element = it->second;
|
||||||
|
for (auto* action : element.actions) {
|
||||||
|
if (action->getTag() == tag) {
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ActionManager::getActionCount(Node* target) const {
|
||||||
|
auto it = targets_.find(target);
|
||||||
|
if (it == targets_.end()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return it->second.actions.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::pauseTarget(Node* target) {
|
||||||
|
auto it = targets_.find(target);
|
||||||
|
if (it != targets_.end()) {
|
||||||
|
it->second.paused = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::resumeTarget(Node* target) {
|
||||||
|
auto it = targets_.find(target);
|
||||||
|
if (it != targets_.end()) {
|
||||||
|
it->second.paused = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ActionManager::isPaused(Node* target) const {
|
||||||
|
auto it = targets_.find(target);
|
||||||
|
if (it == targets_.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return it->second.paused;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::update(float dt) {
|
||||||
|
for (auto it = targets_.begin(); it != targets_.end(); ) {
|
||||||
|
auto& element = it->second;
|
||||||
|
Node* target = element.target;
|
||||||
|
|
||||||
|
if (!element.paused && target) {
|
||||||
|
element.actionIndex = 0;
|
||||||
|
while (static_cast<size_t>(element.actionIndex) < element.actions.size()) {
|
||||||
|
element.currentAction = element.actions[element.actionIndex];
|
||||||
|
element.currentActionSalvaged = false;
|
||||||
|
|
||||||
|
if (element.currentAction->getState() != ActionState::Paused) {
|
||||||
|
element.currentAction->step(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.currentActionSalvaged) {
|
||||||
|
deleteAction(element.currentAction);
|
||||||
|
} else if (element.currentAction->isDone()) {
|
||||||
|
element.currentAction->stop();
|
||||||
|
deleteAction(element.currentAction);
|
||||||
|
element.actions.erase(element.actions.begin() + element.actionIndex);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
element.actionIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.actions.empty()) {
|
||||||
|
it = targets_.erase(it);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::removeActionAt(size_t index, ActionElement& element) {
|
||||||
|
if (index >= element.actions.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Action* action = element.actions[index];
|
||||||
|
if (action == element.currentAction) {
|
||||||
|
element.currentActionSalvaged = true;
|
||||||
|
}
|
||||||
|
action->stop();
|
||||||
|
deleteAction(action);
|
||||||
|
element.actions.erase(element.actions.begin() + index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::deleteAction(Action* action) {
|
||||||
|
if (action) {
|
||||||
|
delete action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -0,0 +1,172 @@
|
||||||
|
#include "extra2d/action/action_special.h"
|
||||||
|
#include "extra2d/scene/node.h"
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Speed
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
Speed* Speed::create(ActionInterval* action, float speed) {
|
||||||
|
auto* speedAction = new Speed();
|
||||||
|
speedAction->innerAction_ = action;
|
||||||
|
speedAction->speed_ = speed;
|
||||||
|
return speedAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
Speed::~Speed() {
|
||||||
|
delete innerAction_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Speed::startWithTarget(Node* target) {
|
||||||
|
Action::startWithTarget(target);
|
||||||
|
innerAction_->startWithTarget(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Speed::stop() {
|
||||||
|
innerAction_->stop();
|
||||||
|
Action::stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Speed::step(float dt) {
|
||||||
|
if (state_ != ActionState::Running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
innerAction_->step(dt * speed_);
|
||||||
|
if (innerAction_->isDone()) {
|
||||||
|
state_ = ActionState::Completed;
|
||||||
|
onComplete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Speed::isDone() const {
|
||||||
|
return innerAction_->isDone();
|
||||||
|
}
|
||||||
|
|
||||||
|
Action* Speed::clone() const {
|
||||||
|
return Speed::create(innerAction_->clone(), speed_);
|
||||||
|
}
|
||||||
|
|
||||||
|
Action* Speed::reverse() const {
|
||||||
|
return Speed::create(innerAction_->reverse(), speed_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Follow
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
Follow* Follow::create(Node* followedNode) {
|
||||||
|
return create(followedNode, Rect::Zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
Follow* Follow::create(Node* followedNode, const Rect& boundary) {
|
||||||
|
auto* follow = new Follow();
|
||||||
|
follow->followedNode_ = followedNode;
|
||||||
|
follow->boundary_ = boundary;
|
||||||
|
follow->boundarySet_ = (boundary != Rect::Zero());
|
||||||
|
return follow;
|
||||||
|
}
|
||||||
|
|
||||||
|
Follow::~Follow() {
|
||||||
|
followedNode_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Follow::startWithTarget(Node* target) {
|
||||||
|
Action::startWithTarget(target);
|
||||||
|
if (target && followedNode_) {
|
||||||
|
halfScreenSize_ = Vec2(0, 0);
|
||||||
|
fullScreenSize_ = Vec2(0, 0);
|
||||||
|
|
||||||
|
if (boundarySet_) {
|
||||||
|
leftBoundary_ = Vec2(boundary_.origin.x, 0);
|
||||||
|
rightBoundary_ = Vec2(boundary_.origin.x + boundary_.size.width, 0);
|
||||||
|
topBoundary_ = Vec2(0, boundary_.origin.y);
|
||||||
|
bottomBoundary_ = Vec2(0, boundary_.origin.y + boundary_.size.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Follow::stop() {
|
||||||
|
followedNode_ = nullptr;
|
||||||
|
Action::stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Follow::step(float dt) {
|
||||||
|
(void)dt;
|
||||||
|
if (state_ != ActionState::Running || !followedNode_ || !target_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 pos = followedNode_->getPosition();
|
||||||
|
|
||||||
|
if (boundarySet_) {
|
||||||
|
pos.x = std::clamp(pos.x, leftBoundary_.x, rightBoundary_.x);
|
||||||
|
pos.y = std::clamp(pos.y, bottomBoundary_.y, topBoundary_.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
target_->setPosition(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Follow::isDone() const {
|
||||||
|
return followedNode_ == nullptr || !followedNode_->isRunning();
|
||||||
|
}
|
||||||
|
|
||||||
|
Action* Follow::clone() const {
|
||||||
|
return Follow::create(followedNode_, boundary_);
|
||||||
|
}
|
||||||
|
|
||||||
|
Action* Follow::reverse() const {
|
||||||
|
return Follow::create(followedNode_, boundary_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// TargetedAction
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
TargetedAction* TargetedAction::create(Node* target, FiniteTimeAction* action) {
|
||||||
|
auto* targeted = new TargetedAction();
|
||||||
|
targeted->targetNode_ = target;
|
||||||
|
targeted->innerAction_ = action;
|
||||||
|
return targeted;
|
||||||
|
}
|
||||||
|
|
||||||
|
TargetedAction::~TargetedAction() {
|
||||||
|
delete innerAction_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TargetedAction::startWithTarget(Node* target) {
|
||||||
|
Action::startWithTarget(target);
|
||||||
|
if (targetNode_) {
|
||||||
|
innerAction_->startWithTarget(targetNode_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TargetedAction::stop() {
|
||||||
|
innerAction_->stop();
|
||||||
|
Action::stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TargetedAction::step(float dt) {
|
||||||
|
if (state_ != ActionState::Running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
innerAction_->step(dt);
|
||||||
|
if (innerAction_->isDone()) {
|
||||||
|
state_ = ActionState::Completed;
|
||||||
|
onComplete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TargetedAction::isDone() const {
|
||||||
|
return innerAction_->isDone();
|
||||||
|
}
|
||||||
|
|
||||||
|
Action* TargetedAction::clone() const {
|
||||||
|
return TargetedAction::create(targetNode_, innerAction_->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
Action* TargetedAction::reverse() const {
|
||||||
|
return TargetedAction::create(targetNode_, innerAction_->reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -1,405 +0,0 @@
|
||||||
#include "extra2d/action/actions.h"
|
|
||||||
#include "extra2d/scene/node.h"
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
// IntervalAction
|
|
||||||
IntervalAction::IntervalAction(float duration) { duration_ = duration; }
|
|
||||||
|
|
||||||
bool IntervalAction::isDone() const { return elapsed_ >= duration_; }
|
|
||||||
|
|
||||||
// InstantAction
|
|
||||||
InstantAction::InstantAction() { duration_ = 0.0f; }
|
|
||||||
|
|
||||||
bool InstantAction::isDone() const { return true; }
|
|
||||||
|
|
||||||
// MoveBy
|
|
||||||
MoveBy::MoveBy(float duration, const Vec2 &delta)
|
|
||||||
: IntervalAction(duration), delta_(delta) {}
|
|
||||||
|
|
||||||
void MoveBy::onStart() { startPosition_ = target_->getPosition(); }
|
|
||||||
|
|
||||||
void MoveBy::onUpdate(float progress) {
|
|
||||||
Vec2 newPos = startPosition_ + delta_ * progress;
|
|
||||||
target_->setPosition(newPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
Action *MoveBy::clone() const { return new MoveBy(duration_, delta_); }
|
|
||||||
|
|
||||||
Action *MoveBy::reverse() const { return new MoveBy(duration_, -delta_); }
|
|
||||||
|
|
||||||
// MoveTo
|
|
||||||
MoveTo::MoveTo(float duration, const Vec2 &position)
|
|
||||||
: IntervalAction(duration), endPosition_(position) {}
|
|
||||||
|
|
||||||
void MoveTo::onStart() {
|
|
||||||
startPosition_ = target_->getPosition();
|
|
||||||
delta_ = endPosition_ - startPosition_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MoveTo::onUpdate(float progress) {
|
|
||||||
Vec2 newPos = startPosition_ + delta_ * progress;
|
|
||||||
target_->setPosition(newPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
Action *MoveTo::clone() const { return new MoveTo(duration_, endPosition_); }
|
|
||||||
|
|
||||||
Action *MoveTo::reverse() const {
|
|
||||||
return new MoveTo(duration_, startPosition_);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScaleBy
|
|
||||||
ScaleBy::ScaleBy(float duration, float scale)
|
|
||||||
: IntervalAction(duration), deltaScale_(scale - 1.0f, scale - 1.0f) {}
|
|
||||||
|
|
||||||
ScaleBy::ScaleBy(float duration, float scaleX, float scaleY)
|
|
||||||
: IntervalAction(duration), deltaScale_(scaleX - 1.0f, scaleY - 1.0f) {}
|
|
||||||
|
|
||||||
ScaleBy::ScaleBy(float duration, const Vec2 &scale)
|
|
||||||
: IntervalAction(duration), deltaScale_(scale.x - 1.0f, scale.y - 1.0f) {}
|
|
||||||
|
|
||||||
void ScaleBy::onStart() { startScale_ = target_->getScale(); }
|
|
||||||
|
|
||||||
void ScaleBy::onUpdate(float progress) {
|
|
||||||
Vec2 newScale = startScale_ + deltaScale_ * progress;
|
|
||||||
target_->setScale(newScale);
|
|
||||||
}
|
|
||||||
|
|
||||||
Action *ScaleBy::clone() const {
|
|
||||||
return new ScaleBy(duration_, Vec2(startScale_.x + deltaScale_.x,
|
|
||||||
startScale_.y + deltaScale_.y));
|
|
||||||
}
|
|
||||||
|
|
||||||
Action *ScaleBy::reverse() const {
|
|
||||||
return new ScaleBy(duration_, Vec2(startScale_.x - deltaScale_.x,
|
|
||||||
startScale_.y - deltaScale_.y));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScaleTo
|
|
||||||
ScaleTo::ScaleTo(float duration, float scale)
|
|
||||||
: IntervalAction(duration), endScale_(scale, scale) {}
|
|
||||||
|
|
||||||
ScaleTo::ScaleTo(float duration, float scaleX, float scaleY)
|
|
||||||
: IntervalAction(duration), endScale_(scaleX, scaleY) {}
|
|
||||||
|
|
||||||
ScaleTo::ScaleTo(float duration, const Vec2 &scale)
|
|
||||||
: IntervalAction(duration), endScale_(scale) {}
|
|
||||||
|
|
||||||
void ScaleTo::onStart() {
|
|
||||||
startScale_ = target_->getScale();
|
|
||||||
delta_ = endScale_ - startScale_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScaleTo::onUpdate(float progress) {
|
|
||||||
Vec2 newScale = startScale_ + delta_ * progress;
|
|
||||||
target_->setScale(newScale);
|
|
||||||
}
|
|
||||||
|
|
||||||
Action *ScaleTo::clone() const { return new ScaleTo(duration_, endScale_); }
|
|
||||||
|
|
||||||
Action *ScaleTo::reverse() const { return new ScaleTo(duration_, startScale_); }
|
|
||||||
|
|
||||||
// RotateBy
|
|
||||||
RotateBy::RotateBy(float duration, float deltaAngle)
|
|
||||||
: IntervalAction(duration), deltaAngle_(deltaAngle) {}
|
|
||||||
|
|
||||||
RotateBy::RotateBy(float duration, float deltaAngleX, float deltaAngleY)
|
|
||||||
: IntervalAction(duration), deltaAngle_(deltaAngleX) {
|
|
||||||
(void)deltaAngleY;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RotateBy::onStart() { startAngle_ = target_->getRotation(); }
|
|
||||||
|
|
||||||
void RotateBy::onUpdate(float progress) {
|
|
||||||
float newAngle = startAngle_ + deltaAngle_ * progress;
|
|
||||||
target_->setRotation(newAngle);
|
|
||||||
}
|
|
||||||
|
|
||||||
Action *RotateBy::clone() const { return new RotateBy(duration_, deltaAngle_); }
|
|
||||||
|
|
||||||
Action *RotateBy::reverse() const {
|
|
||||||
return new RotateBy(duration_, -deltaAngle_);
|
|
||||||
}
|
|
||||||
|
|
||||||
// RotateTo
|
|
||||||
RotateTo::RotateTo(float duration, float angle)
|
|
||||||
: IntervalAction(duration), endAngle_(angle) {}
|
|
||||||
|
|
||||||
RotateTo::RotateTo(float duration, float angleX, float angleY)
|
|
||||||
: IntervalAction(duration), endAngle_(angleX) {
|
|
||||||
(void)angleY;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RotateTo::onStart() {
|
|
||||||
startAngle_ = target_->getRotation();
|
|
||||||
deltaAngle_ = endAngle_ - startAngle_;
|
|
||||||
|
|
||||||
// Shortest path
|
|
||||||
if (deltaAngle_ > 180.0f)
|
|
||||||
deltaAngle_ -= 360.0f;
|
|
||||||
if (deltaAngle_ < -180.0f)
|
|
||||||
deltaAngle_ += 360.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RotateTo::onUpdate(float progress) {
|
|
||||||
float newAngle = startAngle_ + deltaAngle_ * progress;
|
|
||||||
target_->setRotation(newAngle);
|
|
||||||
}
|
|
||||||
|
|
||||||
Action *RotateTo::clone() const { return new RotateTo(duration_, endAngle_); }
|
|
||||||
|
|
||||||
Action *RotateTo::reverse() const {
|
|
||||||
return new RotateTo(duration_, startAngle_);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FadeIn
|
|
||||||
FadeIn::FadeIn(float duration) : IntervalAction(duration) {}
|
|
||||||
|
|
||||||
void FadeIn::onStart() {
|
|
||||||
startOpacity_ = target_->getOpacity();
|
|
||||||
target_->setOpacity(0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FadeIn::onUpdate(float progress) { target_->setOpacity(progress); }
|
|
||||||
|
|
||||||
Action *FadeIn::clone() const { return new FadeIn(duration_); }
|
|
||||||
|
|
||||||
Action *FadeIn::reverse() const { return new FadeOut(duration_); }
|
|
||||||
|
|
||||||
// FadeOut
|
|
||||||
FadeOut::FadeOut(float duration) : IntervalAction(duration) {}
|
|
||||||
|
|
||||||
void FadeOut::onStart() {
|
|
||||||
startOpacity_ = target_->getOpacity();
|
|
||||||
target_->setOpacity(1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FadeOut::onUpdate(float progress) { target_->setOpacity(1.0f - progress); }
|
|
||||||
|
|
||||||
Action *FadeOut::clone() const { return new FadeOut(duration_); }
|
|
||||||
|
|
||||||
Action *FadeOut::reverse() const { return new FadeIn(duration_); }
|
|
||||||
|
|
||||||
// FadeTo
|
|
||||||
FadeTo::FadeTo(float duration, float opacity)
|
|
||||||
: IntervalAction(duration), endOpacity_(opacity) {}
|
|
||||||
|
|
||||||
void FadeTo::onStart() {
|
|
||||||
startOpacity_ = target_->getOpacity();
|
|
||||||
deltaOpacity_ = endOpacity_ - startOpacity_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FadeTo::onUpdate(float progress) {
|
|
||||||
target_->setOpacity(startOpacity_ + deltaOpacity_ * progress);
|
|
||||||
}
|
|
||||||
|
|
||||||
Action *FadeTo::clone() const { return new FadeTo(duration_, endOpacity_); }
|
|
||||||
|
|
||||||
Action *FadeTo::reverse() const { return new FadeTo(duration_, startOpacity_); }
|
|
||||||
|
|
||||||
// Sequence
|
|
||||||
Sequence::Sequence(const std::vector<Action *> &actions)
|
|
||||||
: IntervalAction(0.0f) {
|
|
||||||
for (auto *action : actions) {
|
|
||||||
if (action) {
|
|
||||||
actions_.push_back(action->clone());
|
|
||||||
duration_ += action->getDuration();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Sequence::~Sequence() {
|
|
||||||
for (auto *action : actions_)
|
|
||||||
delete action;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sequence::onStart() {
|
|
||||||
currentIndex_ = 0;
|
|
||||||
split_ = 0.0f;
|
|
||||||
last_ = -1.0f;
|
|
||||||
|
|
||||||
if (!actions_.empty()) {
|
|
||||||
actions_[0]->start(target_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sequence::onUpdate(float progress) {
|
|
||||||
int found = 0;
|
|
||||||
float newTime = progress * duration_;
|
|
||||||
|
|
||||||
if (newTime < last_) {
|
|
||||||
// Rewind
|
|
||||||
for (auto *action : actions_) {
|
|
||||||
action->stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
last_ = newTime;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < actions_.size(); ++i) {
|
|
||||||
split_ += actions_[i]->getDuration();
|
|
||||||
|
|
||||||
if (split_ > newTime) {
|
|
||||||
found = static_cast<int>(i);
|
|
||||||
break;
|
|
||||||
} else if (split_ == newTime) {
|
|
||||||
found = static_cast<int>(i) + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found != currentIndex_) {
|
|
||||||
if (currentIndex_ >= 0 &&
|
|
||||||
currentIndex_ < static_cast<int>(actions_.size())) {
|
|
||||||
actions_[currentIndex_]->update(actions_[currentIndex_]->getDuration());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found >= 0 && found < static_cast<int>(actions_.size())) {
|
|
||||||
actions_[found]->start(target_);
|
|
||||||
}
|
|
||||||
|
|
||||||
currentIndex_ = found;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentIndex_ >= 0 && currentIndex_ < static_cast<int>(actions_.size())) {
|
|
||||||
float localProgress = 0.0f;
|
|
||||||
if (actions_[currentIndex_]->getDuration() > 0.0f) {
|
|
||||||
localProgress =
|
|
||||||
(newTime - (split_ - actions_[currentIndex_]->getDuration())) /
|
|
||||||
actions_[currentIndex_]->getDuration();
|
|
||||||
}
|
|
||||||
actions_[currentIndex_]->step(actions_[currentIndex_]->getDuration() *
|
|
||||||
localProgress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Action *Sequence::clone() const { return new Sequence(actions_); }
|
|
||||||
|
|
||||||
Action *Sequence::reverse() const {
|
|
||||||
std::vector<Action *> rev;
|
|
||||||
for (auto it = actions_.rbegin(); it != actions_.rend(); ++it) {
|
|
||||||
rev.push_back((*it)->reverse());
|
|
||||||
}
|
|
||||||
return new Sequence(rev);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spawn
|
|
||||||
Spawn::Spawn(const std::vector<Action *> &actions) : IntervalAction(0.0f) {
|
|
||||||
for (auto *action : actions) {
|
|
||||||
if (action) {
|
|
||||||
actions_.push_back(action->clone());
|
|
||||||
duration_ = std::max(duration_, action->getDuration());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Spawn::~Spawn() {
|
|
||||||
for (auto *action : actions_)
|
|
||||||
delete action;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Spawn::onStart() {
|
|
||||||
for (auto *action : actions_) {
|
|
||||||
action->start(target_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Spawn::onUpdate(float progress) {
|
|
||||||
for (auto *action : actions_) {
|
|
||||||
float localProgress = 0.0f;
|
|
||||||
if (action->getDuration() > 0.0f) {
|
|
||||||
localProgress =
|
|
||||||
std::min(1.0f, (progress * duration_) / action->getDuration());
|
|
||||||
} else {
|
|
||||||
localProgress = 1.0f;
|
|
||||||
}
|
|
||||||
action->step(action->getDuration() * localProgress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Action *Spawn::clone() const { return new Spawn(actions_); }
|
|
||||||
|
|
||||||
Action *Spawn::reverse() const {
|
|
||||||
std::vector<Action *> rev;
|
|
||||||
for (auto *action : actions_) {
|
|
||||||
rev.push_back(action->reverse());
|
|
||||||
}
|
|
||||||
return new Spawn(rev);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop
|
|
||||||
Loop::Loop(Action *action, int times)
|
|
||||||
: action_(action ? action->clone() : nullptr), times_(times),
|
|
||||||
currentTimes_(0) {
|
|
||||||
if (action_) {
|
|
||||||
duration_ = times < 0 ? -1.0f : action_->getDuration() * times;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loop::~Loop() { delete action_; }
|
|
||||||
|
|
||||||
bool Loop::isDone() const {
|
|
||||||
if (times_ < 0)
|
|
||||||
return false;
|
|
||||||
return currentTimes_ >= times_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Loop::onStart() {
|
|
||||||
currentTimes_ = 0;
|
|
||||||
if (action_) {
|
|
||||||
action_->start(target_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Loop::onUpdate(float progress) {
|
|
||||||
if (!action_)
|
|
||||||
return;
|
|
||||||
|
|
||||||
float actionDuration = action_->getDuration();
|
|
||||||
float dt = progress * duration_ - elapsed_;
|
|
||||||
|
|
||||||
while (dt > 0.0f) {
|
|
||||||
float localProgress = std::min(1.0f, dt / actionDuration);
|
|
||||||
action_->step(actionDuration * localProgress);
|
|
||||||
|
|
||||||
if (action_->isDone()) {
|
|
||||||
currentTimes_++;
|
|
||||||
if (times_ > 0 && currentTimes_ >= times_)
|
|
||||||
break;
|
|
||||||
action_->restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
dt -= actionDuration;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Action *Loop::clone() const { return new Loop(action_, times_); }
|
|
||||||
|
|
||||||
Action *Loop::reverse() const {
|
|
||||||
return new Loop(action_ ? action_->reverse() : nullptr, times_);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delay
|
|
||||||
Delay::Delay(float duration) : IntervalAction(duration) {}
|
|
||||||
|
|
||||||
void Delay::onUpdate(float progress) {
|
|
||||||
// No update needed, just wait
|
|
||||||
}
|
|
||||||
|
|
||||||
Action *Delay::clone() const { return new Delay(duration_); }
|
|
||||||
|
|
||||||
Action *Delay::reverse() const { return new Delay(duration_); }
|
|
||||||
|
|
||||||
// CallFunc
|
|
||||||
CallFunc::CallFunc(Callback callback) : callback_(std::move(callback)) {}
|
|
||||||
|
|
||||||
void CallFunc::onUpdate(float progress) {
|
|
||||||
(void)progress;
|
|
||||||
if (callback_)
|
|
||||||
callback_();
|
|
||||||
}
|
|
||||||
|
|
||||||
Action *CallFunc::clone() const { return new CallFunc(callback_); }
|
|
||||||
|
|
||||||
Action *CallFunc::reverse() const { return new CallFunc(callback_); }
|
|
||||||
} // namespace extra2d
|
|
||||||
|
|
@ -1,179 +1,225 @@
|
||||||
|
#include "extra2d/action/ease.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <extra2d/action/ease.h>
|
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
// Linear
|
|
||||||
float easeLinear(float t) { return t; }
|
|
||||||
|
|
||||||
// Quadratic
|
#ifndef M_PI
|
||||||
float easeInQuad(float t) { return t * t; }
|
#define M_PI 3.14159265358979323846f
|
||||||
|
#endif
|
||||||
|
|
||||||
float easeOutQuad(float t) { return 1.0f - (1.0f - t) * (1.0f - t); }
|
// ============================================================================
|
||||||
|
// 线性缓动
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
float easeLinear(float t) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 二次缓动 (Quad)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
float easeInQuad(float t) {
|
||||||
|
return t * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
float easeOutQuad(float t) {
|
||||||
|
return 1.0f - (1.0f - t) * (1.0f - t);
|
||||||
|
}
|
||||||
|
|
||||||
float easeInOutQuad(float t) {
|
float easeInOutQuad(float t) {
|
||||||
return t < 0.5f ? 2.0f * t * t
|
return t < 0.5f ? 2.0f * t * t : 1.0f - std::pow(-2.0f * t + 2.0f, 2.0f) / 2.0f;
|
||||||
: 1.0f - std::pow(-2.0f * t + 2.0f, 2.0f) / 2.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cubic
|
// ============================================================================
|
||||||
float easeInCubic(float t) { return t * t * t; }
|
// 三次缓动 (Cubic)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
float easeOutCubic(float t) { return 1.0f - std::pow(1.0f - t, 3.0f); }
|
float easeInCubic(float t) {
|
||||||
|
return t * t * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
float easeOutCubic(float t) {
|
||||||
|
return 1.0f - std::pow(1.0f - t, 3.0f);
|
||||||
|
}
|
||||||
|
|
||||||
float easeInOutCubic(float t) {
|
float easeInOutCubic(float t) {
|
||||||
return t < 0.5f ? 4.0f * t * t * t
|
return t < 0.5f ? 4.0f * t * t * t : 1.0f - std::pow(-2.0f * t + 2.0f, 3.0f) / 2.0f;
|
||||||
: 1.0f - std::pow(-2.0f * t + 2.0f, 3.0f) / 2.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quartic
|
// ============================================================================
|
||||||
float easeInQuart(float t) { return t * t * t * t; }
|
// 四次缓动 (Quart)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
float easeOutQuart(float t) { return 1.0f - std::pow(1.0f - t, 4.0f); }
|
float easeInQuart(float t) {
|
||||||
|
return t * t * t * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
float easeOutQuart(float t) {
|
||||||
|
return 1.0f - std::pow(1.0f - t, 4.0f);
|
||||||
|
}
|
||||||
|
|
||||||
float easeInOutQuart(float t) {
|
float easeInOutQuart(float t) {
|
||||||
return t < 0.5f ? 8.0f * t * t * t * t
|
return t < 0.5f ? 8.0f * t * t * t * t : 1.0f - std::pow(-2.0f * t + 2.0f, 4.0f) / 2.0f;
|
||||||
: 1.0f - std::pow(-2.0f * t + 2.0f, 4.0f) / 2.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quintic
|
// ============================================================================
|
||||||
float easeInQuint(float t) { return t * t * t * t * t; }
|
// 五次缓动 (Quint)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
float easeOutQuint(float t) { return 1.0f - std::pow(1.0f - t, 5.0f); }
|
float easeInQuint(float t) {
|
||||||
|
return t * t * t * t * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
float easeOutQuint(float t) {
|
||||||
|
return 1.0f - std::pow(1.0f - t, 5.0f);
|
||||||
|
}
|
||||||
|
|
||||||
float easeInOutQuint(float t) {
|
float easeInOutQuint(float t) {
|
||||||
return t < 0.5f ? 16.0f * t * t * t * t * t
|
return t < 0.5f ? 16.0f * t * t * t * t * t : 1.0f - std::pow(-2.0f * t + 2.0f, 5.0f) / 2.0f;
|
||||||
: 1.0f - std::pow(-2.0f * t + 2.0f, 5.0f) / 2.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sine
|
// ============================================================================
|
||||||
|
// 正弦缓动 (Sine)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
float easeInSine(float t) {
|
float easeInSine(float t) {
|
||||||
return 1.0f - std::cos((t * 3.14159265359f) / 2.0f);
|
return 1.0f - std::cos((t * M_PI) / 2.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
float easeOutSine(float t) { return std::sin((t * 3.14159265359f) / 2.0f); }
|
float easeOutSine(float t) {
|
||||||
|
return std::sin((t * M_PI) / 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
float easeInOutSine(float t) {
|
float easeInOutSine(float t) {
|
||||||
return -(std::cos(3.14159265359f * t) - 1.0f) / 2.0f;
|
return -(std::cos(M_PI * t) - 1.0f) / 2.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exponential
|
// ============================================================================
|
||||||
|
// 指数缓动 (Exponential)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
float easeInExpo(float t) {
|
float easeInExpo(float t) {
|
||||||
return t == 0.0f ? 0.0f : std::pow(2.0f, 10.0f * (t - 1.0f));
|
return t == 0.0f ? 0.0f : std::pow(2.0f, 10.0f * (t - 1.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
float easeOutExpo(float t) {
|
float easeOutExpo(float t) {
|
||||||
return t == 1.0f ? 1.0f : 1.0f - std::pow(2.0f, -10.0f * t);
|
return t == 1.0f ? 1.0f : 1.0f - std::pow(2.0f, -10.0f * t);
|
||||||
}
|
}
|
||||||
|
|
||||||
float easeInOutExpo(float t) {
|
float easeInOutExpo(float t) {
|
||||||
if (t == 0.0f)
|
if (t == 0.0f) return 0.0f;
|
||||||
return 0.0f;
|
if (t == 1.0f) return 1.0f;
|
||||||
if (t == 1.0f)
|
return t < 0.5f
|
||||||
return 1.0f;
|
? std::pow(2.0f, 20.0f * t - 10.0f) / 2.0f
|
||||||
return t < 0.5f ? std::pow(2.0f, 20.0f * t - 10.0f) / 2.0f
|
: (2.0f - std::pow(2.0f, -20.0f * t + 10.0f)) / 2.0f;
|
||||||
: (2.0f - std::pow(2.0f, -20.0f * t + 10.0f)) / 2.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Circular
|
// ============================================================================
|
||||||
float easeInCirc(float t) { return 1.0f - std::sqrt(1.0f - std::pow(t, 2.0f)); }
|
// 圆形缓动 (Circular)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
float easeInCirc(float t) {
|
||||||
|
return 1.0f - std::sqrt(1.0f - std::pow(t, 2.0f));
|
||||||
|
}
|
||||||
|
|
||||||
float easeOutCirc(float t) {
|
float easeOutCirc(float t) {
|
||||||
return std::sqrt(1.0f - std::pow(t - 1.0f, 2.0f));
|
return std::sqrt(1.0f - std::pow(t - 1.0f, 2.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
float easeInOutCirc(float t) {
|
float easeInOutCirc(float t) {
|
||||||
return t < 0.5f
|
return t < 0.5f
|
||||||
? (1.0f - std::sqrt(1.0f - std::pow(2.0f * t, 2.0f))) / 2.0f
|
? (1.0f - std::sqrt(1.0f - std::pow(2.0f * t, 2.0f))) / 2.0f
|
||||||
: (std::sqrt(1.0f - std::pow(-2.0f * t + 2.0f, 2.0f)) + 1.0f) /
|
: (std::sqrt(1.0f - std::pow(-2.0f * t + 2.0f, 2.0f)) + 1.0f) / 2.0f;
|
||||||
2.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Back
|
// ============================================================================
|
||||||
|
// 回震缓动 (Back)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
float easeInBack(float t) {
|
float easeInBack(float t) {
|
||||||
const float c1 = 1.70158f;
|
const float c1 = 1.70158f;
|
||||||
const float c3 = c1 + 1.0f;
|
const float c3 = c1 + 1.0f;
|
||||||
return c3 * t * t * t - c1 * t * t;
|
return c3 * t * t * t - c1 * t * t;
|
||||||
}
|
}
|
||||||
|
|
||||||
float easeOutBack(float t) {
|
float easeOutBack(float t) {
|
||||||
const float c1 = 1.70158f;
|
const float c1 = 1.70158f;
|
||||||
const float c3 = c1 + 1.0f;
|
const float c3 = c1 + 1.0f;
|
||||||
return 1.0f + c3 * std::pow(t - 1.0f, 3.0f) + c1 * std::pow(t - 1.0f, 2.0f);
|
return 1.0f + c3 * std::pow(t - 1.0f, 3.0f) + c1 * std::pow(t - 1.0f, 2.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
float easeInOutBack(float t) {
|
float easeInOutBack(float t) {
|
||||||
const float c1 = 1.70158f;
|
const float c1 = 1.70158f;
|
||||||
const float c2 = c1 * 1.525f;
|
const float c2 = c1 * 1.525f;
|
||||||
return t < 0.5f
|
return t < 0.5f
|
||||||
? (std::pow(2.0f * t, 2.0f) * ((c2 + 1.0f) * 2.0f * t - c2)) / 2.0f
|
? (std::pow(2.0f * t, 2.0f) * ((c2 + 1.0f) * 2.0f * t - c2)) / 2.0f
|
||||||
: (std::pow(2.0f * t - 2.0f, 2.0f) *
|
: (std::pow(2.0f * t - 2.0f, 2.0f) * ((c2 + 1.0f) * (t * 2.0f - 2.0f) + c2) + 2.0f) / 2.0f;
|
||||||
((c2 + 1.0f) * (t * 2.0f - 2.0f) + c2) +
|
|
||||||
2.0f) /
|
|
||||||
2.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Elastic
|
// ============================================================================
|
||||||
|
// 弹性缓动 (Elastic)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
float easeInElastic(float t) {
|
float easeInElastic(float t) {
|
||||||
const float c4 = (2.0f * 3.14159265359f) / 3.0f;
|
const float c4 = (2.0f * M_PI) / 3.0f;
|
||||||
if (t == 0.0f)
|
if (t == 0.0f) return 0.0f;
|
||||||
return 0.0f;
|
if (t == 1.0f) return 1.0f;
|
||||||
if (t == 1.0f)
|
return -std::pow(2.0f, 10.0f * t - 10.0f) * std::sin((t * 10.0f - 10.75f) * c4);
|
||||||
return 1.0f;
|
|
||||||
return -std::pow(2.0f, 10.0f * t - 10.0f) *
|
|
||||||
std::sin((t * 10.0f - 10.75f) * c4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float easeOutElastic(float t) {
|
float easeOutElastic(float t) {
|
||||||
const float c4 = (2.0f * 3.14159265359f) / 3.0f;
|
const float c4 = (2.0f * M_PI) / 3.0f;
|
||||||
if (t == 0.0f)
|
if (t == 0.0f) return 0.0f;
|
||||||
return 0.0f;
|
if (t == 1.0f) return 1.0f;
|
||||||
if (t == 1.0f)
|
return std::pow(2.0f, -10.0f * t) * std::sin((t * 10.0f - 0.75f) * c4) + 1.0f;
|
||||||
return 1.0f;
|
|
||||||
return std::pow(2.0f, -10.0f * t) * std::sin((t * 10.0f - 0.75f) * c4) + 1.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float easeInOutElastic(float t) {
|
float easeInOutElastic(float t) {
|
||||||
const float c5 = (2.0f * 3.14159265359f) / 4.5f;
|
const float c5 = (2.0f * M_PI) / 4.5f;
|
||||||
if (t == 0.0f)
|
if (t == 0.0f) return 0.0f;
|
||||||
return 0.0f;
|
if (t == 1.0f) return 1.0f;
|
||||||
if (t == 1.0f)
|
return t < 0.5f
|
||||||
return 1.0f;
|
? -(std::pow(2.0f, 20.0f * t - 10.0f) * std::sin((20.0f * t - 11.125f) * c5)) / 2.0f
|
||||||
return t < 0.5f ? -(std::pow(2.0f, 20.0f * t - 10.0f) *
|
: (std::pow(2.0f, -20.0f * t + 10.0f) * std::sin((20.0f * t - 11.125f) * c5)) / 2.0f + 1.0f;
|
||||||
std::sin((20.0f * t - 11.125f) * c5)) /
|
|
||||||
2.0f
|
|
||||||
: (std::pow(2.0f, -20.0f * t + 10.0f) *
|
|
||||||
std::sin((20.0f * t - 11.125f) * c5)) /
|
|
||||||
2.0f +
|
|
||||||
1.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bounce
|
// ============================================================================
|
||||||
|
// 弹跳缓动 (Bounce)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
float easeOutBounceInternal(float t) {
|
float easeOutBounceInternal(float t) {
|
||||||
const float n1 = 7.5625f;
|
const float n1 = 7.5625f;
|
||||||
const float d1 = 2.75f;
|
const float d1 = 2.75f;
|
||||||
|
|
||||||
if (t < 1.0f / d1) {
|
if (t < 1.0f / d1) {
|
||||||
return n1 * t * t;
|
return n1 * t * t;
|
||||||
} else if (t < 2.0f / d1) {
|
} else if (t < 2.0f / d1) {
|
||||||
t -= 1.5f / d1;
|
t -= 1.5f / d1;
|
||||||
return n1 * t * t + 0.75f;
|
return n1 * t * t + 0.75f;
|
||||||
} else if (t < 2.5f / d1) {
|
} else if (t < 2.5f / d1) {
|
||||||
t -= 2.25f / d1;
|
t -= 2.25f / d1;
|
||||||
return n1 * t * t + 0.9375f;
|
return n1 * t * t + 0.9375f;
|
||||||
} else {
|
} else {
|
||||||
t -= 2.625f / d1;
|
t -= 2.625f / d1;
|
||||||
return n1 * t * t + 0.984375f;
|
return n1 * t * t + 0.984375f;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // namespace
|
|
||||||
|
|
||||||
float easeInBounce(float t) { return 1.0f - easeOutBounceInternal(1.0f - t); }
|
float easeInBounce(float t) {
|
||||||
|
return 1.0f - easeOutBounceInternal(1.0f - t);
|
||||||
|
}
|
||||||
|
|
||||||
float easeOutBounce(float t) { return easeOutBounceInternal(t); }
|
float easeOutBounce(float t) {
|
||||||
|
return easeOutBounceInternal(t);
|
||||||
|
}
|
||||||
|
|
||||||
float easeInOutBounce(float t) {
|
float easeInOutBounce(float t) {
|
||||||
return t < 0.5f ? (1.0f - easeOutBounceInternal(1.0f - 2.0f * t)) / 2.0f
|
return t < 0.5f
|
||||||
: (1.0f + easeOutBounceInternal(2.0f * t - 1.0f)) / 2.0f;
|
? (1.0f - easeOutBounceInternal(1.0f - 2.0f * t)) / 2.0f
|
||||||
|
: (1.0f + easeOutBounceInternal(2.0f * t - 1.0f)) / 2.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace extra2d
|
} // namespace extra2d
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include "extra2d/action/finite_time_action.h"
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
FiniteTimeAction::FiniteTimeAction(float duration)
|
||||||
|
: duration_(duration) {
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <extra2d/action/action_manager.h>
|
||||||
#include <extra2d/app/application.h>
|
#include <extra2d/app/application.h>
|
||||||
#include <extra2d/audio/audio_engine.h>
|
#include <extra2d/audio/audio_engine.h>
|
||||||
#include <extra2d/event/event_dispatcher.h>
|
#include <extra2d/event/event_dispatcher.h>
|
||||||
|
|
@ -13,9 +14,9 @@
|
||||||
#include <extra2d/utils/object_pool.h>
|
#include <extra2d/utils/object_pool.h>
|
||||||
#include <extra2d/utils/timer.h>
|
#include <extra2d/utils/timer.h>
|
||||||
|
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#ifdef __SWITCH__
|
#ifdef __SWITCH__
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
|
|
@ -74,7 +75,8 @@ bool Application::init(const AppConfig &config) {
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
E2D_LOG_INFO("RomFS initialized successfully");
|
E2D_LOG_INFO("RomFS initialized successfully");
|
||||||
} else {
|
} else {
|
||||||
E2D_LOG_WARN("romfsInit failed: {:#08X}, will use regular filesystem", rc);
|
E2D_LOG_WARN("romfsInit failed: {:#08X}, will use regular filesystem",
|
||||||
|
rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========================================
|
// ========================================
|
||||||
|
|
@ -98,7 +100,7 @@ bool Application::init(const AppConfig &config) {
|
||||||
winConfig.height = config.height;
|
winConfig.height = config.height;
|
||||||
if (platform == PlatformType::Switch) {
|
if (platform == PlatformType::Switch) {
|
||||||
winConfig.fullscreen = true;
|
winConfig.fullscreen = true;
|
||||||
winConfig.fullscreenDesktop = false; // Switch 使用固定分辨率全屏
|
winConfig.fullscreenDesktop = false; // Switch 使用固定分辨率全屏
|
||||||
winConfig.resizable = false;
|
winConfig.resizable = false;
|
||||||
winConfig.enableCursors = false;
|
winConfig.enableCursors = false;
|
||||||
winConfig.enableDpiScale = false;
|
winConfig.enableDpiScale = false;
|
||||||
|
|
@ -171,7 +173,7 @@ bool Application::init(const AppConfig &config) {
|
||||||
void Application::prewarmObjectPools() {
|
void Application::prewarmObjectPools() {
|
||||||
E2D_LOG_INFO("Prewarming object pools...");
|
E2D_LOG_INFO("Prewarming object pools...");
|
||||||
|
|
||||||
auto& poolManager = ObjectPoolManager::getInstance();
|
auto &poolManager = ObjectPoolManager::getInstance();
|
||||||
|
|
||||||
// 预热常用类型的对象池
|
// 预热常用类型的对象池
|
||||||
// 这些池会在首次使用时自动预热,但提前预热可以避免运行时延迟
|
// 这些池会在首次使用时自动预热,但提前预热可以避免运行时延迟
|
||||||
|
|
@ -201,9 +203,9 @@ void Application::shutdown() {
|
||||||
// 1. 先清理所有持有 GPU 资源的子系统
|
// 1. 先清理所有持有 GPU 资源的子系统
|
||||||
// 必须在渲染器关闭前释放纹理等资源
|
// 必须在渲染器关闭前释放纹理等资源
|
||||||
// ========================================
|
// ========================================
|
||||||
sceneManager_.reset(); // 场景持有纹理引用
|
sceneManager_.reset(); // 场景持有纹理引用
|
||||||
resourceManager_.reset(); // 纹理缓存持有 GPU 纹理
|
resourceManager_.reset(); // 纹理缓存持有 GPU 纹理
|
||||||
camera_.reset(); // 相机可能持有渲染目标
|
camera_.reset(); // 相机可能持有渲染目标
|
||||||
|
|
||||||
// ========================================
|
// ========================================
|
||||||
// 2. 关闭音频(不依赖 GPU)
|
// 2. 关闭音频(不依赖 GPU)
|
||||||
|
|
@ -340,6 +342,9 @@ void Application::mainLoop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::update() {
|
void Application::update() {
|
||||||
|
// Update action manager (single update per frame)
|
||||||
|
ActionManager::getInstance()->update(deltaTime_);
|
||||||
|
|
||||||
if (timerManager_) {
|
if (timerManager_) {
|
||||||
timerManager_->update(deltaTime_);
|
timerManager_->update(deltaTime_);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <extra2d/action/action.h>
|
#include <extra2d/action/action.h>
|
||||||
|
#include <extra2d/action/action_manager.h>
|
||||||
#include <extra2d/graphics/render_command.h>
|
#include <extra2d/graphics/render_command.h>
|
||||||
#include <extra2d/scene/node.h>
|
#include <extra2d/scene/node.h>
|
||||||
#include <extra2d/scene/scene.h>
|
#include <extra2d/scene/scene.h>
|
||||||
|
|
@ -13,6 +14,7 @@ Node::Node() = default;
|
||||||
Node::~Node() {
|
Node::~Node() {
|
||||||
removeAllChildren();
|
removeAllChildren();
|
||||||
stopAllActions();
|
stopAllActions();
|
||||||
|
ActionManager::getInstance()->removeAllActionsFromTarget(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::addChild(Ptr<Node> child) {
|
void Node::addChild(Ptr<Node> child) {
|
||||||
|
|
@ -201,6 +203,12 @@ void Node::setOpacity(float opacity) {
|
||||||
|
|
||||||
void Node::setVisible(bool visible) { visible_ = visible; }
|
void Node::setVisible(bool visible) { visible_ = visible; }
|
||||||
|
|
||||||
|
void Node::setColor(const Color3B& color) { color_ = color; }
|
||||||
|
|
||||||
|
void Node::setFlipX(bool flipX) { flipX_ = flipX; }
|
||||||
|
|
||||||
|
void Node::setFlipY(bool flipY) { flipY_ = flipY; }
|
||||||
|
|
||||||
void Node::setZOrder(int zOrder) {
|
void Node::setZOrder(int zOrder) {
|
||||||
if (zOrder_ != zOrder) {
|
if (zOrder_ != zOrder) {
|
||||||
zOrder_ = zOrder;
|
zOrder_ = zOrder;
|
||||||
|
|
@ -332,17 +340,6 @@ void Node::onExit() {
|
||||||
void Node::onUpdate(float dt) {
|
void Node::onUpdate(float dt) {
|
||||||
onUpdateNode(dt);
|
onUpdateNode(dt);
|
||||||
|
|
||||||
// Update actions
|
|
||||||
for (auto it = actions_.begin(); it != actions_.end();) {
|
|
||||||
auto &action = *it;
|
|
||||||
action->update(dt);
|
|
||||||
if (action->isDone()) {
|
|
||||||
it = actions_.erase(it);
|
|
||||||
} else {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update children
|
// Update children
|
||||||
for (auto &child : children_) {
|
for (auto &child : children_) {
|
||||||
child->onUpdate(dt);
|
child->onUpdate(dt);
|
||||||
|
|
@ -406,74 +403,44 @@ void Node::updateSpatialIndex() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::runAction(Ptr<Action> action) {
|
// ============================================================================
|
||||||
|
// 动作系统 - 新接口
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
Action* Node::runAction(Action* action) {
|
||||||
if (!action) {
|
if (!action) {
|
||||||
return;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
ActionManager::getInstance()->addAction(action, this);
|
||||||
action->start(this);
|
return action;
|
||||||
|
|
||||||
int tag = action->getTag();
|
|
||||||
if (tag != -1) {
|
|
||||||
// 有 tag 的 Action 存入哈希表,O(1) 查找
|
|
||||||
// 如果已存在相同 tag 的 Action,先停止它
|
|
||||||
auto it = actionByTag_.find(tag);
|
|
||||||
if (it != actionByTag_.end()) {
|
|
||||||
// 从 vector 中移除旧的 Action
|
|
||||||
auto oldAction = it->second;
|
|
||||||
auto vecIt = std::find(actions_.begin(), actions_.end(), oldAction);
|
|
||||||
if (vecIt != actions_.end()) {
|
|
||||||
actions_.erase(vecIt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
actionByTag_[tag] = action;
|
|
||||||
}
|
|
||||||
|
|
||||||
actions_.push_back(action);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::stopAllActions() {
|
void Node::stopAllActions() {
|
||||||
actions_.clear();
|
ActionManager::getInstance()->removeAllActionsFromTarget(this);
|
||||||
actionByTag_.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::stopAction(Ptr<Action> action) {
|
void Node::stopAction(Action* action) {
|
||||||
if (!action) {
|
ActionManager::getInstance()->removeAction(action);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从 vector 中移除
|
|
||||||
auto it = std::find(actions_.begin(), actions_.end(), action);
|
|
||||||
if (it != actions_.end()) {
|
|
||||||
// 如果有 tag,从哈希表中也移除
|
|
||||||
int tag = action->getTag();
|
|
||||||
if (tag != -1) {
|
|
||||||
actionByTag_.erase(tag);
|
|
||||||
}
|
|
||||||
actions_.erase(it);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::stopActionByTag(int tag) {
|
void Node::stopActionByTag(int tag) {
|
||||||
auto it = actionByTag_.find(tag);
|
ActionManager::getInstance()->removeActionByTag(tag, this);
|
||||||
if (it != actionByTag_.end()) {
|
|
||||||
auto action = it->second;
|
|
||||||
// 从 vector 中移除
|
|
||||||
auto vecIt = std::find(actions_.begin(), actions_.end(), action);
|
|
||||||
if (vecIt != actions_.end()) {
|
|
||||||
actions_.erase(vecIt);
|
|
||||||
}
|
|
||||||
actionByTag_.erase(it);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ptr<Action> Node::getActionByTag(int tag) const {
|
void Node::stopActionsByFlags(unsigned int flags) {
|
||||||
// O(1) 哈希查找
|
ActionManager::getInstance()->removeActionsByFlags(flags, this);
|
||||||
auto it = actionByTag_.find(tag);
|
}
|
||||||
if (it != actionByTag_.end()) {
|
|
||||||
return it->second;
|
Action* Node::getActionByTag(int tag) {
|
||||||
}
|
return ActionManager::getInstance()->getActionByTag(tag, this);
|
||||||
return nullptr;
|
}
|
||||||
|
|
||||||
|
size_t Node::getActionCount() const {
|
||||||
|
return ActionManager::getInstance()->getActionCount(const_cast<Node*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Node::isRunningActions() const {
|
||||||
|
return getActionCount() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::update(float dt) { onUpdate(dt); }
|
void Node::update(float dt) { onUpdate(dt); }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,598 @@
|
||||||
|
# 动作系统 (Action System)
|
||||||
|
|
||||||
|
Extra2D 的动作系统提供了一套完整的动画解决方案,参考 Cocos2d-x 的设计模式,支持丰富的动作类型和缓动效果。
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
1. [概述](#概述)
|
||||||
|
2. [核心概念](#核心概念)
|
||||||
|
3. [基本动作](#基本动作)
|
||||||
|
4. [组合动作](#组合动作)
|
||||||
|
5. [缓动动作](#缓动动作)
|
||||||
|
6. [特殊动作](#特殊动作)
|
||||||
|
7. [瞬时动作](#瞬时动作)
|
||||||
|
8. [动作管理](#动作管理)
|
||||||
|
9. [完整示例](#完整示例)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
动作系统用于在节点上创建动画效果,通过修改节点的属性(位置、缩放、旋转、透明度等)实现各种动画。
|
||||||
|
|
||||||
|
### 类层次结构
|
||||||
|
|
||||||
|
```
|
||||||
|
Action (基类)
|
||||||
|
├── FiniteTimeAction (有限时间动作)
|
||||||
|
│ ├── ActionInterval (时间间隔动作)
|
||||||
|
│ │ ├── MoveBy/MoveTo
|
||||||
|
│ │ ├── JumpBy/JumpTo
|
||||||
|
│ │ ├── BezierBy/BezierTo
|
||||||
|
│ │ ├── ScaleBy/ScaleTo
|
||||||
|
│ │ ├── RotateBy/RotateTo
|
||||||
|
│ │ ├── FadeIn/FadeOut/FadeTo
|
||||||
|
│ │ ├── Blink
|
||||||
|
│ │ ├── TintBy/TintTo
|
||||||
|
│ │ ├── Sequence
|
||||||
|
│ │ ├── Spawn
|
||||||
|
│ │ ├── Repeat/RepeatForever
|
||||||
|
│ │ ├── DelayTime
|
||||||
|
│ │ ├── ReverseTime
|
||||||
|
│ │ └── ActionEase (缓动动作基类)
|
||||||
|
│ └── ActionInstant (瞬时动作)
|
||||||
|
│ ├── CallFunc/CallFuncN
|
||||||
|
│ ├── Place
|
||||||
|
│ ├── FlipX/FlipY
|
||||||
|
│ ├── Show/Hide
|
||||||
|
│ ├── ToggleVisibility
|
||||||
|
│ └── RemoveSelf
|
||||||
|
├── Speed (速度控制)
|
||||||
|
├── Follow (跟随动作)
|
||||||
|
└── TargetedAction (目标动作)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 核心概念
|
||||||
|
|
||||||
|
### 创建动作
|
||||||
|
|
||||||
|
所有动作都使用静态工厂方法 `create()` 创建:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 创建移动动作
|
||||||
|
auto move = MoveTo::create(2.0f, Vec2(100, 100));
|
||||||
|
|
||||||
|
// 创建缩放动作
|
||||||
|
auto scale = ScaleTo::create(1.0f, 2.0f);
|
||||||
|
|
||||||
|
// 创建旋转动作
|
||||||
|
auto rotate = RotateBy::create(3.0f, 360.0f);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 运行动作
|
||||||
|
|
||||||
|
通过节点的 `runAction()` 方法运行动作:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
sprite->runAction(move);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 动作完成回调
|
||||||
|
|
||||||
|
使用 `setCompletionCallback()` 设置动作完成时的回调:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto action = MoveTo::create(2.0f, Vec2(100, 100));
|
||||||
|
action->setCompletionCallback([]() {
|
||||||
|
E2D_LOG_INFO("动作完成!");
|
||||||
|
});
|
||||||
|
sprite->runAction(action);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 基本动作
|
||||||
|
|
||||||
|
### 移动动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// MoveTo - 移动到指定位置
|
||||||
|
auto moveTo = MoveTo::create(2.0f, Vec2(100, 100));
|
||||||
|
|
||||||
|
// MoveBy - 相对移动
|
||||||
|
auto moveBy = MoveBy::create(2.0f, Vec2(50, 0)); // 向右移动 50 像素
|
||||||
|
```
|
||||||
|
|
||||||
|
### 跳跃动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// JumpTo - 跳跃到指定位置
|
||||||
|
auto jumpTo = JumpTo::create(2.0f, Vec2(100, 100), 50, 3); // 跳到 (100,100),高度 50,跳 3 次
|
||||||
|
|
||||||
|
// JumpBy - 相对跳跃
|
||||||
|
auto jumpBy = JumpBy::create(2.0f, Vec2(100, 0), 50, 3); // 向右跳跃 100 像素
|
||||||
|
```
|
||||||
|
|
||||||
|
### 贝塞尔曲线动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
BezierConfig bezier;
|
||||||
|
bezier.controlPoint1 = Vec2(100, 200);
|
||||||
|
bezier.controlPoint2 = Vec2(200, 100);
|
||||||
|
bezier.endPosition = Vec2(300, 150);
|
||||||
|
|
||||||
|
// BezierTo - 贝塞尔曲线移动到指定位置
|
||||||
|
auto bezierTo = BezierTo::create(3.0f, bezier);
|
||||||
|
|
||||||
|
// BezierBy - 相对贝塞尔曲线移动
|
||||||
|
auto bezierBy = BezierBy::create(3.0f, bezier);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 缩放动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// ScaleTo - 缩放到指定比例
|
||||||
|
auto scaleTo = ScaleTo::create(1.0f, 2.0f); // 缩放到 2 倍
|
||||||
|
auto scaleToXY = ScaleTo::create(1.0f, 2.0f, 1.5f); // X 缩放 2 倍,Y 缩放 1.5 倍
|
||||||
|
|
||||||
|
// ScaleBy - 相对缩放
|
||||||
|
auto scaleBy = ScaleBy::create(1.0f, 0.5f); // 缩小一半
|
||||||
|
```
|
||||||
|
|
||||||
|
### 旋转动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// RotateTo - 旋转到指定角度
|
||||||
|
auto rotateTo = RotateTo::create(2.0f, 90.0f); // 旋转到 90 度
|
||||||
|
|
||||||
|
// RotateBy - 相对旋转
|
||||||
|
auto rotateBy = RotateBy::create(2.0f, 360.0f); // 旋转 360 度
|
||||||
|
```
|
||||||
|
|
||||||
|
### 淡入淡出动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// FadeIn - 淡入(透明度从 0 到 1)
|
||||||
|
auto fadeIn = FadeIn::create(1.0f);
|
||||||
|
|
||||||
|
// FadeOut - 淡出(透明度从 1 到 0)
|
||||||
|
auto fadeOut = FadeOut::create(1.0f);
|
||||||
|
|
||||||
|
// FadeTo - 淡入到指定透明度
|
||||||
|
auto fadeTo = FadeTo::create(1.0f, 0.5f); // 淡入到 50% 透明度
|
||||||
|
```
|
||||||
|
|
||||||
|
### 闪烁动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Blink - 闪烁
|
||||||
|
auto blink = Blink::create(2.0f, 5); // 2 秒内闪烁 5 次
|
||||||
|
```
|
||||||
|
|
||||||
|
### 色调动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// TintTo - 变化到指定颜色
|
||||||
|
auto tintTo = TintTo::create(1.0f, 255, 0, 0); // 变为红色
|
||||||
|
|
||||||
|
// TintBy - 相对颜色变化
|
||||||
|
auto tintBy = TintBy::create(1.0f, 50, 0, 0); // 红色通道增加 50
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 组合动作
|
||||||
|
|
||||||
|
### Sequence - 序列动作
|
||||||
|
|
||||||
|
按顺序依次执行多个动作:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto sequence = Sequence::create(
|
||||||
|
MoveTo::create(1.0f, Vec2(100, 100)),
|
||||||
|
DelayTime::create(0.5f),
|
||||||
|
FadeOut::create(1.0f),
|
||||||
|
CallFunc::create([]() { E2D_LOG_INFO("完成"); }),
|
||||||
|
nullptr // 必须以 nullptr 结尾
|
||||||
|
);
|
||||||
|
sprite->runAction(sequence);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Spawn - 并行动作
|
||||||
|
|
||||||
|
同时执行多个动作:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto spawn = Spawn::create(
|
||||||
|
MoveTo::create(2.0f, Vec2(200, 200)),
|
||||||
|
RotateBy::create(2.0f, 360),
|
||||||
|
FadeIn::create(2.0f),
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
sprite->runAction(spawn);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Repeat - 重复动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Repeat - 重复指定次数
|
||||||
|
auto repeat = Repeat::create(
|
||||||
|
Sequence::create(
|
||||||
|
MoveBy::create(0.5f, Vec2(50, 0)),
|
||||||
|
MoveBy::create(0.5f, Vec2(-50, 0)),
|
||||||
|
nullptr
|
||||||
|
),
|
||||||
|
5 // 重复 5 次
|
||||||
|
);
|
||||||
|
|
||||||
|
// RepeatForever - 永久重复
|
||||||
|
auto repeatForever = RepeatForever::create(
|
||||||
|
RotateBy::create(1.0f, 360)
|
||||||
|
);
|
||||||
|
sprite->runAction(repeatForever);
|
||||||
|
```
|
||||||
|
|
||||||
|
### DelayTime - 延时动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto sequence = Sequence::create(
|
||||||
|
MoveTo::create(1.0f, Vec2(100, 0)),
|
||||||
|
DelayTime::create(1.0f), // 延时 1 秒
|
||||||
|
MoveTo::create(1.0f, Vec2(200, 0)),
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### ReverseTime - 反向动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto move = MoveBy::create(1.0f, Vec2(100, 0));
|
||||||
|
auto reverse = ReverseTime::create(move->clone());
|
||||||
|
// 反向执行,相当于 MoveBy(1.0f, Vec2(-100, 0))
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 缓动动作
|
||||||
|
|
||||||
|
缓动动作使用装饰器模式包装其他动作,实现各种缓动效果。
|
||||||
|
|
||||||
|
### 使用缓动
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 创建基础动作
|
||||||
|
auto move = MoveTo::create(3.0f, Vec2(500, 300));
|
||||||
|
|
||||||
|
// 用缓动包装
|
||||||
|
auto easeMove = EaseElasticOut::create(move);
|
||||||
|
sprite->runAction(easeMove);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 可用缓动类型
|
||||||
|
|
||||||
|
| 缓动类 | 效果 |
|
||||||
|
|--------|------|
|
||||||
|
| `EaseQuadIn/Out/InOut` | 二次缓动 |
|
||||||
|
| `EaseCubicIn/Out/InOut` | 三次缓动 |
|
||||||
|
| `EaseQuartIn/Out/InOut` | 四次缓动 |
|
||||||
|
| `EaseQuintIn/Out/InOut` | 五次缓动 |
|
||||||
|
| `EaseSineIn/Out/InOut` | 正弦缓动 |
|
||||||
|
| `EaseExponentialIn/Out/InOut` | 指数缓动 |
|
||||||
|
| `EaseCircleIn/Out/InOut` | 圆形缓动 |
|
||||||
|
| `EaseBackIn/Out/InOut` | 回震缓动 |
|
||||||
|
| `EaseElasticIn/Out/InOut` | 弹性缓动 |
|
||||||
|
| `EaseBounceIn/Out/InOut` | 弹跳缓动 |
|
||||||
|
|
||||||
|
### 缓动效果说明
|
||||||
|
|
||||||
|
- **In**: 开始时慢,逐渐加速
|
||||||
|
- **Out**: 开始时快,逐渐减速
|
||||||
|
- **InOut**: 开始和结束时慢,中间快
|
||||||
|
|
||||||
|
### 示例
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 弹性缓动
|
||||||
|
auto jump = JumpBy::create(2.0f, Vec2(200, 0), 100, 1);
|
||||||
|
auto elasticJump = EaseElasticOut::create(jump, 0.5f);
|
||||||
|
sprite->runAction(elasticJump);
|
||||||
|
|
||||||
|
// 弹跳缓动
|
||||||
|
auto scale = ScaleTo::create(1.0f, 2.0f);
|
||||||
|
auto bounceScale = EaseBounceOut::create(scale);
|
||||||
|
sprite->runAction(bounceScale);
|
||||||
|
|
||||||
|
// 指数缓动
|
||||||
|
auto move = MoveTo::create(2.0f, Vec2(300, 200));
|
||||||
|
auto expoMove = EaseExponentialInOut::create(move);
|
||||||
|
sprite->runAction(expoMove);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 自定义缓动
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 使用自定义缓动函数
|
||||||
|
auto customEase = EaseCustom::create(move, [](float t) {
|
||||||
|
// 自定义缓动函数
|
||||||
|
return t * t * (3.0f - 2.0f * t); // smoothstep
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 特殊动作
|
||||||
|
|
||||||
|
### Speed - 速度控制
|
||||||
|
|
||||||
|
动态控制动作的播放速度:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto move = MoveTo::create(5.0f, Vec2(500, 300));
|
||||||
|
auto speed = Speed::create(move, 0.5f); // 半速播放
|
||||||
|
sprite->runAction(speed);
|
||||||
|
|
||||||
|
// 运行时调整速度
|
||||||
|
speed->setSpeed(2.0f); // 2 倍速
|
||||||
|
```
|
||||||
|
|
||||||
|
### Follow - 跟随动作
|
||||||
|
|
||||||
|
使节点跟随另一个节点移动(常用于相机):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 无边界跟随
|
||||||
|
auto follow = Follow::create(player);
|
||||||
|
|
||||||
|
// 带边界跟随
|
||||||
|
Rect boundary(0, 0, 2000, 2000); // 世界边界
|
||||||
|
auto followWithBoundary = Follow::create(player, boundary);
|
||||||
|
|
||||||
|
camera->runAction(follow);
|
||||||
|
```
|
||||||
|
|
||||||
|
### TargetedAction - 目标动作
|
||||||
|
|
||||||
|
在一个节点上运行动作,但作用于另一个节点:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 在 spriteA 上运行,但影响 spriteB
|
||||||
|
auto targeted = TargetedAction::create(spriteB, MoveTo::create(2.0f, Vec2(100, 100)));
|
||||||
|
spriteA->runAction(targeted);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 瞬时动作
|
||||||
|
|
||||||
|
瞬时动作立即完成,没有动画过程。
|
||||||
|
|
||||||
|
### CallFunc - 回调动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 无参数回调
|
||||||
|
auto callFunc = CallFunc::create([]() {
|
||||||
|
E2D_LOG_INFO("回调执行");
|
||||||
|
});
|
||||||
|
|
||||||
|
// 带节点参数的回调
|
||||||
|
auto callFuncN = CallFuncN::create([](Node* node) {
|
||||||
|
E2D_LOG_INFO("节点: %p", node);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Place - 放置动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 立即放置到指定位置
|
||||||
|
auto place = Place::create(Vec2(100, 100));
|
||||||
|
```
|
||||||
|
|
||||||
|
### FlipX/FlipY - 翻转动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto flipX = FlipX::create(true); // 水平翻转
|
||||||
|
auto flipY = FlipY::create(true); // 垂直翻转
|
||||||
|
```
|
||||||
|
|
||||||
|
### Show/Hide - 显示/隐藏动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto show = Show::create(); // 显示
|
||||||
|
auto hide = Hide::create(); // 隐藏
|
||||||
|
auto toggle = ToggleVisibility::create(); // 切换可见性
|
||||||
|
```
|
||||||
|
|
||||||
|
### RemoveSelf - 移除自身
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 从父节点移除
|
||||||
|
auto removeSelf = RemoveSelf::create();
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 动作管理
|
||||||
|
|
||||||
|
### 停止动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 停止所有动作
|
||||||
|
sprite->stopAllActions();
|
||||||
|
|
||||||
|
// 停止指定动作
|
||||||
|
sprite->stopAction(action);
|
||||||
|
|
||||||
|
// 根据标签停止动作
|
||||||
|
sprite->stopActionByTag(1);
|
||||||
|
|
||||||
|
// 根据标志位停止动作
|
||||||
|
sprite->stopActionsByFlags(0x01);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 查询动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 获取动作数量
|
||||||
|
size_t count = sprite->getActionCount();
|
||||||
|
|
||||||
|
// 检查是否有动作在运行
|
||||||
|
bool running = sprite->isRunningActions();
|
||||||
|
|
||||||
|
// 根据标签获取动作
|
||||||
|
Action* action = sprite->getActionByTag(1);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 动作标签和标志位
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto action = MoveTo::create(2.0f, Vec2(100, 100));
|
||||||
|
action->setTag(1); // 设置标签
|
||||||
|
action->setFlags(0x01); // 设置标志位
|
||||||
|
sprite->runAction(action);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 完整示例
|
||||||
|
|
||||||
|
### 示例 1:角色移动动画
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void Player::moveTo(const Vec2& target) {
|
||||||
|
// 停止当前移动
|
||||||
|
stopActionByTag(TAG_MOVE);
|
||||||
|
|
||||||
|
// 创建移动动作
|
||||||
|
auto move = MoveTo::create(1.0f, target);
|
||||||
|
move->setTag(TAG_MOVE);
|
||||||
|
|
||||||
|
// 添加缓动效果
|
||||||
|
auto easeMove = EaseQuadInOut::create(move);
|
||||||
|
|
||||||
|
runAction(easeMove);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 示例 2:UI 弹出动画
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void UIPanel::show() {
|
||||||
|
// 初始状态
|
||||||
|
setScale(0.0f);
|
||||||
|
setOpacity(0.0f);
|
||||||
|
setVisible(true);
|
||||||
|
|
||||||
|
// 并行动画:缩放 + 淡入
|
||||||
|
auto spawn = Spawn::create(
|
||||||
|
EaseBackOut::create(ScaleTo::create(0.3f, 1.0f)),
|
||||||
|
FadeIn::create(0.3f),
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
runAction(spawn);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 示例 3:游戏结束动画
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void GameOverLayer::playAnimation() {
|
||||||
|
// 从屏幕底部滑入
|
||||||
|
setPosition(Vec2(screenWidth / 2, screenHeight));
|
||||||
|
|
||||||
|
auto moveUp = MoveBy::create(1.0f, Vec2(0, -screenHeight));
|
||||||
|
moveUp->setCompletionCallback([this]() {
|
||||||
|
// 动画完成后启用按钮
|
||||||
|
restartBtn_->setEnabled(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加缓动效果
|
||||||
|
auto easeMove = EaseQuadOut::create(moveUp);
|
||||||
|
runAction(easeMove);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 示例 4:复杂序列动画
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void Enemy::playDeathAnimation() {
|
||||||
|
auto sequence = Sequence::create(
|
||||||
|
// 闪烁
|
||||||
|
Blink::create(0.5f, 3),
|
||||||
|
// 放大
|
||||||
|
ScaleTo::create(0.2f, 1.5f),
|
||||||
|
// 淡出
|
||||||
|
FadeOut::create(0.3f),
|
||||||
|
// 移除自身
|
||||||
|
RemoveSelf::create(),
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
runAction(sequence);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 示例 5:循环动画
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void Coin::startFloating() {
|
||||||
|
// 上下浮动
|
||||||
|
auto floatUp = MoveBy::create(0.5f, Vec2(0, 10));
|
||||||
|
auto floatDown = floatUp->reverse();
|
||||||
|
|
||||||
|
auto floatSequence = Sequence::create(
|
||||||
|
EaseSineInOut::create(floatUp),
|
||||||
|
EaseSineInOut::create(floatDown),
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
// 永久循环
|
||||||
|
auto floatForever = RepeatForever::create(floatSequence);
|
||||||
|
floatForever->setTag(TAG_FLOAT);
|
||||||
|
|
||||||
|
runAction(floatForever);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 性能优化建议
|
||||||
|
|
||||||
|
1. **复用动作**:对于频繁使用的动作,可以 `clone()` 复用
|
||||||
|
2. **合理使用标签**:便于管理和停止特定动作
|
||||||
|
3. **避免过多并发动作**:大量节点同时运行动作会影响性能
|
||||||
|
4. **及时停止不需要的动作**:节点销毁前调用 `stopAllActions()`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API 参考
|
||||||
|
|
||||||
|
### Action 基类
|
||||||
|
|
||||||
|
| 方法 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `isDone()` | 检查动作是否完成 |
|
||||||
|
| `startWithTarget(node)` | 启动动作 |
|
||||||
|
| `stop()` | 停止动作 |
|
||||||
|
| `pause()` | 暂停动作 |
|
||||||
|
| `resume()` | 恢复动作 |
|
||||||
|
| `clone()` | 克隆动作 |
|
||||||
|
| `reverse()` | 创建反向动作 |
|
||||||
|
| `getTag()` / `setTag()` | 获取/设置标签 |
|
||||||
|
| `getFlags()` / `setFlags()` | 获取/设置标志位 |
|
||||||
|
| `setCompletionCallback()` | 设置完成回调 |
|
||||||
|
|
||||||
|
### Node 动作接口
|
||||||
|
|
||||||
|
| 方法 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `runAction(action)` | 运行动作 |
|
||||||
|
| `stopAllActions()` | 停止所有动作 |
|
||||||
|
| `stopAction(action)` | 停止指定动作 |
|
||||||
|
| `stopActionByTag(tag)` | 根据标签停止动作 |
|
||||||
|
| `stopActionsByFlags(flags)` | 根据标志位停止动作 |
|
||||||
|
| `getActionByTag(tag)` | 根据标签获取动作 |
|
||||||
|
| `getActionCount()` | 获取动作数量 |
|
||||||
|
| `isRunningActions()` | 检查是否有动作运行 |
|
||||||
|
|
@ -0,0 +1,678 @@
|
||||||
|
# Extra2D 动作系统重构规格文档
|
||||||
|
|
||||||
|
## 一、概述
|
||||||
|
|
||||||
|
本文档描述了 Extra2D 动作系统的重构方案,参考 Cocos2d-x 的动作系统设计模式,实现一个更加完善、易用、功能丰富的动作系统。
|
||||||
|
|
||||||
|
## 二、现有系统分析
|
||||||
|
|
||||||
|
### 2.1 当前类层次结构
|
||||||
|
|
||||||
|
```
|
||||||
|
Action (基类)
|
||||||
|
├── IntervalAction (有限时间动作基类)
|
||||||
|
│ ├── MoveBy/MoveTo
|
||||||
|
│ ├── ScaleBy/ScaleTo
|
||||||
|
│ ├── RotateBy/RotateTo
|
||||||
|
│ ├── FadeIn/FadeOut/FadeTo
|
||||||
|
│ ├── Sequence
|
||||||
|
│ ├── Spawn
|
||||||
|
│ ├── Delay
|
||||||
|
│ └── Loop
|
||||||
|
└── InstantAction (瞬时动作基类)
|
||||||
|
└── CallFunc
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 与 Cocos2d-x 的差异
|
||||||
|
|
||||||
|
| 特性 | Extra2D 当前 | Cocos2d-x | 差异说明 |
|
||||||
|
|------|-------------|-----------|---------|
|
||||||
|
| 类层次 | Action -> IntervalAction/InstantAction | Action -> FiniteTimeAction -> ActionInterval/ActionInstant | 缺少 FiniteTimeAction 中间层 |
|
||||||
|
| 动作管理 | Node 内部管理 | ActionManager 单例集中管理 | 缺少集中式管理 |
|
||||||
|
| 缓动动作 | EaseAction 静态方法 | ActionEase 类系(装饰器模式) | 不够灵活,无法组合 |
|
||||||
|
| 速度控制 | Action::speed_ 成员 | Speed 动作包装器 | 缺少动态速度控制 |
|
||||||
|
| 跟随动作 | 无 | Follow 类 | 缺失 |
|
||||||
|
| 跳跃动作 | 无 | JumpBy/JumpTo | 缺失 |
|
||||||
|
| 贝塞尔动作 | 无 | BezierBy/BezierTo | 缺失 |
|
||||||
|
| 闪烁动作 | 无 | Blink | 缺失 |
|
||||||
|
| 色调动作 | 无 | TintBy/TintTo | 缺失 |
|
||||||
|
| 重复动作 | Loop | Repeat/RepeatForever | 命名和功能差异 |
|
||||||
|
| 反向动作 | reverse() 方法 | reverse() 方法 | 相同 |
|
||||||
|
| 克隆动作 | clone() 方法 | clone() 方法 | 相同 |
|
||||||
|
|
||||||
|
## 三、重构目标
|
||||||
|
|
||||||
|
### 3.1 核心目标
|
||||||
|
|
||||||
|
1. **完善类层次结构** - 添加 FiniteTimeAction 中间层
|
||||||
|
2. **集中式动作管理** - 实现 ActionManager 单例
|
||||||
|
3. **装饰器模式缓动** - 实现 ActionEase 类系
|
||||||
|
4. **丰富动作类型** - 添加跳跃、贝塞尔、闪烁、色调等动作
|
||||||
|
5. **统一API风格** - 与 Cocos2d-x API 保持一致
|
||||||
|
|
||||||
|
### 3.2 设计原则
|
||||||
|
|
||||||
|
1. **组合优于继承** - 使用装饰器模式实现缓动和速度控制
|
||||||
|
2. **单一职责** - ActionManager 只负责动作调度
|
||||||
|
3. **开放封闭** - 易于扩展新动作类型
|
||||||
|
4. **接口隔离** - 不同类型动作提供不同接口
|
||||||
|
|
||||||
|
## 四、新类层次结构
|
||||||
|
|
||||||
|
```
|
||||||
|
Action (基类)
|
||||||
|
├── FiniteTimeAction (有限时间动作基类)
|
||||||
|
│ ├── ActionInterval (时间间隔动作)
|
||||||
|
│ │ ├── MoveBy/MoveTo
|
||||||
|
│ │ ├── MoveBy3D/MoveTo3D (新增)
|
||||||
|
│ │ ├── JumpBy/JumpTo (新增)
|
||||||
|
│ │ ├── BezierBy/BezierTo (新增)
|
||||||
|
│ │ ├── ScaleBy/ScaleTo
|
||||||
|
│ │ ├── RotateBy/RotateTo
|
||||||
|
│ │ ├── FadeIn/FadeOut/FadeTo
|
||||||
|
│ │ ├── Blink (新增)
|
||||||
|
│ │ ├── TintBy/TintTo (新增)
|
||||||
|
│ │ ├── Sequence
|
||||||
|
│ │ ├── Spawn
|
||||||
|
│ │ ├── DelayTime
|
||||||
|
│ │ ├── Repeat (重命名自 Loop)
|
||||||
|
│ │ ├── RepeatForever (新增)
|
||||||
|
│ │ ├── ReverseTime (新增)
|
||||||
|
│ │ └── ActionEase (缓动动作基类,新增)
|
||||||
|
│ │ ├── EaseIn/EaseOut/EaseInOut
|
||||||
|
│ │ ├── EaseSineIn/EaseSineOut/EaseSineInOut
|
||||||
|
│ │ ├── EaseExponentialIn/EaseExponentialOut/EaseExponentialInOut
|
||||||
|
│ │ ├── EaseBounceIn/EaseBounceOut/EaseBounceInOut
|
||||||
|
│ │ ├── EaseElasticIn/EaseElasticOut/EaseElasticInOut
|
||||||
|
│ │ ├── EaseBackIn/EaseBackOut/EaseBackInOut
|
||||||
|
│ │ └── EaseBezier (新增)
|
||||||
|
│ └── ActionInstant (瞬时动作)
|
||||||
|
│ ├── CallFunc
|
||||||
|
│ ├── CallFuncN (新增)
|
||||||
|
│ ├── Place (新增)
|
||||||
|
│ ├── FlipX/FlipY (新增)
|
||||||
|
│ ├── Show/Hide (新增)
|
||||||
|
│ ├── ToggleVisibility (新增)
|
||||||
|
│ └── RemoveSelf (新增)
|
||||||
|
├── Speed (速度控制动作,新增)
|
||||||
|
├── Follow (跟随动作,新增)
|
||||||
|
└── TargetedAction (目标动作,新增)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 五、核心类设计
|
||||||
|
|
||||||
|
### 5.1 Action 基类
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class Action {
|
||||||
|
public:
|
||||||
|
virtual ~Action() = default;
|
||||||
|
|
||||||
|
// 核心接口
|
||||||
|
virtual bool isDone() const;
|
||||||
|
virtual void startWithTarget(Node* target);
|
||||||
|
virtual void stop();
|
||||||
|
virtual void step(float dt);
|
||||||
|
virtual void update(float time);
|
||||||
|
|
||||||
|
// 克隆和反向
|
||||||
|
virtual Action* clone() const = 0;
|
||||||
|
virtual Action* reverse() const = 0;
|
||||||
|
|
||||||
|
// 属性访问
|
||||||
|
Node* getTarget() const;
|
||||||
|
Node* getOriginalTarget() const;
|
||||||
|
int getTag() const;
|
||||||
|
void setTag(int tag);
|
||||||
|
unsigned int getFlags() const;
|
||||||
|
void setFlags(unsigned int flags);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Node* target_ = nullptr;
|
||||||
|
Node* originalTarget_ = nullptr;
|
||||||
|
int tag_ = -1;
|
||||||
|
unsigned int flags_ = 0;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 FiniteTimeAction 中间层
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class FiniteTimeAction : public Action {
|
||||||
|
public:
|
||||||
|
float getDuration() const { return duration_; }
|
||||||
|
void setDuration(float duration) { duration_ = duration; }
|
||||||
|
|
||||||
|
virtual FiniteTimeAction* clone() const = 0;
|
||||||
|
virtual FiniteTimeAction* reverse() const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
float duration_ = 0.0f;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.3 ActionInterval 时间间隔动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class ActionInterval : public FiniteTimeAction {
|
||||||
|
public:
|
||||||
|
float getElapsed() const { return elapsed_; }
|
||||||
|
bool isDone() const override;
|
||||||
|
|
||||||
|
void startWithTarget(Node* target) override;
|
||||||
|
void step(float dt) override;
|
||||||
|
|
||||||
|
void setAmplitudeRate(float amp) { amplitudeRate_ = amp; }
|
||||||
|
float getAmplitudeRate() const { return amplitudeRate_; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
float elapsed_ = 0.0f;
|
||||||
|
bool firstTick_ = true;
|
||||||
|
float amplitudeRate_ = 1.0f;
|
||||||
|
EaseFunction easeFunc_ = nullptr; // 内置缓动函数
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.4 ActionInstant 瞬时动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class ActionInstant : public FiniteTimeAction {
|
||||||
|
public:
|
||||||
|
bool isDone() const override { return true; }
|
||||||
|
void step(float dt) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool done_ = false;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.5 ActionManager 动作管理器
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class ActionManager {
|
||||||
|
public:
|
||||||
|
static ActionManager* getInstance();
|
||||||
|
|
||||||
|
// 动作管理
|
||||||
|
void addAction(Action* action, Node* target, bool paused = false);
|
||||||
|
void removeAction(Action* action);
|
||||||
|
void removeActionByTag(int tag, Node* target);
|
||||||
|
void removeAllActionsFromTarget(Node* target);
|
||||||
|
void removeAllActions();
|
||||||
|
|
||||||
|
// 查询
|
||||||
|
Action* getActionByTag(int tag, Node* target);
|
||||||
|
size_t getActionCount(Node* target) const;
|
||||||
|
|
||||||
|
// 暂停/恢复
|
||||||
|
void pauseTarget(Node* target);
|
||||||
|
void resumeTarget(Node* target);
|
||||||
|
bool isPaused(Node* target) const;
|
||||||
|
|
||||||
|
// 更新(每帧调用)
|
||||||
|
void update(float dt);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct ActionElement {
|
||||||
|
std::vector<Action*> actions;
|
||||||
|
Node* target;
|
||||||
|
bool paused;
|
||||||
|
int actionIndex;
|
||||||
|
Action* currentAction;
|
||||||
|
bool currentActionSalvaged;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<Node*, ActionElement> targets_;
|
||||||
|
static ActionManager* instance_;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.6 ActionEase 缓动动作基类
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class ActionEase : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static ActionEase* create(ActionInterval* action);
|
||||||
|
|
||||||
|
ActionInterval* getInnerAction() const { return innerAction_; }
|
||||||
|
|
||||||
|
void startWithTarget(Node* target) override;
|
||||||
|
void stop() override;
|
||||||
|
void update(float time) override;
|
||||||
|
Action* reverse() const override;
|
||||||
|
Action* clone() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ActionInterval* innerAction_ = nullptr;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.7 Speed 速度控制动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class Speed : public Action {
|
||||||
|
public:
|
||||||
|
static Speed* create(ActionInterval* action, float speed);
|
||||||
|
|
||||||
|
float getSpeed() const { return speed_; }
|
||||||
|
void setSpeed(float speed) { speed_ = speed; }
|
||||||
|
|
||||||
|
void startWithTarget(Node* target) override;
|
||||||
|
void stop() override;
|
||||||
|
void step(float dt) override;
|
||||||
|
bool isDone() const override;
|
||||||
|
Action* reverse() const override;
|
||||||
|
Action* clone() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ActionInterval* innerAction_ = nullptr;
|
||||||
|
float speed_ = 1.0f;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## 六、新增动作类型
|
||||||
|
|
||||||
|
### 6.1 JumpBy/JumpTo 跳跃动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class JumpBy : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static JumpBy* create(float duration, const Vec2& position,
|
||||||
|
float height, int jumps);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Vec2 startPosition_;
|
||||||
|
Vec2 delta_;
|
||||||
|
float height_;
|
||||||
|
int jumps_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class JumpTo : public JumpBy {
|
||||||
|
// 继承实现,目标位置版本
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 BezierBy/BezierTo 贝塞尔动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct BezierConfig {
|
||||||
|
Vec2 controlPoint1;
|
||||||
|
Vec2 controlPoint2;
|
||||||
|
Vec2 endPosition;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BezierBy : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static BezierBy* create(float duration, const BezierConfig& config);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BezierConfig config_;
|
||||||
|
Vec2 startPosition_;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.3 Blink 闪烁动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class Blink : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static Blink* create(float duration, int times);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int times_;
|
||||||
|
int currentTimes_;
|
||||||
|
bool originalVisible_;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.4 TintBy/TintTo 色调动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class TintTo : public ActionInterval {
|
||||||
|
public:
|
||||||
|
static TintTo* create(float duration,
|
||||||
|
uint8_t red, uint8_t green, uint8_t blue);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Color3B startColor_;
|
||||||
|
Color3B endColor_;
|
||||||
|
Color3B deltaColor_;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.5 Follow 跟随动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class Follow : public Action {
|
||||||
|
public:
|
||||||
|
static Follow* create(Node* followedNode,
|
||||||
|
const Rect& boundary = Rect::ZERO);
|
||||||
|
|
||||||
|
bool isDone() const override;
|
||||||
|
void step(float dt) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Node* followedNode_ = nullptr;
|
||||||
|
Rect boundary_;
|
||||||
|
bool boundarySet_ = false;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.6 瞬时动作扩展
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 放置到指定位置
|
||||||
|
class Place : public ActionInstant {
|
||||||
|
public:
|
||||||
|
static Place* create(const Vec2& position);
|
||||||
|
};
|
||||||
|
|
||||||
|
// X/Y轴翻转
|
||||||
|
class FlipX : public ActionInstant {
|
||||||
|
public:
|
||||||
|
static FlipX* create(bool flipX);
|
||||||
|
};
|
||||||
|
|
||||||
|
class FlipY : public ActionInstant {
|
||||||
|
public:
|
||||||
|
static FlipY* create(bool flipY);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 显示/隐藏
|
||||||
|
class Show : public ActionInstant {
|
||||||
|
public:
|
||||||
|
static Show* create();
|
||||||
|
};
|
||||||
|
|
||||||
|
class Hide : public ActionInstant {
|
||||||
|
public:
|
||||||
|
static Hide* create();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 切换可见性
|
||||||
|
class ToggleVisibility : public ActionInstant {
|
||||||
|
public:
|
||||||
|
static ToggleVisibility* create();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 移除自身
|
||||||
|
class RemoveSelf : public ActionInstant {
|
||||||
|
public:
|
||||||
|
static RemoveSelf* create();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 带Node参数的回调
|
||||||
|
class CallFuncN : public ActionInstant {
|
||||||
|
public:
|
||||||
|
static CallFuncN* create(const std::function<void(Node*)>& func);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## 七、缓动动作完整实现
|
||||||
|
|
||||||
|
### 7.1 通用缓动包装器
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 通用缓动包装器
|
||||||
|
class EaseCustom : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseCustom* create(ActionInterval* action,
|
||||||
|
EaseFunction easeFunc);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 指数缓动
|
||||||
|
class EaseExponentialIn : public ActionEase { /* ... */ };
|
||||||
|
class EaseExponentialOut : public ActionEase { /* ... */ };
|
||||||
|
class EaseExponentialInOut : public ActionEase { /* ... */ };
|
||||||
|
|
||||||
|
// 正弦缓动
|
||||||
|
class EaseSineIn : public ActionEase { /* ... */ };
|
||||||
|
class EaseSineOut : public ActionEase { /* ... */ };
|
||||||
|
class EaseSineInOut : public ActionEase { /* ... */ };
|
||||||
|
|
||||||
|
// 弹性缓动
|
||||||
|
class EaseElasticIn : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseElasticIn* create(ActionInterval* action, float period = 0.3f);
|
||||||
|
};
|
||||||
|
class EaseElasticOut : public ActionEase { /* ... */ };
|
||||||
|
class EaseElasticInOut : public ActionEase { /* ... */ };
|
||||||
|
|
||||||
|
// 弹跳缓动
|
||||||
|
class EaseBounceIn : public ActionEase { /* ... */ };
|
||||||
|
class EaseBounceOut : public ActionEase { /* ... */ };
|
||||||
|
class EaseBounceInOut : public ActionEase { /* ... */ };
|
||||||
|
|
||||||
|
// 回震缓动
|
||||||
|
class EaseBackIn : public ActionEase { /* ... */ };
|
||||||
|
class EaseBackOut : public ActionEase { /* ... */ };
|
||||||
|
class EaseBackInOut : public ActionEase { /* ... */ };
|
||||||
|
|
||||||
|
// 贝塞尔缓动(自定义曲线)
|
||||||
|
class EaseBezier : public ActionEase {
|
||||||
|
public:
|
||||||
|
static EaseBezier* create(ActionInterval* action);
|
||||||
|
void setBezierParamer(float p0, float p1, float p2, float p3);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## 八、Node 类接口更新
|
||||||
|
|
||||||
|
### 8.1 动作相关接口
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class Node {
|
||||||
|
public:
|
||||||
|
// 运行动作
|
||||||
|
Action* runAction(Action* action);
|
||||||
|
|
||||||
|
// 停止动作
|
||||||
|
void stopAllActions();
|
||||||
|
void stopAction(Action* action);
|
||||||
|
void stopActionByTag(int tag);
|
||||||
|
void stopActionsByFlags(unsigned int flags);
|
||||||
|
|
||||||
|
// 获取动作
|
||||||
|
Action* getActionByTag(int tag);
|
||||||
|
size_t getNumberOfRunningActions() const;
|
||||||
|
|
||||||
|
// 暂停/恢复所有动作
|
||||||
|
void pauseAllActions();
|
||||||
|
void resumeAllActions();
|
||||||
|
|
||||||
|
// 检查是否有动作在运行
|
||||||
|
bool isRunningActions() const;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## 九、使用示例
|
||||||
|
|
||||||
|
### 9.1 基本动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 移动
|
||||||
|
auto moveTo = MoveTo::create(2.0f, Vec2(100, 100));
|
||||||
|
sprite->runAction(moveTo);
|
||||||
|
|
||||||
|
// 跳跃
|
||||||
|
auto jump = JumpBy::create(2.0f, Vec2(200, 0), 100, 3);
|
||||||
|
sprite->runAction(jump);
|
||||||
|
|
||||||
|
// 贝塞尔曲线
|
||||||
|
BezierConfig bezier;
|
||||||
|
bezier.controlPoint1 = Vec2(100, 200);
|
||||||
|
bezier.controlPoint2 = Vec2(200, 100);
|
||||||
|
bezier.endPosition = Vec2(300, 150);
|
||||||
|
auto bezierAction = BezierTo::create(3.0f, bezier);
|
||||||
|
sprite->runAction(bezierAction);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.2 组合动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 序列动作
|
||||||
|
auto seq = Sequence::create(
|
||||||
|
MoveTo::create(1.0f, Vec2(100, 100)),
|
||||||
|
DelayTime::create(0.5f),
|
||||||
|
FadeOut::create(1.0f),
|
||||||
|
CallFunc::create([](){ log("Done!"); }),
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
sprite->runAction(seq);
|
||||||
|
|
||||||
|
// 并行动作
|
||||||
|
auto spawn = Spawn::create(
|
||||||
|
MoveTo::create(2.0f, Vec2(200, 200)),
|
||||||
|
RotateBy::create(2.0f, 360),
|
||||||
|
FadeIn::create(2.0f),
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
sprite->runAction(spawn);
|
||||||
|
|
||||||
|
// 重复动作
|
||||||
|
auto repeat = Repeat::create(MoveBy::create(1.0f, Vec2(50, 0)), 5);
|
||||||
|
sprite->runAction(repeat);
|
||||||
|
|
||||||
|
// 永久重复
|
||||||
|
auto repeatForever = RepeatForever::create(
|
||||||
|
Sequence::create(
|
||||||
|
MoveBy::create(1.0f, Vec2(100, 0)),
|
||||||
|
MoveBy::create(1.0f, Vec2(-100, 0)),
|
||||||
|
nullptr
|
||||||
|
)
|
||||||
|
);
|
||||||
|
sprite->runAction(repeatForever);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.3 缓动动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 使用缓动包装器
|
||||||
|
auto move = MoveTo::create(3.0f, Vec2(500, 300));
|
||||||
|
auto easeMove = EaseElasticOut::create(move, 0.5f);
|
||||||
|
sprite->runAction(easeMove);
|
||||||
|
|
||||||
|
// 指数缓动
|
||||||
|
auto jump = JumpBy::create(2.0f, Vec2(200, 0), 100, 1);
|
||||||
|
auto easeJump = EaseExponentialOut::create(jump);
|
||||||
|
sprite->runAction(easeJump);
|
||||||
|
|
||||||
|
// 弹跳缓动
|
||||||
|
auto scale = ScaleTo::create(1.0f, 2.0f);
|
||||||
|
auto bounceScale = EaseBounceOut::create(scale);
|
||||||
|
sprite->runAction(bounceScale);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.4 速度控制
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 慢动作回放
|
||||||
|
auto action = MoveTo::create(5.0f, Vec2(500, 300));
|
||||||
|
auto speed = Speed::create(action, 0.5f); // 半速
|
||||||
|
sprite->runAction(speed);
|
||||||
|
|
||||||
|
// 动态调整速度
|
||||||
|
speed->setSpeed(2.0f); // 2倍速
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.5 跟随动作
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 相机跟随玩家
|
||||||
|
auto follow = Follow::create(player, Rect(0, 0, 2000, 2000));
|
||||||
|
camera->runAction(follow);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 十、文件结构
|
||||||
|
|
||||||
|
```
|
||||||
|
Extra2D/include/extra2d/action/
|
||||||
|
├── action.h # Action 基类
|
||||||
|
├── finite_time_action.h # FiniteTimeAction 中间层
|
||||||
|
├── action_interval.h # ActionInterval 及其子类
|
||||||
|
├── action_instant.h # ActionInstant 及其子类
|
||||||
|
├── action_ease.h # 缓动动作类系
|
||||||
|
├── action_manager.h # ActionManager
|
||||||
|
├── ease_functions.h # 缓动函数
|
||||||
|
└── action_factory.h # 动作工厂(可选)
|
||||||
|
|
||||||
|
Extra2D/src/action/
|
||||||
|
├── action.cpp
|
||||||
|
├── finite_time_action.cpp
|
||||||
|
├── action_interval.cpp
|
||||||
|
├── action_instant.cpp
|
||||||
|
├── action_ease.cpp
|
||||||
|
├── action_manager.cpp
|
||||||
|
└── ease_functions.cpp
|
||||||
|
```
|
||||||
|
|
||||||
|
## 十一、实现优先级
|
||||||
|
|
||||||
|
### 第一阶段(核心重构)
|
||||||
|
1. Action 基类重构
|
||||||
|
2. FiniteTimeAction 中间层
|
||||||
|
3. ActionInterval 重构
|
||||||
|
4. ActionInstant 重构
|
||||||
|
5. ActionManager 实现
|
||||||
|
|
||||||
|
### 第二阶段(新增动作)
|
||||||
|
1. JumpBy/JumpTo
|
||||||
|
2. BezierBy/BezierTo
|
||||||
|
3. Blink
|
||||||
|
4. TintBy/TintTo
|
||||||
|
5. Follow
|
||||||
|
6. Speed
|
||||||
|
|
||||||
|
### 第三阶段(缓动系统)
|
||||||
|
1. ActionEase 基类
|
||||||
|
2. 各类缓动包装器
|
||||||
|
3. EaseCustom 自定义缓动
|
||||||
|
|
||||||
|
### 第四阶段(瞬时动作扩展)
|
||||||
|
1. Place
|
||||||
|
2. FlipX/FlipY
|
||||||
|
3. Show/Hide
|
||||||
|
4. ToggleVisibility
|
||||||
|
5. RemoveSelf
|
||||||
|
6. CallFuncN
|
||||||
|
|
||||||
|
## 十二、兼容性考虑
|
||||||
|
|
||||||
|
### 12.1 API 变更
|
||||||
|
|
||||||
|
- 动作创建方式改为 `create()` 静态工厂方法
|
||||||
|
- `Loop` 重命名为 `Repeat`
|
||||||
|
- `Delay` 重命名为 `DelayTime`
|
||||||
|
- 动作管理由 `ActionManager` 集中处理
|
||||||
|
|
||||||
|
### 12.2 迁移指南
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 旧写法
|
||||||
|
auto action = std::make_shared<MoveTo>(2.0f, Vec2(100, 100));
|
||||||
|
sprite->runAction(action);
|
||||||
|
|
||||||
|
// 新写法(推荐)
|
||||||
|
auto action = MoveTo::create(2.0f, Vec2(100, 100));
|
||||||
|
sprite->runAction(action);
|
||||||
|
|
||||||
|
// 旧写法(缓动)
|
||||||
|
auto action = EaseAction::create(MoveTo::create(2.0f, Vec2(100, 100)), easeInQuad);
|
||||||
|
|
||||||
|
// 新写法(缓动)
|
||||||
|
auto action = EaseQuadIn::create(MoveTo::create(2.0f, Vec2(100, 100)));
|
||||||
|
```
|
||||||
|
|
||||||
|
## 十三、性能优化
|
||||||
|
|
||||||
|
1. **对象池集成** - 动作对象使用对象池管理
|
||||||
|
2. **批量更新** - ActionManager 统一调度减少调用开销
|
||||||
|
3. **延迟删除** - 动作完成时标记删除,统一清理
|
||||||
|
4. **缓存友好** - 连续存储同一类型动作
|
||||||
|
|
||||||
|
## 十四、测试计划
|
||||||
|
|
||||||
|
1. 单元测试:每个动作类型的独立测试
|
||||||
|
2. 集成测试:组合动作测试
|
||||||
|
3. 性能测试:大量动作并发测试
|
||||||
|
4. 内存测试:动作对象生命周期测试
|
||||||
|
|
@ -44,8 +44,7 @@ void GameOverLayer::onEnter() {
|
||||||
initButtons();
|
initButtons();
|
||||||
|
|
||||||
// 创建向上移动的动画(从屏幕底部移动到正常位置)
|
// 创建向上移动的动画(从屏幕底部移动到正常位置)
|
||||||
auto moveAction = extra2d::makePtr<extra2d::MoveBy>(
|
auto moveAction = extra2d::MoveBy::create(1.0f, extra2d::Vec2(0.0f, -screenHeight));
|
||||||
1.0f, extra2d::Vec2(0.0f, -screenHeight));
|
|
||||||
moveAction->setCompletionCallback([this]() {
|
moveAction->setCompletionCallback([this]() {
|
||||||
animationDone_ = true;
|
animationDone_ = true;
|
||||||
if (restartBtn_)
|
if (restartBtn_)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue