状态机
StateMachineInstance 是 C++ 中的播放单元:
class StateMachineInstance {
public:
bool advanceAndApply(float elapsedSeconds);
void draw(Renderer*);
HitResult pointerDown(Vec2D, int pointerId = 0);
HitResult pointerMove(Vec2D, float timeStamp = 0, int pointerId = 0);
HitResult pointerUp(Vec2D, int pointerId = 0);
HitResult pointerExit(Vec2D, int pointerId = 0);
};
如果要驱动状态机——设置值、触发 trigger、响应变化——请使用 Data Binding。参见 Data Binding。
Advancing
advanceAndApply(dt) 会运行 solver(状态机、动画、布局、数据绑定),推进 dt 秒,并将结果应用到 artboard 的组件图。每次绘制前都应调用:
sm->advanceAndApply(deltaSeconds);
sm->draw(&renderer);
返回值为 true 表示状态机仍在动画中,下一帧需要重绘;false 表示一切已经稳定。
提示
使用固定时间步长累加器。固 定步长下状态机和动画具有数值确定性,可以在不同帧率下保持一致播放。参见 Rendering Loop。
强制执行布局计算
传入 dt = 0 可以在不推进时间的情况下重新计算布局。它常用于窗口尺寸变化,或修改 artboard 的 width() / height() 之后:
artboard->width(newWidth);
artboard->height(newHeight);
sm->advanceAndApply(0.f);
指针事件
状态机会监听编辑器中放置在 Listener 组件上的指针事件。转发前,请先将窗口坐标映射到 artboard-local 空间:
#include "rive/renderer.hpp"
Mat2D align = computeAlignment(
Fit::contain,
Alignment::center,
AABB(0, 0, windowWidth, windowHeight),
artboard->bounds());
Vec2D toArtboard(int x, int y) {
return align.invertOrIdentity() * Vec2D{(float)x, (float)y};
}
sm->pointerMove(toArtboard(mx, my));
sm->pointerDown(toArtboard(mx, my));
sm->pointerUp(toArtboard(mx, my));
sm->pointerExit(toArtboard(mx, my));
HitResult 会返回三个值之一,告诉你如何把同一个事件路由到 Rive 背后的其他 UI:
none—— 事件穿过 Rive,未触发 listener。可以转发给背后的 UI。hit—— listener 被触发,但所在形状是透明的。Rive 不阻挡事件,也可以继续转发。hitOpaque—— listener 被触发且形状不透明。Rive 消费了事件,不要继续转发。
读取状态变化
每次 advanceAndApply 后,你可以检查 StateMachineInstance 上发生了什么:
for (size_t i = 0, n = sm->stateChangedCount(); i < n; ++i) {
const LayerState* s = sm->stateChangedByIndex(i);
// s->name(), s->is<AnimationState>(), 等等。
}
这个 hook 可用于在 C++ 中响应 .riv 文件里定义的状态变化,例如记录分析事件、播放音效,或回调到你的引擎。