快速开始
本指南将带你克隆运行时、编译它,并使用真实的 GPU 后端将一个
.riv 文件显示到屏幕上。
前提条件
- 支持 C++17 的较新版本 clang 或 MSVC。
- git — 构建脚本会自行克隆并引导
premake5。 - 你所选择渲染器对应的平台 SDK(用于 D3D 的 Windows SDK、用于 Metal 的 Xcode、用于 Vulkan 的 Vulkan SDK 等)。
Rive 使用 clang vector builtins。使用 clang 构建时,请使用可用的最新版本 — 较旧的工具链可能无法编译渲染器。
1. 克隆并构建运行时
git clone https://github.com/rive-app/rive-runtime.git
cd rive-runtime/renderer
运行时随附了一个构建辅助脚本 build/build_rive.sh(Windows 上有
PowerShell 包装脚本 build_rive.ps1)。它会在首次运行时安装固定版本的
premake5,并根据你的平台分发到正确的构建系统
(macOS/Linux 上的 gmake2、Windows 上的 MSBuild 等)。
macOS / Linux:
../build/build_rive.sh release
Windows:
..\build\build_rive.ps1 release
常见变体:
build_rive.sh(无参数)— 为宿主平台进行 debug 构建。build_rive.sh release clean— 清理后重新构建。build_rive.sh ninja release— 使用 Ninja 而不是 make。build_rive.sh ios release/build_rive.sh android release— 交叉编译。
构建产物位于 out/release/(或 out/debug/)。你需要链接
librive.a(Windows 上为 rive.lib),以及各后端渲染器库,例如
librive_pls_renderer.a。
2. 将头文件添加到你的项目
公共 include 根目录为:
rive-runtime/include # rive-cpp core
rive-runtime/renderer/include # GPU renderer (only if you use rive::gpu)
一个最小 CMake 片段:
target_include_directories(my_app PRIVATE
${RIVE}/include
${RIVE}/renderer/include
)
target_link_libraries(my_app PRIVATE
rive
rive_pls_renderer
# plus your backend, e.g. d3d11, dxgi on Windows
)
3. 加载 .riv 文件
#include "rive/file.hpp"
#include <fstream>
#include <iterator>
#include <vector>
using namespace rive;
std::vector<uint8_t> readFile(const char* path) {
std::ifstream in(path, std::ios::binary);
return {std::istreambuf_iterator<char>(in), {}};
}
// `factory` is a Factory* — usually your RenderContext (which inherits Factory).
auto bytes = readFile("hero.riv");
ImportResult result;
rcp<File> file = File::import(bytes, factory, &result);
if (!file || result != ImportResult::success) {
// Bad file or unsupported version.
return;
}
4. 选择 Artboard 和 State Machine
#include "rive/artboard.hpp"
#include "rive/animation/state_machine_instance.hpp"
std::unique_ptr<ArtboardInstance> artboard = file->artboardDefault();
std::unique_ptr<StateMachineInstance> sm = artboard->defaultStateMachine();
if (!sm && artboard->stateMachineCount() > 0) {
sm = artboard->stateMachineAt(0);
}
5. Advance 并绘制
渲染循环每帧包含三个阶段:advance、draw、flush。
#include "rive/renderer/rive_renderer.hpp"
#include "rive/renderer/render_context.hpp"
void renderFrame(float dt) {
sm->advanceAndApply(dt);
RenderContext::FrameDescriptor frame{};
frame.renderTargetWidth = windowWidth;
frame.renderTargetHeight = windowHeight;
frame.clearColor = 0xff202020; // ARGB
renderContext->beginFrame(frame);
RiveRenderer renderer(renderContext.get());
renderer.save();
renderer.align(Fit::contain,
Alignment::center,
AABB(0, 0, windowWidth, windowHeight),
artboard->bounds());
sm->draw(&renderer);
renderer.restore();
RenderContext::FlushResources flush{};
flush.renderTarget = renderTarget.get();
renderContext->flush(flush);
}
💡
对 advanceAndApply 使用固定时间步长(例如 1/120s),并累计真实经过时间。在固定步长下,状态机是确定性的,这能让播放在不同机器和帧率上保持可复现。参见
Rendering Loop。
6. 转发输入
将指针事件路由回状态机,以便监听器和命中测试能够正常工作:
#include "rive/renderer.hpp"
Mat2D align = computeAlignment(Fit::contain,
Alignment::center,
AABB(0, 0, w, h),
artboard->bounds());
Vec2D toArtboard(int x, int y) {
return align.invertOrIdentity() * Vec2D{(float)x, (float)y};
}
sm->pointerMove(toArtboard(mouseX, mouseY));
sm->pointerDown(toArtboard(mouseX, mouseY));
sm->pointerUp(toArtboard(mouseX, mouseY));