Genvid「Event」jsonスキーマ設定例

# はじめに: Genvid SDKについて
Genvidは、動画ストリーミングとブラウザを介したインタラクティブな体験を組み合わせた「大規模インタラクティブ・ライブ・イベント」（Massive Interactive Live Events）を実現するSDKです。
https://www.genvidtech.com/ja/mile%E3%81%A8%E3%81%AF%EF%BC%9F/

ゲーム技術をベースに、リアルタイムで進行する動画番組に対して、動画視聴者が能動的に参加できるシステムを提供します。
コンテンツ内のキャラクターが次に何をするかを投票で決めたり、ミニゲームをプレイしてポイントをため、特定のキャラクターを応援するなどの活動を経て、物語が変化していきます。
MILEは、Unityを使いFacebook上で配信されている「Rival Peak」と、Unreal Engine 4を使った「Project Raven」があります。

『RIVAL PEAK』が示す次世代の視聴者参加型デジタルエンタテインメント
https://news.yahoo.co.jp/byline/onokenji/20210326-00229353

Genvid SDKの導入については、Genvidディベロッパーサイトの日本語マニュアルからご確認ください。
https://www.genvidtech.com/for-developers/

# Genvid Eventのjsonスキーマについて

Genvidのシステムは、大量の動画視聴者から送られてくるデータを成型・集計し、ゲームが使いやすいデータの頻度に変換してくれます。
動画視聴者から送られてきたjsonデータの配列から新しい配列を生成する「Mapステップ」、配列からデータを集計するReduceステップがあります。
それらの挙動はjsonスキーマによって定義します。定義の読み方については以下の投稿をご覧ください。

Genvidにおける動画視聴者からの送信データ「Event」を集計処理するjsonスキーマの読み方
https://qiita.com/Takaaki_Ichijo/items/33e46d7849107f0bcfa7

本投稿では、具体的にインタラクティブ・ストリーミングでどのような設定になるかを考えていきます。

## 次のステージを視聴者投票で決める

もっとも簡単なGenvidの利用方法は、動画を視聴している視聴者が今見ているゲームに対して何らかの投票を行い、その結果をもってゲーム内に反映させるものです。
次に出現する敵の種類を選んだり、アイテムの出現を選んだりなど、さまざまな活用が考えられます。

動画視聴者側（ブラウザ）からはデータとして「投票の種類の名前:投票先の名前」のペア情報を送ります。
次に出現する敵の種類を選んだり、アイテムの出現を選んだりなど、さまざまな活用が考えられます。
たとえば「次に出現する敵の種類:ゴブリン」「次に出現する敵の種類:オーク」や、「次に投下されるアイテムの種類:回復薬」「次に投下されるアイテムの種類:毒薬」など、データの種類と中身を送る形です。

たとえば、なんらかの対戦ゲームで「次のステージ」を収集するケースを考えてみましょう。
投票の種類の名前をnextLevel, 視聴者が選ぶステージの名前が文字列(string)で送信されるものとします。

動画視聴者側（ブラウザ）からはEvent名「nextLevel」で、stringでステージの名前を指定するjsonデータを送信します。
Genvidシステム側では、まずそれを「キーが["nextLevel","{ステージ名}"]の配列で、値が１」のデータを生成します。(maps)
それを、valueの合計値(sum)で集計し(reductions)、250msecに1回ゲーム側に渡す処理を考えます。

```json
{
  "version": "1.7.0",
  "event": {
      "game": {
          "maps": [
              {
                  "id": "nextLevel",
                  "source": "userinput",
                  "where": {"key": ["nextLevel"], "name": "<name>", "type": "string"},
                  "key": ["nextLevel", "<name>"], "value": 1
              }
          ],
          "reductions": [
              {
                  "id": "nextLevel",
                  "where": {"key": ["nextLevel", "<name>"]},
                  "key": ["<name>"],
                  "value": ["$sum"],
                  "period": 250
              }
          ]
      }
  }
}

```

