VRChat 非公式日本語ドキュメント

Udon Example Scene

このシーンには、ワールドでUdonをどのように使用できるかの例が含まれています。ビルド&テストを行うか、このワールドを公開してVRChatで試すことができます。

プレハブ

このシーン内のプレハブは、ボタン、アバターペデスタル、ステーション、ミラーなど、VRChatコンポーネントとの一般的なインタラクションを示しています。

以下のすべてのプレハブはVRChat Worlds SDKに含まれています。これらは自身のどのワールドにも追加できます。例えば、VRCWorldは、ほとんどのVRChatシーンにデフォルトで含まれています。

UdonExampleScene

VRCWorld

このプレハブを使用すると、UnityシーンをVRChatに簡単にアップロードできます。これには4つのコンポーネントが含まれています:

  • ワールドの基本的なプロパティを定義するVRC Scene Descriptorスクリプト。これはすべてのVRChatワールドで必須となります。
  • ワールドIDが含まれているVRC Pipeline Managerスクリプト。これはVRC Scene Descriptorと共に自動的に追加されます。
  • ワールド内のプレイヤーの移動速度を変更できる VRCWorldSettings Udon Graph プログラムです。
  • ワールド内のプレイヤーのアバター倍率を制限できる Avatar Scaling Settings Udon Graph プログラムです。

VRCWorld プレハブを自分の Unity シーンで使用する場合は、\Packages\com.vrchat.worlds\Samples\VRCPrefabs\VRCWorld.prefab を参照してください。

AvatarPedestal

これはプレハブとして利用可能で、ペデスタルをインタラクトした際にユーザーをアバターに着替えさせるプログラムが設定されています。これがプレハブのデフォルトの動作です。

プレハブのインタラクト距離を変更するには、プレハブを「Unpack」し、Udon Behaviour コンポーネントの「Proximity」設定を変更してください。

VRCChair3

これはプレハブとして利用可能で、StationGraph というプログラムが設定されています。プレイヤーがインタラクトするとステーションに着席し、乗降した際にそのプレイヤーの displayName がログ出力されます。

MirrorSystem

このオブジェクトにはToggleGameObjectプログラムがアタッチされており、Interactイベントを使用してターゲットオブジェクトの有効/無効を切り替えます。この例では、このオブジェクトの子であるVRCMirrorオブジェクトを制御します。

Cubes

これらのオブジェクトは、Cubeを使ってできる簡単な例を示しています。主にChangeMaterialOnEventプログラムを再利用し、他のオブジェクトからカスタムイベントをトリガーする方法を紹介します。

Cubeの例

InteractCube

このオブジェクトにはSendEventOnInteractプログラムが設定されており、プレイヤーがオブジェクトを指差して「使用」ボタンを押したときに発生するInteractイベントを監視します。この例では、「changeMaterial」というカスタムイベントを、子オブジェクトにアタッチされたChangeMaterialOnEventプログラムへ送信します。このイベントを受け取るたびに、配列からマテリアルを切り替えます。これらのプログラムはどちらも再利用可能で、UdonBehaviourコンポーネントのインスペクターからSendEventOnInteractプログラムが送信するeventNameを変更できます。

TimerCube

このオブジェクトには SendEventOnTimer プログラムが設定されています。これは指定された duration(期間)の間タイマーを実行し、その後指定したイベントを送信するものです。この例では、「changeMaterial」というカスタムイベントを、子オブジェクトにアタッチされた ChangeMaterialOnEvent プログラムへ送信します。このイベントを受け取るたびに、配列からマテリアルを切り替えます。これらのプログラムはどちらも再利用可能です。UdonBehaviour コンポーネントのインスペクター上で SendEventOnTimer プログラムから送信される eventName を変更したり、duration を秒単位で変更してトリガーの間隔を調整したりできます。

UseCube

