599 lines
13 KiB
Markdown
599 lines
13 KiB
Markdown
# 动作系统 (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()` | 检查是否有动作运行 |
|