見出し画像

【VRChat】【Unity】Contact処理のAnimatorと同期

1. 適用範囲

・2023.01時点
・Unity 2019.4.31f1
・VRChat SDK - Avatars 3.1.10(VCC対応版)
・アバターギミックでContactを使用する人向けの説明になります

2. 要点

 Contactで判定処理した「結果」だけを同期処理させる

3. 説明

 3.1 Contactについて(要点のみ)

 Contactは
・①で設定した人(Self…自分 Others…他人)の
・②のタグが付けられたSenderがReceiverの設定範囲内に入ると
・③で設定したパラメータがリアルタイムに変わる
という機構です。「リアルタイムに変わる」のがポイント。

 3.2 基本説明

  3.2.1 概要

 今回は、この「セレアーテちゃん」を使って説明します。

セレアーテちゃんはいいぞ(なんと無料) 竜娘。

 筆者が使っているセレアーテちゃんはアバター改変で飛行能力を搭載しており、飛行モードに入ると翼の大きさが3倍になります。

通常時
飛行モード時
飛んでる時翼が大きい方が映えるよね

 通常モード⇔飛行モードの切り替えはContactを使用しており、Expression Menuを開かずともモード切替が可能になっています。メニューを開いて選択する、というメタ的な動作がなくなるので他の人から見た時に見栄えが良いですね。
 この「翼の大きさをContactで切り替える」というAnimatorの組み方に関する記述となります。

  3.2.2 Animatorでやりがちな組み方

 ついやってしまいがちな組み方がこれです。 

 通常時は翼1倍ステートに居て、Contact Receiverの範囲内に手を入れた状態でGestureLeft=2(左手を開く)と翼3倍ステートへ移動。逆はContact Receiverの範囲内に手を入れた状態でGestureLeft=1(左手を握る)と翼1倍へ戻る。一見これで良さそうに見えます。確かに自分1人だけならこれで良いんですが、他人へ同期させようとした時に問題が発生します。

 飛行モード中に、他の人がJoinしてきた場合を考えてみます。
 後から人がJoinした場合、Joinした人の世界に居る自分はEntryのステートから始まります。平行世界の自分についての考え方は別記事を参照。

翼3倍ステートに遷移しないといけないのだが…?

 後からJoinした人の世界に居る自分はEntryステートから始まるので、本体の世界と同期させる為には翼3倍ステートに合流しないといけません。が、Contact判定が既にfalseになっていますので、翼1倍→翼3倍の遷移条件を満たしておらず遷移できません。なので、本体の世界(翼3倍)と後からJoinした人の世界(翼1倍)で滞在ステートが違う同期ずれが発生します。

本体の世界(飛行モード)
後からJoinした人の世界にいる自分(通常モード)。同期ずれ

 つまりこのAnimatorの組み方では飛行モード中にJoinしてきた人に対する同期がされないので、組み方を変える必要があります。

  3.2.3 解決法

 Contact判定で使用しているパラメータをそのままモードチェンジ用の遷移として使用した場合、後からJoinした人がいる場合にステート遷移がそこで止まってしまう為、モードチェンジ用のパラメータを別途用意して、そのパラメータをExpression Parametersに乗せて同期させます。

「Contact判定のレイヤー」「翼のアニメーション再生レイヤー」を分ける

 Contact判定処理は同期されないので、同期処理させたいレイヤー(アニメーション再生レイヤー)と分けます。ステートの遷移条件自体は先ほどと同じですが、ここの設定アニメは空アニメ(何もキーが登録されていないアニメ)にします。▲Noneは不可です(Weightが0以外のレイヤーにWrite Defaults オフ+▲Noneの存在があると様々なバグを引き起こします)。
 
ステートにアニメを登録する代わりに、Add BehaviourでVRC Avatar Parameter Driverを追加して、同期処理用のパラメータを登録します。

変数処理だけをするステート

 上の例では「飛行モード_ON」というBool変数を定義して、【Contact判定処理の結果「飛行モード_ON」というBool変数のfalse⇔trueを切り替える】という処理を行っています。この「飛行モード_ON」というBool変数をExpression Parametersに登録します。

Contact判定用の変数は登録しなくてOK(登録しても意味が無い)

 「ここに定義されているパラメータのみがネットワーク上の人と同期するよ!」て注意書きがちゃんとあります(赤枠の部分)。
 Contactで判定した結果変わる変数「飛行モード_ON」のtrue⇔falseを切り替え、その切り替わった結果のみを同期させます。後からJoinした人が居た場合、「飛行モード_ON」のBool変数は最初はfalseが入りますが、Exパラメータによって「現在値はtrueですよ」という同期指示が飛んでくれるため、Contactに関係なく飛行モードONになってくれます。

翼のアニメーションレイヤー

 あとは翼のアニメーションレイヤーを作るだけです。遷移条件は「飛行モード_ON」のBoolオンオフのみ。

4. Local Onlyについて

 VRC Contact ReceiverやVRC Avatar Parameter DriverにはLocal Onlyという項目があります。VRChatの内部パラメータであるIsLocal(Bool値)も同様です。これは「対象の処理が本体であるかどうか(他人の世界に居る自分ではない)」という判定です。

4人接続時。平行世界が4つ存在して自分が4人いると考える。
IsLocal=trueな自分は1人だけ

 Local Onlyは、基本的にはONです(チェックを入れる)。以下説明

 例えばVRC Avatar Parameter Driverには、乱数を発生させる項目があります。(下の画像水色枠)

ちなみに赤枠は「Exパラメータだけが同期するぞ!覚えておいてね!」て書いてある

 Local Onlyにチェックを入れない場合、VRChatはローカル動作で動いている為、平行世界の自分4人それぞれが乱数を発生させます。

全員バラバラやんけ!

 なので、「乱数=nの時はn番目のアニメーションを再生する」という設定をLocal Only無しで組むと、4人全員異なるアニメーションが再生されます(同期してない)。
 これを4人全員同じアニメーションを再生する(同期する)為には、Local Onlyにチェックを入れます。すると乱数の発生処理が自分(本体)のみになります。

自分だけ乱数=6を生成

 この発生した乱数6を別の変数sと結び付け、この変数sをExpression ParameterでA,B,Cさんの世界にいる自分と共有させます。つまり乱数=nの時、変数s=n と定義して、変数s=n の時、n番目のアニメーションを再生する、と組みます。

「結果(変数s=6)」だけ平行世界の自分へ受け渡す

 Contactも原理は同じで、「乱数」の部分をContactに置き換えれば理解しやすいです。Contactの値も4人バラバラの値を持つ(同期してない)為、Contactの判定処理をLocal Onlyにして自分だけで処理するようにして、判定結果だけを別のパラメータで同期させるようにすれば、4人全員が同じ結果になりやすくなると思います。

・Local Onlyにチェックを入れないパターン
無くはないです。

ハイタッチパーティクルエフェクト

 Local Onlyだと自分本体で判定処理を行う→他の人へ結果を同期させる、の流れなので同期処理は安定しますがタイムラグが生じます。自分自身だけで完結する処理ならLocal Only一択なのですが、相手と反応させる処理(例えばハイタッチするとパーティクルエフェクトを発生させるContact判定)は、Local Onlyで行うとタイムラグの関係で見た目が若干不自然になるかもしれません。Local Onlyを外すと平行世界の自分それぞれが判定処理を行うようになるので、相手の環境の速度で発生判定が行われるので見た目が自然になる(かもしれません)。「相手と反応して一瞬だけエフェクトを発生させる」というような処理ならLocal Onlyを外すこともあります。

5. まとめ

 Contactを用いた処理はパラメータを動的に動かせる為Expression Menuを用いた方法よりも直感的にアバターを動かせる為、アバターとの一体感が飛躍的に向上します。同期処理さえ気を付ければ相手からの見栄えも良くなり、まるで手品でもしているかのような動きも可能になる為、導入をお勧めしたい処理です。

ちなみに実際にセレアーテちゃんに搭載した飛行システム(の一部)はこれ。
飛行の有効化/コライダーダッシュ/コライダージャンプのON/OFFを全てContactで切り替える。
このレイヤーは全て変数制御のみ(別レイヤーでアニメーション変更する)
バイバイ

この記事が気に入ったらサポートをしてみませんか?