このオブジェクトの Model 子オブジェクトには SendEventOnUse プログラムが設定されており、オブジェクトを拾って「Use」した際にイベントを送信できます。この例では、「changeMaterial」というカスタムイベントを MaterialChanger オブジェクトにある ChangeMaterialOnEvent プログラムへ送信します。このイベントを受信すると、配列からマテリアルを切り替えます。これらのプログラムはどちらも再利用可能です。SendEventOnUse プログラムから送信される eventName は、UdonBehaviour コンポーネントのインスペクター上で変更できます。また、Model オブジェクトには VRCObjectSync コンポーネントがあり、動かした際にその移動を他のユーザーと同期します。

Udon 変数同期

これらのオブジェクトは、オブジェクトのオーナーからインスタンス内の他の全員へ変数の値を同期する、さまざまな方法を示しています。 Udon 変数同期の例

「Canvas」アイテムには、同期された変数を持つ多くの UI アイテムが含まれています:

ButtonSyncOwner

これは、Manual Sync(手動同期)方式を使用する、ここで説明する最初のプログラムです。下の画像では、OnClick() ハンドラーが UdonBehaviour.SendCustomEvent を「OnClick」という値で呼び出していることが確認できます。これは直下の UdonBehaviour をターゲットにしており、そこで「OnClick」カスタムイベントが実行されます。UI要素からUdonBehaviour上のイベントを実行するには、このように行います。

Unity UIコントロールからカスタムイベントをトリガーする

グラフプログラムでは、OnClickイベントがクリックしたプレイヤーがそのオブジェクトのオーナーであるかを確認します。オーナーであれば、「clickCount」変数を1増やし、RequestSerialization を呼び出します。これにより、この手動同期されるUdonBehaviourのデータを更新するようUdonに通知されます。

OnClick ▸ If Owner ▸ Set clickCount to clickCount + 1 ▸ Serialize.

「Set clickCount」ノードの「sendChange」トグルがオンになっていることに注目してください。これにより、新しいclickCountの値を受け取った全員に対してイベントがトリガーされます。

変数変更イベントは非常に強力です!同期変数が変更されるたびに、オーナーと他のユーザーの両方で同じロジックを実行するために使用できます。

clickCountが更新されると、この変更イベントがトリガーされます。すると、このプログラムの「オーナー」が誰であるかに関係なく、ボタンのテキストが新しい値に設定されます。

ButtonSyncAnyone

このオブジェクトは上記の ButtonSyncOwner と非常によく似たプログラムを使用していますが、ボタンをクリックしたユーザーがオブジェクトのオーナーでない場合のためのロジックが追加されています。その場合、ユーザーはカスタムイベント「OnClick」をオブジェクトのオーナーに送信します。以上です!オーナーはこのイベントを受信し、まるで自分自身でボタンをクリックしたかのように処理を行います。

非オーナーはオーナーにイベントを送信することで、数値を簡単に更新できます。

ButtonSyncBecomeOwner

このオブジェクトは、すでにおなじみのButtonSyncプログラムをベースにしており、オブジェクトのオーナー権限を簡単に変更する方法を示しています。非オーナーがボタンをクリックすると、そのユーザーにオーナー権限が割り当てられ、変数が更新されます。これは、複数の変数を変更したい場合や、単に数値をインクリメントするよりも複雑なロジックを実行したい場合に便利です。 ButtonSyncBecomeOwner

オブジェクトのオーナー権限を移行する際、その移行を許可するかどうかを判断するためのロジックが実行されます。詳細については、Networking を参照してください。カスタムロジックを追加しない場合、すべてのオーナー権限リクエストが承認されます。以下のノードは、someSpecialLogic というブール変数をチェックして権限移行を承認するかどうかを判断するシンプルな設定例です。requesternewOwner、あるいはその両方に基づいて独自のロジックを構築してください。

誰かが新しいオーナーになることを希望していますか?別の場所で更新した<code>someSpecialLogic</code>を確認してください。

SliderSync

SliderSync

