NTTドコモR&Dの技術ブログです。

Unityの2Dアニメーションをリッチにしよう② ~Rive編~

※ 本記事は 2026/3/31 以前にNTTコノキューにて記載した記事になります

Image from Gyazo

0. はじめに

この記事はNTTコノキュー アドベントカレンダー2025の記事です。

こんにちは。NTTコノキューの高木です。こちらの記事は前回のLottie編の続きとなります。

Riveは比較的新しい2Dアニメーションのフォーマットで、フォーマットだけでなく専用のデザインエディタやランタイム(描画エンジン)が用意されています。

Lottieとの大きな違いとしては『インタラクティブ性』と『ステートフル』が挙げられています。まだ日本ではあまり導入されていませんが、海外では某英会話アプリ等々、少しずつ利用され始めています。採用事例

本記事は、RiveのUnity活用の導入部分が中心になります。

1. Riveとは

Riveは2022年に発表されたインタラクティブなアニメーションを特徴とした2Dアニメーションツールで、アニメーションを作成するデザインツールであるEditorと、それを多様なプラットフォームで実行できるRuntimeの2つがあります。

エクスポートされたファイルである.rivはRive独自の軽量バイナリフォーマットで、Lottieファイル以上の小ささを誇ります。また、ランタイムライブラリは全てOSSで公開されています。

Riveの特徴

1.1 Riveのメリット・デメリット

1.1.1 Riveのメリット

  • Lottie以上のファイルサイズ削減 : Lottieの1/10程度のファイルサイズ

  • 解像度非依存:ベクターファイルであるため解像度を変更しても品質が変わらない

  • クロスプラットフォーム : Web/モバイル/PC等で再生するランタイムが存在する

  • 描画負荷が低い : 独自のGPUレンダリングエンジンにより描画

  • インタラクティブ性 : ステートマシン機能をRive自体が持つ

  • 教材の充実:公式ドキュメント・サンプル・動画チュートリアルが豊富(※英語)

  • サウンド連携:ステートマシンと音を連携し、SEを簡単にアニメーションにフィット

  • データバインディング機能(β) : MVVMにおけるVMをRive自体がサポート

  • Unity/Unreal対応(β) : ゲームエンジン向けランタイムを公式が用意

1.1.2 Riveのデメリット

  • エクスポートが有料:Rive Editorを使いエクスポートするのにサブスク加入が必要

  • 情報の少なさ : 新しいツールであるため、情報が少なく日本語は更に少ない

  • 既存資産との互換性の低さ : AfterEffectsなどを使えず、独自エディタのみ

  • インタラクティブ性 : アニメーションのブレンドや複雑な状態・分岐を持たせられない

  • アプリサイズの増加 : 独自のレンダリングエンジンを組み込むためサイズが大きくなる

1.2 他との比較

前回と同じ内容となります。

項目 Lottie Sprite Animation Rive
Unity対応 🔺
知名度 🔺
ファイルサイズ 🔺
インタラクティブ性 🔺
CPU負荷 🔺
GPU負荷 🔺
RAM消費
音の組み込み

1.3 ワークスペースにおけるメンバー権限

料金を考える前に、Workspace(組織)におけるメンバーの権限(ロール)を理解する必要があります。

ロール名 Admin / Editor Visitor
エクスポート (.riv) ✅️ ✅️
バックアップ用エクスポート (.rev) ✅️ ❌️
編集 ✅️ ❌️
閲覧 ✅️ ✅️
早期アクセス機能の利用 ✅️ ❌️

基本的に、デザイナーはEditor, エンジニアはVisitorという振り分けになると思います。Unity等ランタイム向けのエクスポートはVisitorでも出来るため、以下のフローはこの振り分けでも実現します。

  1. エンジニアがデザイナに修正を依頼する

  2. デザイナがRive Editorで修正する

  3. エンジニアがRive EditorでUnity向けに最終確認してエクスポートする (エクスポートした.rivをデザイナから受け取ることも可能)

1.4 Riveの料金プラン

Rive EditorにおけるImportは無料で可能(※ファイル数制限アリ)ですが、Exportには有料プランが必須です。

注意点として、RIveのシートライセンスは個人ではなくWorkspaceに紐付きます。

エクスポートや共同編集複数人で行う必要があるワークスペースにはCadetプラン以上が必須になります。Visitorは無制限となります。

Rive料金プラン

ただし、CadetではEditorはAdmin含め3名まで、Editorが4名以上になる場合はVoyagerプランが求められます。

Rive Editor人数制限

チーム規模、Riveを使うデザイナーが何名か最初に見積もることを推奨します。

