17 KiB
17 KiB
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 核心目标
- 完善类层次结构 - 添加 FiniteTimeAction 中间层
- 集中式动作管理 - 实现 ActionManager 单例
- 装饰器模式缓动 - 实现 ActionEase 类系
- 丰富动作类型 - 添加跳跃、贝塞尔、闪烁、色调等动作
- 统一API风格 - 与 Cocos2d-x API 保持一致
3.2 设计原则
- 组合优于继承 - 使用装饰器模式实现缓动和速度控制
- 单一职责 - ActionManager 只负责动作调度
- 开放封闭 - 易于扩展新动作类型
- 接口隔离 - 不同类型动作提供不同接口
四、新类层次结构
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 基类
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 中间层
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 时间间隔动作
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 瞬时动作
class ActionInstant : public FiniteTimeAction {
public:
bool isDone() const override { return true; }
void step(float dt) override;
protected:
bool done_ = false;
};
5.5 ActionManager 动作管理器
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 缓动动作基类
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 速度控制动作
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 跳跃动作
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 贝塞尔动作
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 闪烁动作
class Blink : public ActionInterval {
public:
static Blink* create(float duration, int times);
protected:
int times_;
int currentTimes_;
bool originalVisible_;
};
6.4 TintBy/TintTo 色调动作
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 跟随动作
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 瞬时动作扩展
// 放置到指定位置
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 通用缓动包装器
// 通用缓动包装器
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 动作相关接口
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 基本动作
// 移动
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 组合动作
// 序列动作
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 缓动动作
// 使用缓动包装器
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 速度控制
// 慢动作回放
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 跟随动作
// 相机跟随玩家
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
十一、实现优先级
第一阶段(核心重构)
- Action 基类重构
- FiniteTimeAction 中间层
- ActionInterval 重构
- ActionInstant 重构
- ActionManager 实现
第二阶段(新增动作)
- JumpBy/JumpTo
- BezierBy/BezierTo
- Blink
- TintBy/TintTo
- Follow
- Speed
第三阶段(缓动系统)
- ActionEase 基类
- 各类缓动包装器
- EaseCustom 自定义缓动
第四阶段(瞬时动作扩展)
- Place
- FlipX/FlipY
- Show/Hide
- ToggleVisibility
- RemoveSelf
- CallFuncN
十二、兼容性考虑
12.1 API 变更
- 动作创建方式改为
create()静态工厂方法 Loop重命名为RepeatDelay重命名为DelayTime- 动作管理由
ActionManager集中处理
12.2 迁移指南
// 旧写法
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)));
十三、性能优化
- 对象池集成 - 动作对象使用对象池管理
- 批量更新 - ActionManager 统一调度减少调用开销
- 延迟删除 - 动作完成时标记删除,统一清理
- 缓存友好 - 连续存储同一类型动作
十四、测试计划
- 单元测试:每个动作类型的独立测试
- 集成测试:组合动作测试
- 性能测试:大量动作并发测试
- 内存测试:动作对象生命周期测试