このオブジェクトには SliderSync というプログラムが含まれており、ButtonSyncBecomeOwner と同様に動作します。誰かがスライダーを動かすと、その人がオーナーになり、新しい値を他の全員に送信します。1つ違いがあるのは、UI から「OnValueChanged」イベントがトリガーされた際、この新しい値がスライダーの現在の値と異なるかどうかをチェックする点です。これは、Udon からスライダーの値を更新するとこのイベントもトリガーされ、無限ループが発生してしまうためです。そのため、残りの処理を実行する前に、sliderValue 変数がスライダーの値と異なっていることを確認するロジックを組み込んでいます。

また、Variable Change イベントを使用して、誰かがオーナーになって値を更新するたびに、スライダーの値でテキストフィールドを更新します。

Toggle

このオブジェクトには ToggleSync というプログラムが含まれており、上記のSliderと同様に動作します。誰かが現在の値と異なる値に変更すると、その人がオーナーとなり、新しい値を他の全員に送信します。 Toggle

Dropdown

このオブジェクトには DropdownSync というプログラムが含まれており、上記のToggleやSliderと同様に動作します。誰かが値を変更した際、それが現在の値と異なることを確認してからオーナーとなり、新しい値を他の全員に送信します。

InputField

InputField

このオブジェクトには、上記のDropdownと同様に動作するInputFieldSyncというプログラムが含まれています。誰かが値を変更すると、現在の値と異なる値に変更すると、オーナー権限を取得した上で、新しい値を他のユーザー全員に送信します。

PickupCube

PickupCube

このオブジェクトにはVRC PickupおよびVRC Object Syncコンポーネントが設定されており、拾い上げて移動させたり、他のユーザーと位置情報を自動的に同期したりできます。このUdonBehaviourは、上記の同期プログラムとは異なり、Transformを常に最新の状態に保つ必要があるため、同期モードを「Manual」ではなく「Continuous」に設定しています。このUdonBehaviourには SyncPickupColor というプログラムが設定されており、手に持っている間スムーズに色を変化させます。これは、Updateイベントの中で、ローカルプレイヤーがそのオブジェクトのオーナーであり、かつ VRCPickup.isHeld がtrueであるかを確認することで実行されます。Continuousに設定されているため、RequestSerializationを使用する必要はありません。値は可能な限り頻繁に更新されます。

これは毎フレーム実行され、trueになるとプログラムが面白い計算式を用いて、インスペクターで指定された2色間をゆっくりと変化させます。

PickupSphere

このオブジェクト自体には実際にはUdonは設定されていません!単にVRC PickupコンポーネントとVRC Object Syncコンポーネントを使用しており、ユーザーがそれを手に取って同期された状態で動かせるようになっています。

PickupSphere

PlayerDetection

プレイヤーが特定のエリアに進入した時や、物理演算オブジェクトと衝突した時に処理を行うことは非常に有用です。これらのサンプルプログラムでは、その実現方法をいくつか紹介します。

PlayerTrigger

PlayerTrigger

これは、プレイヤーがエリアへの出入りを検知する際にもっとも一般的に使われる方法です。「TriggerArea」オブジェクトには半透明の青いマテリアルが適用されており、IsTrigger にチェックが入ったBox Colliderと、PlayerTrigger プログラムソースを持つUdonBehaviourが設定されています。

このプログラムでは、プレイヤーがコライダーに進入または退出するたびに、OnPlayerTriggerEnter イベントと OnPlayerTriggerExit イベントが発生します。その後、プログラムはそのプレイヤーの displayName を取得し、ターゲットとなるキャンバス上のテキストを更新します。 PlayerTrigger Program

PlayerCollision

このセットアップでは、物理オブジェクトがプレイヤーのコライダーに接触した際に発生する OnPlayerCollisionEnter/Exit イベントをトリガーする方法と、その応答方法を解説します。 PlayerCollision

TriggerArea オブジェクトには FireOnTrigger Udonプログラムが設定されており、上記の PlayerTrigger プログラムと同様に、プレイヤーがトリガーエリアに侵入したことを検知します。この例では、このイベントを使用して「Fire」というカスタムイベントを Projectile オブジェクトに送信します。これにより、Projectile キューブ自身に力が加わり、プレイヤーの方向へ移動します。プレイヤーと衝突すると、そのプレイヤーの displayName をターゲットの Text フィールドに書き込みます。