## 対戦ゲームで特定のプレイヤーにアイテムを付与する
もう少し選択肢が増えるやり方を考えてみましょう。先ほど、視聴者が選べるのは「次のステージはどれか」という1種類でしたが、
特定のキャラクターに特定のアイテムを付与する動画インタラクションを考える場合は「キャラクター名」「アイテム名」を指定する、という2種類を指定するデータになります。
このデータの名称をgiveItem、対象のプレイヤー名をname、アイテムの名前をitemとして定義します。
Genvidシステム側では、「キーが["giveItem", プレイヤー名, アイテム名]の配列で、値が1」のデータを生成します。(maps)
それを、valueの値の数(count)で集計し(reductions)、250msecに1回の頻度でゲーム側に渡す処理を考えます。

 ["\<name>", "\<item>"]のペアが何個あったか、という値の数で集計を行うところがポイントです。

```json
{
  "version": "1.7.0",
  "event": {
      "game": {
          "maps": [
              {
                  "id": "giveItem",
                  "source": "userinput",
                  "where": {"key": ["giveItem", "<name>"], "name": "<item>", "type": "string"},
                  "key": ["giveItem", "<name>", "<item>"], "value": 1
              }
          ],
          "reductions": [
              {
                  "id": "giveItem",
                  "where": {"key": ["giveItem", "<name>", "<item>"]},
                  "key": ["<name>", "<item>"],
                  "value": ["$count"],
                  "period": 250
              }
          ]
      }
  }
}

```


## 対戦ゲームでステージの特定位置に罠を召喚

こんどは、対戦ゲームで特定の位置に罠を召喚する仕組みを考えてみましょう。
ただし、動画視聴者が罠落とす位置を自由に指定する仕組みはあまりお勧めしません。というのも、
贈られてくるデータのキーとなる値の種類が多すぎると「データをまとめる」reduce段階の恩恵が薄くなり、ゲームインスタンスに大量のデータが送られてきてハングアップしてしまう可能性があるからです。

そこで、ステージに罠を投げ入れるような設計をしたい場合は、ステージをグリッドに分けてどのエリアに罠を落とすかを決める方法がシンプルです。
見下ろし方のバトルゲームだったら、マップを3x4で区切って12カ所とし、0から11までの数値で「どこに落とすか」を指定するとデータの種類を限定できます。

このデータの名称をdropTrap、対象のグリッドIDをgridId、罠の名前をtrapとして定義します。
Genvidシステム側では、「キーが["dripTrap", グリッドID, 罠名]の配列で、値が1」のデータを生成します。(maps)
それを、valueの値の数(count)で集計し(reductions)、250msecに1回の頻度でゲーム側に渡す処理を考えます。

```json
{
  "version": "1.7.0",
  "event": {
      "game": {
          "maps": [
              {
                  "id": "dropTrap",
                  "source": "userinput",
                  "where": {"key": ["dropTrap", "<gridId>"], "name": "<trap>", "type": "string"},
                  "key": ["dropTrap", "<gridId>", "<trap>"], "value": 1
              }
          ],
          "reductions": [
              {
                  "id": "dropTrap",
                  "where": {"key": ["dropTrap", "<gridId>", "<trap>"]},
                  "key": ["<gridId>", "<trap>"],
                  "value": ["$count"],
                  "period": 250
              }
          ]
      }
  }
}

```

ただし、いくらグリッドに分けても、千個の罠が一度に投げられたら大変です。
そこで、ただ同じ位置に罠を投入するのではなく、同じ1秒間に同じグリッドをクリックした視聴者の数を集計して、その数分の強力な罠1つを投入する、というデザインも考えられます。

# その他の集計項目の活用を調査中
今回はreductionsでcount, sumを活用しました。このほか、genvidでは最大値を取るmax、最小値を取るminが使用できます。
このルールを使って、Genvid Eventを活用した視聴者連動コンテンツのケースを調査中です。