Extra2D/docs/API_Tutorial/09_Action_System.md

599 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 动作系统 (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);
}
```
### 示例 2UI 弹出动画
```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()` | 检查是否有动作运行 |