ここでの PlayerCollision イベントは、そのイベントを発生させたプレイヤーに対してローカルでのみ発生することに注意してください。これらのイベントを他のプレイヤーに通知したい場合は、Synced Variables(同期変数)や Custom Network Events(カスタムネットワークイベント)を使用して、その機能を自分で追加する必要があります。

PlayerParticleCollision

PlayerParticleCollision Scene

このデモは上記の PlayerCollision と同様の構成で、Trigger Area を使用して他のイベントを開始します。この例では、プレイヤーが Trigger Area に入ると SetActiveFromPlayerTrigger プログラムが CollisionParticles オブジェクトを有効にします。このオブジェクトには ParticleSystem があり、World Collision と Send Collision Messages を有効にした状態でプレイヤーに向けて発射します。このオブジェクトにアタッチされた Udon プログラム PlayerCollisionParticles は、グラフ内で OnPlayerParticleCollision イベントを発生させ、影響を受けたプレイヤーの displayName をターゲットのテキストフィールドに書き込みます。

PlayerParticleCollision Program

Udon Sync Player

Udon Sync Player

このセットアップは、Unity / AVPro ビデオプレイヤーを使用して動画の読み込みと同期を行う一例を示しています。プログラムが大規模であるため、専用のページに分けて解説します。

CubeArraySync

CubeArraySync

このシンプルなプログラムは、誰かがクリックするとランダムにオン/オフが切り替わるキューブのグリッドを作成します。使用するデータ量は非常に少なく、配列を同期する強力さを実証しています。CubeArraySync プログラムには、25個の値を保持する Boolean Array 型の data という変数が含まれています。これは、全ユーザー間で同期される25個の単純な「はい/いいえ(オン/オフ)」の値を意味します。また、25個のキューブを格納した cubes という GameObject 配列も持っています。

すべてのキューブを含むオブジェクトが誰かにクリックされると、「Randomize」というカスタムネットワークイベントが CubeArraySync オブジェクトのオーナーに送信されます。オーナーは For ループを使用して、0から1の間の数値を生成し、その値が0.5より大きいかどうかを確認することで、各値をランダムにオンまたはオフに設定します。配列変数を更新したら、RequestSerialization を呼び出し、続いてカスタムイベントの UpdateCubes を呼び出します。

各ユーザーは、ブール配列からのランダムな値に基づいて、各キューブのオン/オフを切り替えます。

UpdateCubes イベントでは、別の For ループを使用して配列内の各 yes/no 変数を順に処理し、対応する Cube のオン/オフを切り替えます。このイベントは、配列を更新した後にオーナーによってトリガーされるか、VRChat が他のすべてのユーザーに対して配列変数を更新した後に OnDeserialization によってトリガーされます。ここでは OnVariableChange の代わりに OnDeserialization を使用しています。これは、現在配列変数が変数変更イベントを発火させないためで、OnDeserialization で新しいデータを受け取るまで待機し、その時点でシーンを更新するようにしています。

ObjectPool

一度落下して跳ね回り始めると、これらのキューブが再びこのようにきれいに並ぶことはありません。

Object Pool は、オブジェクトのコレクションを管理するのに役立つコンポーネントです。オブジェクトの Active 状態を自動的に同期します。このサンプルプログラムでは、空から箱を1つずつ落下させて積み重ねたグリッド状に配置し、箱をクリックするとそれが取り除かれ、再び空からスポーンされるようになっています。

これを行うために、ObjectPool プログラムは単純なタイマーを実行し、一定の間隔でオブジェクトを Spawn しようとします。プール内の各 Pooled Box には単純な Pooled Box プログラムが設定されており、Start時に初期位置を保存し、有効化(プールからスポーンされた時)されるたびにその位置に復元し、クリックするとオブジェクトをプールに戻すようになっています。

Simple Pen System

基本的なペンであってもかなりの作業が必要になるため、この例については専用のページで解説します。

最終更新: