Mirrativ Tech Blog

株式会社ミラティブの開発者(バックエンド,iOS,Android,Unity,機械学習,インフラ, etc.)によるブログです

あてっこ!ぷにまるずで利用したVisualScriptingとデザイナーフレンドリーな開発

皆さんこんにちは。Unityエンジニアのおはぎです。

ミラティブでは先日「あてっこ!ぷにまるず」(以下ぷにまるず)というライブゲームをリリースしました。 使っている技術については以下の記事に概要が書かれています。

tech.mirrativ.stream

本稿ではその中からVisualScriptingについて詳細を記述していきます。

VisualScripting

VisualScriptingはUnity公式が提供しているノードベースのノーコードツールです。 Unity2018からBoltとしてAssetStoreで有料販売されていましたが、 Unity社が買い取りUnity2021からはVisualScriptingとして統合されています。

unity.com

ぷにまるずで使われているVisualScripting

ぷにまるずのインゲームでは以下のものがVisualScriptingで実装されています。

  • UI演出
    • 開始/終了時演出、ストックが減ったとき、コンボ表示など
  • キャラクターアニメーション
    • 移動、ショットなど
  • エフェクト
    • ヒット、撃破など
  • カメラ演出
    • ゲーム開始時のパン、撃破時のズームなど
  • ステージ演出
    • ステージのコンポーネント動作など
  • チュートリアルの制御
    • 移動場所やショット方向の判定、Tipsの表示、UIの押下可否など

ぷにまるずでは、VisualScriptingを主に演出やアニメーションの制御に使用しており、 ゲームの基盤ロジックはC#で実装されています。 例外としてチュートリアルではロジックの制御も行われますが、VisualScriptingだけで実現しています。

これらの処理はVisualScriptingを使えるデザイナーによって実装されており、エンジニアが直接触る必要はありません。 エンジニアがやることは以下の2点です。

  • VisualScriptingに必要なデータを参照できる形式で渡す。
  • VisualScriptingのイベントを発火する。

構成

ぷにまるずではVisualScriptingを利用するため、下図のような構成になっています。

構成図

  • InGameLifetimeScope
    • VContainerを導入しており、LifetimeScopeに寿命管理を一任している。
  • AnimationEventBridge
    • VisualScripting Targetを参照する橋渡し役。
    • キャラクターなどを伴わない演出はこれ経由で発火する。
  • VisualScriptingTarget
    • これにアタッチされているStateMachineから様々な処理が行われる。
    • 自身はSceneVariablesに設定されており、他のStateMachineから参照できる。
    • 演出に必要なデータをVariablesに設定しておく。
  • キャラクターなど
    • キャラクターにもStateMachineが設定されている。
    • 主にキャラクターのアニメーションを制御している。

橋渡し

ぷにまるずのコード上には以下のように各種イベント名を定数で定義しています。

public static class VsEventMessages
{
    /// <summary>
    /// 初期化終了して、ゲーム開始の演出
    /// </summary>
    public const string OnGameEntry = "OnGameEntry";

    /// <summary>
    /// ゲーム開始
    /// </summary>
    public const string OnGameStart = "OnGameStart";

    /// <summary>
    /// ターン開始
    /// </summary>
    public const string OnTurnStart = "OnTurnStart";

    // 以下同様に記述
}

呼び出したいときは以下のように CustomEvent.Trigger 関数を呼び出します。

CustomEvent.Trigger(visualScriptingTarget, VsEventMessages.OnGameEntry);

VisualScriptingにもイベント名を参照して同名のCustomEventを作成しておくと、イベントが紐付けられます。

OnGameEntryの例

この先はデザイナーに自由にいじって貰えるようになっており、エンジニアが触らなくとも演出をつけることができます。

また、ぷにまるずで動いているものは前後の処理が複雑になっており、 動かしたイベントの終了待ちやタイムアウトの検知、 リアルタイム通信での複数回呼び出しの抑制のためTickを用いたキューイングをするなどの工夫をしています。

メリット

エンジニアはエントリーポイントとしてイベント名や必要な変数を渡しておけば演出に気をかけることなく開発ができるようになり、 内部処理・リアルタイム通信・マッチング・アウトゲーム・最適化など他の重い部分に工数を割くことができました。 これにより、ぷにまるずの短期間でのリリースが実現しました。

また変数によってデザイナー側で演出を変えることができるため、デザイナーが実現できることにも幅が出ました。 チュートリアル制御などは最たるもので、これをエンジニアが対応せずに済むのは革命的でした。 デザイナードリブンでかなりゴリゴリと開発が進むようになり、開発中の最新版をpullする度に見た目がブラッシュアップされていました。

デメリット

デザイナーが開発していくことになりレビューもしづらいため、エンジニアから見るとかなりブラックボックス化します。 バグの発生原因の切り出しなど、どこからがVisualScriptingの領域なのかを把握する必要があります。 イベント名でエントリーポイントをルール付けているのはその対策であり、原因究明は比較的しやすくなっていると思います。

モバイルWebGLという制限の多い環境だったこともあり、パフォーマンス面にも気を払う必要がありました。 VisualScriptingは内部的にはjsonであり、デシリアライズのタイミングでGC Allocが発生したり、jsonそのものの容量も無視できません。 そのため、VisualScriptingの最適化が発生し、エンジニアもVisualScriptingを少なからず把握する必要がありました。 具体的には、以下のような最適化を行いました。

  • 変数を減らす。
  • 不要な変数の参照は解放する。
  • StateMachine/ScriptGraphに処理を詰め込まず、分割する。
  • StateMachine/ScriptMachineのSourceにembedは使わず、アセットを参照して使う。
  • 同じ処理を行う場合はSubGraphをアセット参照で作り、関数のように使う。

また、メモリリークのバグがある(バージョン1.8.1で修正予定)ようで、長時間起動し続けていると落ちる場合があります。 こちらも特定に苦労しました。

優秀なデザイナーによってかなりの工数削減になりましたが、かなり属人化していると肌で感じました。 他のデザイナーへの引き継ぎや育成が大変なので、運用フェイズへの転換にもハードルが高そうです。

所感

大きなプロジェクトでは難しいですが、小さいプロジェクトでUnityを使えるデザイナーがいるなら使ってみる価値はかなりあると思いました。 演出のブラッシュアップのサイクルが早くなるので、見た目ひいてはユーザー体験が飛躍的に良くなると思います。

一方でメモリ使用量は無視できず、モバイルWebGLなどパフォーマンスに制限のある環境では難しいかと思います。 今回は使用しませんでしたが、次回は他のノーコードツールも試してみるかもしれません。

We are hiring!

ミラティブでは面白いゲームを共に作っていくエンジニアを募集しています!!

mirrativ.co.jp

speakerdeck.com

mirrativ.notion.site