詳しくはRive公式のPlansを参照してください。

2. Unity Runtimeを使いUnityでRiveを動かす

2.1 RiveのUnityサンプルについて

Riveは公式のUnityサンプルを用意しており、.rivが含まれているため課金せずともUnity上での動きやスクリプトの書き方は学ぶことができます。

サンプルがカッコイイのって大事ですよね。こちらのサンプルはdemo/Buidingsに用意されています。

2.2 RiveのUnityサンプルの構成

大きく3つのサンプルプロジェクトが用意されています。

  1. demo (見栄え重視、複雑なサンプルが多いが、mainブランチには不具合も...)

  2. getting-started (シンプルなサンプルが多く、最初に見るのにおすすめ)

  3. low-level-api (低レベルAPIのサンプル。Riveを細かく制御したい中上級者向け)

各プロジェクトに様々なサンプル、Riveファイルがあるので今回は2. getting-startedを入門編として扱います。

2.3 サンプルからRiveを読み解く

2.3.1 EventSceneサンプルを実行する

getting-startedプロジェクトをUnity Hubから開きます。Unity 6000系で開くことが出来ます。

Assets/Scenes/EventScene.unityを開くと、星が5個並んだシーンが開くので、早速実行してみましょう。

このように、ユーザー操作に応じたインタラクションを表現できることがRiveの強み。このサンプルは地味ですがぷにゅっとした動きが良いですね。最もシンプルなのでこちらのサンプルから色々見て行きます。

なお、このサンプルではUnityのCanvas/Panelを使いますが、3Dモデルに貼り付けるサンプルである「DrawToCube」サンプルも存在します。

2.3.2 Riveのコンポーネントを見る

Unityのシーンはシンプルで、Canvasのみ着目すればOKです。Canvasのうち一番深い階層であるRive Widgetオブジェクトから見て行きます。

Rive Widgetコンポーネント

このオブジェクトにはRive Widgetコンポーネントがあり、このコンポーネントは主に設定します。

  1. Asset:何のRiveファイル(.riv)を利用するか

  2. Artboard Name:どのアートボードを利用するか

  3. State Machine Name:どのステートマシンを利用するか

  4. Display: 表示の方法(アスペクト比を維持するかなど)

1.のAssetを変更することで、利用したい.rivを指定することが出来ます。

次に、その親であるRive Panelを見ます。

Rive Panel

これは、UnityにおけるPanelのRive対応と認識すればOKです。カスタマイズ要素はありますが基本的にはデフォルトで構いません。
このRive Panelの子であるRive Widgetは正しく表示されます。

最後に、Canvasを見てみましょう。

Canvas構成

ReportedEventListenerというC#スクリプトがアタッチされ、Rive Widgetを参照しています。
これはこのサンプルのためのスクリプトであり、Canvas自体にRive関連のコンポーネントが必須な訳ではありません。このスクリプトには最小のスクリプトがあるのでこれを見てみます。

2.3.3 Riveと連携するスクリプトを見る

ReportedEventListener.csはRiveが発行するイベントをUnity側で受け取るスクリプトになっています。

RiveWidget.OnRiveEventReportedを購読し、イベントが発行されたらそのイベントの名前がrating〜であれば、rating(float), message(string)を取得しログに表示されます。

実際に、実行時にログを見るとクリック時に評価に沿ったログが表示されています。
ここから、Riveが発行するイベントとプロパティをUnityが取得できることがわかります。

実行時のログ

2.3.4 Riveの「イベント」について

そもそもRiveにおけるイベントとは何なのでしょうか?先ほどのサンプルで動作を確認するにはRive Editorで確認する必要がありますが、残念ながらリポジトリ上配布していないため再現したものをマーケットプレイスで公開しました。

マーケットプレイス

マーケットプレイスで簡易的な動作確認もできますが、「Preview in Rive」でその作品をVisitorとしてRive Editorで見ることが出来ます。イベントとは何かを見てみましょう。

Editorを開いたら、①Animateタブを開き、②State Machineを選択し、③実行ボタンでステートマシンの動作を確認できます。

Rive Editor Animateタブ

動作とステートマシンの変化を見ると、クリックした際にAny Stateから操作に応じたステートに変化しているようです。また、クリック時に画面上部の雷マークの「rating~」が反応しています。これがイベントが発火している合図になります。

イベントの中身を見てみましょう。画面左の「Hierarchy」から「rating4」を選択してみると右側のインスペクターにイベントの詳細が表示され、Propertiesの存在が確認できます。

イベントのProperties

「rating」という数値と「message」という文字列のプロパティがあり、これは先ほどUnityで見たログと一致します。

このように、Riveではイベントをオブジェクトのように追加でき、各イベント毎にプロパティを自由に定義できます。そしてそのプロパティをUnityは受け取ることが可能です。

2.3.5 クリック等を受け取るListenersについて

まだ1つ分かっていないことがあります。クリックしたというユーザー操作とイベント発火を結びつける部分です。Listenersと呼ばれるこの仕組みを次に見て行きましょう。

まずは画面下部のステートマシンの横で折り畳まれているListenersとInputsを開きます。

ListenersにStar_1~5, Inputsにratingがあるのが分かります。

Inputsは後述するDataBindingを利用する場合は不要であるため、ここでは解説しません。「変数を定義できる」くらいの認識でOKです。

ListenersのうちStar_4をクリックしてみてみましょう。

Star_4 Listener設定

見るところが多いので画像にまとめました。Listenersの1つであるStar_4は以下の動作をします。

  1. Artboard上の『Star_4』というオブジェクト(星型の絵)が押された瞬間(Pointer Down)に

  2. Inputsのratingを「4」にセットする

このように、Listenerは対象物と入力操作、操作時の処理を定義することが出来ます。

このサンプルでは、Listenersを5個定義し、それぞれの星を押した時の動作を定義しています。

2.3.6 Inputsに応じたStateMachineの動作

Listenersによって「rating」という変数が変化することがわかりました。あとは、その変数が変化した時に何が起きるのかを最後に見て行きます。

RiveのステートマシンはUnityのステートマシンと似ています。1つのステートから別のステートに遷移する条件をトリガーと言い、ここでは「ratingの数値が何と一致するか」がトリガーとなっています。

スタートはrating=0で始まり、「idle_empty」に遷移しますが、星をクリックするとListenerがInputs(rating)を押した対象物に応じて変化させ、ratingの変化から別のステートに遷移し、そのステートのアニメーションが再生されます。

ここで、動画0:14あたりにステートに結びついたイベントを確認することが出来ます。

ステートに結びついたイベント

定義したイベント(rating1~5)は遷移時、ステート開始時、終了時など任意のタイミングで発火させることが出来ます。
ここでは、星のアニメーション開始時=rating変更時にratingに合ったイベントを発火していることがわかります。

長くなりましたが、これでRiveがどのようにイベントを発火しているか、なぜクリック位置に応じてアニメーション、イベントの変化を行えるかを理解することが出来ました。 

3. RiveのDataBinding機能とUnityの連携

3.1 なぜDataBinding?

2.3で、デザイナーもエンジニアもこう思ったはずです。「Unityと連携させるにはメッセージや値の変更を全てイベントとして定義して発火タイミングも全て指定しないといけないのか?」と。

これを解決する仕組みとして、RiveにはDataBinding(データバインディング)があり各ArtboardがViewModelを持てる仕組みが存在します。

Image from Gyazo

ViewModelとは何か?MVVMを理解しているプログラマには説明は不要ですが、今回のレーティングを例に説明します。

  • View・・・ユーザーの目に触れる部分、ユーザーの入力
    →UnityのUIやユーザー操作、Riveのステートマシンやアニメーション、音の変化

  • ViewModel・・・Viewを制御する部分、Modelに応じて必要な情報を整理する部分
    →ViewとModelの橋渡し。rating(Model変化)に応じた表示内容の計算、変更など

  • Model・・・ビジネス/ドメインロジックの定義
    →ルールの定義。「レーティングにおいては評価は5段階である」など。

『ViewModelがなぜ必要なのか』をデザイナに理解してもらうのは大変ですが、概念の説明よりも実例で伝えると良いです。

分かりやすくViewModelがないと困るのは、「ユーザーが値を変更できる箇所が複数ある」「1つの操作で複数箇所が変更される」場合などです。

例えば、言語切り替えを例に取りましょう。言語がいつでも右上の国旗アイコンで切り替えられ、設定からも切り替えられます。また、言語を切り替えたら画面の文字に全て反映されます。

言語切り替え例1

言語切り替え例2

これをRive x Unityで実現させるにはどうすれば良いでしょうか?また、UIがRiveとUnity混在する場合どのように両方に変更を適用させましょうか?これを解決するのがViewModelであり、DataBindingであるというくらいの認識でOKです。

3.2 レーティング(EventScene)サンプルでDataBindingを使う

3.2.1 Rive Editor側の変更

2.3でinputs, eventを使っていたものをDataBindingを利用したUnity連携に変更します。

こちらのサンプルもマーケットプレイスに公開しています。早速中身を見てみましょう。

DataBindingのListeners

画像のように、Inputs,Eventが消えています。ListenersのPointer Down時の処理に変化が見られます。このrating, messageは何を操作しているのでしょうか?その答えがViewModelのプロパティになります。

次に、ViewModelを見て行きましょう。画面左のHierarchyタブをDataタブに切り替えてください。

ViewModelのプロパティ

「Main」というViewModelがあり、rating, messageの2つのプロパティがあります。
このプロパティをListenerから操作しています。

3.2.2 Unity側の変更

DataBindingを使った.rivファイルをインポートし、Rive Widgetを更新します。

Rive Widgetの更新

アセットが更新されているか、各種設定が一致しているを確認してください。

次に、Canvasのスクリプトを変更します。今回利用するスクリプトはgistにスクリプトを公開していますので、全文はこちらをご参照ください。

    private void OnWidgetStatusChanged()
    {
        // WidgetがLoadされたら初期化
        if (riveWidget.Status == WidgetStatus.Loaded)
        {
            // ViewModelインスタンスを取得(デフォルト)
            ViewModelInstance viewModelInstance = riveWidget.StateMachine.ViewModelInstance;

            _numberProperty = viewModelInstance.GetNumberProperty(RATING_PROPERTY);
            _numberProperty.OnValueChanged += OnNumberPropertyChanged;

            _stringProperty = viewModelInstance.GetStringProperty(MESSAGE_PROPERTY);
            _stringProperty.OnValueChanged += OnStringPropertyChanged;
            
            // 初期値を設定
            _numberProperty.Value = 0;
            _stringProperty.Value = "Please rate!";
        }
    }

このように、ViewModelのプロパティ変化をスクリプトで監視することが出来ます。
また、初期値をUnity側で設定することができます。

あとは変化時の動作を記載すれば完成です。

    private void OnNumberPropertyChanged(float newValue)
    {
        Debug.Log($"Rated: {newValue}");
    }

    private void OnStringPropertyChanged(string newValue)
    {
        Debug.Log($"Message: {newValue}");
    }

Unityで動作を見てみましょう。

無事、Unity上でDataBindingを使ったModel, Viewとの橋渡しができました。

RiveはInputsの利用は現在非推奨となり、DataBindingの利用を推奨しています。ゲームやアプリでRiveを利用する上でも、DataBindingは必ず活用しましょう。

4. Riveに音を組み込む

4.1 Rive側の変更

最後に、Riveの強みである音の連携を入れてみましょう。評価ボタンを押したら気持ちよく音が鳴って欲しいものです。「ユーザー操作に連動する音を入れる」が簡単にでき、Rive Editorでデザイナーが確認することが出来ます。

こちらもマーケットプレイスに公開しています。

押すと「チーン」となるRiveファイルを作ります。Eventの種類の一つであるAudioを追加することで音を鳴らせるようになります。

Audio Eventの追加

音声ファイルはAssetsにアップロードすることも出来ますし、Riveが用意している音を使うことも出来ます。

AudioのEventを作成できたら、各ステートの開始時にイベントが再生されるように設定します。

ステート開始時のAudio設定

これでRive Editorを実行して音声が鳴れば成功です。

4.2 Unity側の変更

データバインディングのUnityシーンに、スクリプトを新たに追加します。
このスクリプトも公開しています。

    private void OnWidgetStatusChanged()
    {
        // WidgetがLoadされたら初期化
        if (riveWidget.Status == WidgetStatus.Loaded)
        {
            _audioEngine = AudioEngine.Make(_channelCount, AudioSettings.outputSampleRate);
            riveWidget.Artboard.SetAudioEngine(_audioEngine);
        }
    }

    void OnAudioFilterRead(float[] data, int channels)
    {
        if (_audioEngine == null) return;
        _audioEngine.Sum(data, channels);
    }

AudioSourceに対し、OnAudioFilterReadで音声を再生します。AudioEngineを作成・セットする事前準備が必要です。

最終的に、このような状態になります。

Unity側の音声設定

Unityを実行して音声が再生されれば成功です。

5. まとめ

Riveは単にLottieやSpriteAnimationを置き換えるものではなく、2Dアニメーションのワークフローを根底から変えるものです。

今回はRive及びRiveとUnityの連携の基本をまとめましたが、それだけでも相当なボリュームになってしまいました。
このように、学習コストの高さという欠点はありますが、それを上回るだけの利便性と学習教材の多さがあるので是非チャレンジしてみてください。

実践として、近日中にMiRZAとRiveを組み合わせたデモを公開予定です。