VRC TriggerをUDONノードで再現する

うどん、こねてますか?

VRCがUnity2018に移行、SDK3+Udonに対応し、色んなギミックを搭載したワールドが作れるようになって1ヶ月。
ワールド制作の多くはU Sharp(U#)環境で書かれていると聞きますが、テキスト型プログラミングなんて触ったことのない方(僕もそうです)にはまだまだビジュアル型のノードは助かりまくっています。

ところで、SDK3ではこれまでのギミックの中核を担っていたVRC Triggerが使えず、Udonで代用する必要があります
というわけで、VRC Triggerの各トリガーに対応する(or代用できる)ノードをざっくりまとめました。


はじめに

この記事では、簡単なEventの解説のみに留めています。(Actionsの解説はしません)
VRC特有の関数を除けば、大体の関数の使い方はググればC#等の記事が出てきます。
もちろんC#はテキストですが、ノードと見比べるとどういう挙動をするのかはある程度想像がつくと思いますので、実際に作りながら確かめてみると良いです。

Custom/OnInteract

画像3

画像1

画像2

他のほとんどのイベントはEventsから辿れるのですが、カスタムトリガーはSpecialから辿る必要があります。(何で?)
イベントのStringには適当な定義を書いておき、他から発火させます。

例えば、他Objectに設置したInteractイベントから発火させたい場合、以下のように設定します。

画像4

InteractイベントからUdon Behavior>Send Custom Event(発火を同期させたい場合はSend Custom Network Event)に繋げ、publicにチェックを入れたUdon Behavior>VariableでCustomイベントをくっつけているObjectを設定、Get Variableで取得しSend Custom Eventのinstanceに設定してeventNameを先程Stringに入れた定義名にすればOKです。(早口)

ちなみに、Send Custom EventのeventNameはString値で他コンポーネント(UiText等)から参照できるので、上手く使えばパスワードとかに使えます。
逆に、Customイベント側のStringは能動的に変更することは出来ません。

能動的に変更したい場合は、以下のようにBranch(いわゆるif)を使う方法があります。

画像5

画像6

Relay

対応する関数は無いので、発火させたいうどんの最後に全体に伝播させるCustomを発火させる等での対応になるでしょうか。

OnNetworkReady

そのまま対応する関数はありません。
再現するにはOnPreSerialization/OnDeserialization/OnPlayerJoinedのいずれかを使うことになります。

画像7

順に簡単な説明を書いておくと、
OnPreSerialization:変数の同期前に発火
OnDeserialization:変数の同期後に発火
OnPlayerJoined:誰かがインスタンスに入った時に発火(後述)
といった感じです。

試していないので憶測になるのですが、OnPreSerialization/OnDeserializationは同じUdon BehaviorにSynced変数を入れていないと動かない気がします。

また、OnPlayerJoinedは「誰かが」Joinした時に発火するので、他プレイヤーが入ってくる度に発火します。
以下のように設定することで、自身の下でのみactionを起こすことができます。(たぶん)

画像8

やってることは「JoinしたプレイヤーのApiを取得し、ローカルプレイヤーのApiと比較、同じ(=Joinしたのが自分)なら発火」といった感じです。
ただ、OnPlayerJoinedとOnNetworkReadyは発火タイミングが恐らく異なる(前者はインスタンスに入った時、後者は入った後、ワールドの読み込みが終わった時)ので、タイミングを合わせたければOnPreSerialization/OnDeserializationを使う方が正しい気がします。

OnPlayerJoined/OnPlayerLeft

画像9

そのままEventにあります。下側の見切れてるやつでJoin/LeftしたプレイヤーのPlayerApiを取得することも出来ます。

OnEnterTrigger/OnExitTrigger/OnEnterCollider/OnExitCollider/OnParticleCollision

画像10

それぞれOnTriggerEnter/OnTriggerExit/OnCollisionEnter/OnCollisionExit/OnParticleCollisionがEventにあります。ついでに重なっている時に毎フレーム呼ばれるOnTriggerStayOnCollisionStayもあります。下側のやつで「当たった相手のコンポーネント」を取得することも出来ます。

注意点として、Triggerが取得するのはCollider、Collisionが取得するのはCollisionの型であるということです。
クッッッッソ名前が似ていますが異なるものなので、それぞれ別の型には当然繋がりません。
また、OnParticleCollisionはGameObjectそのものを取得します。

OnPickup/OnPickupUseDown/OnPickupUseUp/OnDrop/OnEnable/OnDisable/OnSpawn/OnDestroy/OnStationEntered/OnStationExited/OnVideoStart/OnVideoEnd/OnVideoPlay/OnVideoPause/OnOwnershipTransfer

そのまんまEventにあります。ので全部省略!

OnKeyDown/OnKeyUp

Eventとしてはありません。UpdateイベントとBranchを使う必要があります。

画像11

UnityEngine>Input>GetKeyDown(Up)で特定のキーの押す/離すを取得し、BranchのTrue側にactionを書く感じです。Key Codeはリストで選ぶ場合、アホみたいにあるので頑張って下さい。

OnAvatarHit

Event内のOnControllerColliderHitが対応している・・・ようですが、現状機能していない模様。
同じような再現をする場合、PlayerLocalとのみ衝突するLayerを作成→そのLayerに設定したコライダー付きオブジェクトにOnTrigger/OnCollider系を付けて反応させる等で可能です。

OnTimer

対応する関数はありません。
ざっくり再現するなら、FixedUpdateを使うか、deltaTimeを使うかが挙げられるかと思います。

FixedUpdateに関してはほぼそのままなのでググってもらうとして、deltaTimeを使った例が下記になります。

画像12

これをコライダー付きのGameObjectにアタッチすることで、「インタラクトすると1秒毎に音がなるギミック(メトロノーム)」になります。

仕組みについてはカウントアップタイマーの応用です。ノードは複雑ですが、やってることは割とシンプルなので読み解いてみて下さい。
Update内2つ目のBranchの条件Greater Than Or Equalの下側をランダムに設定すればOnTimerの下限と上限を設定できます。

とはいえ、正直、固定時間間隔で発火させるならAnimatorでいいです。

OnDataStorageChange

VRC_DataStorageが無いので無いです。そりゃそうだ。



以上となります。
この記事が、まだまだノードをがんばる人の一助になれば幸いです。


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