【VRChat】Udon Graph 入門【SDK3】

## 更新情報
2025年05月31日: [ノードの入出力検索](#基本的な組み方)や[変数の追加・設定](#変数の追加設定)などに関する文言を調整。
最新の情報をもとに記事の内容を点検し、一部画像を差し替えました。(旧UIのままの画像もありますが、挙動等に差はないはずです。)
2021年12月22日: [配列](#配列)についての補足説明を追加。[VRCPlayerApi, Networking](#vrcplayerapiqs-vrcplayerapi-networkingqs-vrcnetworking-など)に次記事への誘導を追加。回転系の処理について言及を調整。
2021年10月30日: [ノード検索](#基本的な組み方)についての内容を追加・調整
2021年10月23日: 投稿

## 目次
<details><summary></summary><div>

- [対象者](#対象者)
- [この記事の概要](#この記事の概要)
- [Udonとは？](#udonとは)
- [基礎知識編](#基礎知識編)
  - [型](#型)
  - [変数](#変数)
  - [配列](#配列)
  - [イベント](#イベント)
  - [オブジェクト](#オブジェクト)
  - [その他用語](#その他用語)
- [UdonGraph編](#udongraph編)
  - [Udonの付け方](#udonの付け方)
  - [基本的な組み方](#基本的な組み方)
  - [変数の追加・設定](#変数の追加設定)
- [作例](#作例)
- [種類別 よく使うノード一覧](#種類別-よく使うノード一覧)
  - [イベント(QS: Events)](#イベントqs-events)
  - [分岐・ループ処理(QS: Special)](#分岐ループ処理qs-special)
  - [変数関連(QS: なし 検索不可)](#変数関連qs-なし-検索不可)
  - [計算(QS: System→任意の型名)](#計算qs-system任意の型名)
  - [比較関連(QS: System→任意の型名 Equal系は更にその中のOther内)](#比較関連qs-system任意の型名-equal系は更にその中のother内)
  - [条件分岐関連(QS: System→Boolean)](#条件分岐関連qs-systemboolean)
  - [配列関連(QS: System→任意の型名\[\])](#配列関連qs-system任意の型名)
  - [GameObject系(QS: System→GameObject GetComponentのみ更にその中のGetComponents内)](#gameobject系qs-systemgameobject-getcomponentのみ更にその中のgetcomponents内)
  - [Transform系(QS: System→Transform GetComponentのみ更にその中のGetComponents内)](#transform系qs-systemtransform-getcomponentのみ更にその中のgetcomponents内)
  - [VRCPlayerApi(QS: VRC→PlayerApi) Networking(QS: VRC→Networking) など](#vrcplayerapiqs-vrcplayerapi-networkingqs-vrcnetworking-など)
  - [その他](#その他)
- [おわりに](#おわりに)
</div></details>

## 対象者
- VRChatのワールドギミックを作ってみたい人
- Udonって何？という人
- UdonSharpで挫折した人

など...

## この記事の概要
- UdonGraphを使ったギミックの作り方説明
- UdonSharpは使わないので、追加で必要なものは無し
- プログラミングが分からなくてもOK

UdonGraphの情報が少ないので記事を書きました。
VRCユーザーがUdonをもっと手軽に扱えるようになりますように。

分かりにくいところや問題点があれば、[Misskey](https://misskey.niri.la/@Sayabeans)や[Twitter](https://twitter.com/Sayabeans_0011)などにお願いします！
ちなみに、UdonGraphを用いたサンプルを[Booth](https://sayamame-beans.booth.pm/)で無料配布していますので、良ければ参考にどうぞ。(随時更新)

## Udonとは？
- Udon
  - VRCSDK3で追加された、ワールドギミックのためのプログラミング言語
  - 作った処理をゲームオブジェクトに付けて動作させることが出来る
- UdonGraph
  - VRCSDK3を入れれば使える
  - `ノード`を線で繋ぐことによって処理を作る(任天堂の「はじめてゲームプログラミング」に少し似ている)
  - 非プログラマー向けではあるが、前提知識が無いと少しつらい
- UdonSharp
  - C#の記法でUdon処理を作ることが出来るもの
  - プログラマー向け(特にC#やUnityでゲーム制作の経験がある人など)
  - ~~使うには追加でアセットを入れる必要がある(標準ではない)~~
  - VRChat SDK 3.4.0から標準で同梱されている

:::note warn
動作確認環境
・Unity 2019.4.31f1, 2022.3.22f1
・VRCSDK3-WORLD-2021.09.30.16.18_Public, VRChat SDK - Worlds 3.8.1

この記事は2025年05月31日時点の情報です。
Udonはアップデートされていくため、情報が古くなりやすく、最新版とは仕様が違うことがあります。
:::

## 基礎知識編
- プログラミングの経験が無い方向けの用語説明
- 分かる方は読み飛ばし推奨
- Unityの知識が少し必要
  - アバターやワールドを触ったことがあれば多分大丈夫

### 型
データの種類、と言えるものです。
その中でもUdonGraphでよく見かけるものを列挙し、少し雑に説明します。

- int
整数
(例: -16, 0, 1, 32など)

- float(Singleと表記されることも)
実数(小数と整数)
(例: -1.2, 3.14, 5.0など)

- string
文字列
(例: VRChatなど)

- bool(booleanとも)
真偽値
(TrueかFalseの2種類で、それぞれ真、偽)

- GameObject
Unityのゲームオブジェクト
(例: CubeやEmptyなど、Unity上で設置出来るもの)

- Transform
Unityゲームオブジェクトの位置情報などが入った要素(Component)
(UnityのInspectorで見られる、座標や回転角度を入力出来るアレ)

- Vector3
位置情報(X, Y, Z)
角度の表現に使われることもある

- UdonBehaviour
Udonプログラム要素(Component)
(UnityのInspectorのAdd Componentにて、Udon Behaviourとして追加されるもの)

- VRCPlayerApi
VRChat内のプレイヤー情報
プレイヤー名やワールド上の位置などが取得出来る

- []
型名に[]が付いたものはその型の配列(後述)
(例: int[], float[], GameObject[]など)

### 変数
変数とはデータを格納するための箱のようなもの、とよく表現されます。
この箱にデータを格納しておくことで、後から取り出して使うことが出来ます。
例えば、int型の変数xに2を代入する、といった感じです。

### 配列
配列とは、変数を複数纏めた棚のようなもの。
先頭を0番として、番号で指定して中身を取り出したりすることが出来ます。
この番号を配列の添え字、または要素番号と呼び、それぞれの中身のことを要素と呼んだりします。
例えば、int[]である[8, 1, 9, 2]の2番目の要素は9。要素数(要素の数)は4つです。

補足: 引っ掛かりやすいポイントですが、配列の要素番号は**0から始まる**ため、0番目の要素が8、1番目の要素が1、2番目の要素が9、3番目の要素が2となります。

### イベント
特定の条件が満たされた時などに実行される処理。基本的に、これを起点にして処理を作ることになると思います。
(ちなみに、「～された時に実行される」という言葉は、「～された時に呼ばれる」と表現されることがあります。)

### オブジェクト
とても大雑把に言えば、`モノ`です。どんな型・データが入っているかを考えず、一纏めにして扱うときに出てきます。
変数も値も、あらゆるものがオブジェクトと言えます。

### その他用語
- ループ
繰り返し処理のこと。

- get
主にデータを取得したいときに出てくる。

- set
主にデータを設定したいときに出てくる。

---

## UdonGraph編
Udonをゲームオブジェクトに付ける方法や、その編集の仕方などを説明します。

### Udonの付け方
![要素追加.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/40d568fa-df58-77fb-6e49-092add185c54.png)
Inspectorから`Udon Behaviour`Componentを追加します。
![Udon追加.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/b02e5637-8502-ca8e-3437-204eb5386dff.png)
追加したら、ProgramSourceのプルダウンメニュー(右下の三角形のところ)を選択して、`Udon Graph Program Asset`を選択し、New Programを押します。
`Open Udon Graph`をクリックすることで編集画面を開けます。
![udon_window_SDK381.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/f405a335-a9de-4d28-aab0-a256d09b4bdc.png)

### 基本的な組み方
UdonGraphはノードを線で繋いで処理を作ります。
ノードには、処理を分岐させるための`Branch`ノードや、オブジェクトからデータを得るためのget系ノードなど様々な種類があるので、作りたい処理に応じて使いたいノードを選択します。

![一般_ノード検索.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/657be1a5-2ebc-fb21-34ff-5113265c8e9d.png)
ノードを検索するには、主に`Quick Search`を使います。
`Quick Search`は右クリックから`Create Node`を選択するか、スペースキーを押すことで開けます。型や種類で分類されていて、マウス等で選択して探すか、名前で分類を検索することが出来ます。
ノードを選択すると、画面上にノードが配置されます。
なお、名前は分かっているがどの分類にあるのか分からない、という場合はtabキーで`Full Search`を開いて検索することも出来ますが、処理に少し時間が掛かります。

![入出力_ノード検索.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/76c683fd-2dab-82f5-5902-e6d90c4685f2.png)
ノードを検索する方法はもう一つあり、線を何もないところにドラッグ&ドロップすることで入出力検索が出来ます。
これを使うことで、繋げたい入出力に対応したノードを検索することが出来ますが、**一部の型(Objectなど)については対応しているはずのノードが表示されない場合がある**ため、繋げたいノードが表示されなかった場合は、通常のノード検索でノードを出し、本当に繋がらないかを試してみてください。(ただし、変換するノードなどを間に挟まないと本当に繋がらない場合もあります。)

![線の種類.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/43b9d451-333f-cea3-8714-8c822a9bae72.png)
右向きの三角形で繋がった線が処理の流れ、丸で繋がった線がデータの流れになっています。

### 変数の追加・設定
ノードとは別に、変数が設定できます。設定した変数は[変数関連](#変数関連qs-なし-検索不可)のノードで操作します。

![変数追加.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/07bc41fe-c305-4d9a-818f-215d14ee2eb4.png)
![変数追加_型.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/2b2f212e-53b0-b58c-7393-e92e773f578b.png)
左上のVariablesメニューの+ボタンを押し、追加したい変数の型を選ぶと変数が追加されます。
![variable_config.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/2bc4a5ae-003a-c055-deb5-a752852e1425.png)
変数の左の三角形を押すと変数の設定画面が現れます。
![public変数.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/417debc4-1b34-85b7-4962-f546c8c4a053.png)
`public`はチェックを入れることでInspectorから値を入力出来るようになります。(上の画像は実際に変数に値を指定している例)
`synced`はチェックを入れることで他の人と値を同期できるようになります。(一部の型のみ)
`default value`で初期値を設定できます。

![array_edit.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/54ed98ba-b91d-0a57-da78-e53bfd7e5d5a.png)
配列の場合には、Default Valueのところに`Edit`ボタンがあり、これを押して初期値を編集します。
sizeは要素数で、これを変更したりして初期値を変更します。(要素の数だけ入力欄が出ます)
編集を終えたら`Save`を忘れないようにしましょう。

![variable_rename_delete.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/44803349-b5b1-4b70-91bd-48bfa958f7e4.png)
なお、変数の名前部分を右クリックすることで変数名の変更や変数の削除が可能です。
変数を削除した場合、その変数に[直接関連するノード](#変数関連qs-なし-検索不可)も同時に削除されます。

## 作例
![作例.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/22781cf2-e631-95ac-282a-d95453589388.png)
これは実際にUdonGraphを使ってスイッチを作ってみたものです。(私が配布している[【無料】スイッチ数種類【説明付きUdon配布】](https://sayamame-beans.booth.pm/items/3343488)の中の1つです)
個々のノードの説明は次節の一覧の中にあります。

## 種類別 よく使うノード一覧
Quick Search時に選択する箇所を(QS: 場所)として記します。検索キーワードを入力する場合はEventsやSystemなどを除いた名前で検索します。

### イベント(QS: Events)
![イベント.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/ff2d9e9f-dd31-3407-4e0a-999e263d023e.png)

- Start  
初回読み込み時に実行される。これを用いて初期化処理などを行うことが出来る。
- Update  
毎フレーム実行される。リアルタイムに処理を行う場合などに用いる。
- Interact  
オブジェクトを触った時に実行される。これに処理を繋げることで、`Use`関連の設定がUnityのInspectorに表示されるようになる。
- OnPlayerJoined  
プレイヤーがワールドにJoinした際に実行される。Joinしたプレイヤー情報(VRCPlayerApi型のデータ)が利用可能。
- OnPlayerLeft  
プレイヤーがワールドから離れた際に実行される。離脱したプレイヤー情報(VRCPlayerApi型のデータ)が利用可能。

### 分岐・ループ処理(QS: Special)
![分岐とループ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/3dfb829e-2d2e-544c-9429-25ce60e9a990.png)

- Branch  
与えられたboolの値に応じて処理を分岐する。いわゆるif文と同じ。
- While  
与えられるboolの値がTrueの間、Bodyに繋がっている処理を繰り返す。与えられるboolの値がFalseである時、又はFalseとなった時、Exitに続く。
- For  
startから始まり、indexがend未満の間、Bodyに繋がっている処理を繰り返す。処理を1週する度、indexにstep分の値が加えられる。処理終了後、Exitに続く。

### 変数関連(QS: なし 検索不可)
![変数関連.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/21db43f1-4a13-4c8a-f1a7-eabecb300d42.png)

- Get Variable  
画面上のVariablesから変数をドラッグ&ドロップすることで出るノード。変数の値を得る。
- Set Variable  
画面上のVariablesから変数を、Ctrlキーを押しながらドラッグ&ドロップすることで出るノード。変数の値を設定する。チェックボックスにチェックを入れると、On Var Changeイベントが呼び出される。
- On Var Change  
画面上のVariablesから変数を、Altキーを押しながらドラッグ&ドロップすることで出るノード。変数の値が変わった際に実行されるイベント。

対応する変数が削除された場合、これらのノードは同時に削除されてしまうため、少し注意が必要です。

### 計算(QS: System→任意の型名)
![計算.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/75fbf3a4-d38d-ac8e-44e3-19667fb82566.png)

- Addition  
2つの数を足した結果を得る。
- Subtraction  
上の数から下の数を引いた結果を得る。
- Multiplication  
2つの数を掛けた結果を得る。
- Division  
上の数を下の数で割った結果を得る。
**intの場合、割り切れなくても計算結果が整数になることに注意が必要。**
- Remainder  
上の数を下の数で割った際の余りを得る。

### 比較関連(QS: System→任意の型名 Equal系は更にその中のOther内)
![比較関連.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/d7162c46-687e-578a-53e5-03d71a1c31cf.png)

- GreaterThan  
上の数が下の数より大きい時、Trueを得る。そうでない時、Falseを得る。
- GreaterThanOrEqual  
上の数が下の数以上の時、Trueを得る。そうでない時、Falseを得る。
- LessThan  
上の数が下の数未満の時、Trueを得る。そうでない時、Falseを得る。
- LessThanOrEqual  
上の数が下の数以下の時、Trueを得る。そうでない時、Falseを得る。
- Equality または Equals  
値が同じ時、Trueを得る。そうでない時、Falseを得る。
- Inequality  
値が異なる時、Trueを得る。そうでない時、Falseを得る。

### 条件分岐関連(QS: System→Boolean)
![条件分岐関連.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/310758df-1c6c-a754-e35d-9e8aaf196aa9.png)

- ConditionalAnd  
boolの値で「かつ」を処理する。(2つの値が共にTrueならTrueを得る)
- ConditionalOr  
boolの値で「または」を処理する。(2つの値がどちらかTrueならTrueを得る)
- ConditionalXor  
boolの値で「どちらかが真なら」を処理する。(2つの値が異なる時、Trueを得る)
- UnaryNegation  
boolの値を反転させる。

### 配列関連(QS: System→任意の型名\[\])
![配列関連.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/21aafac7-6e60-41b3-6a0f-9c93a00e20f4.png)

- Get または GetValue  
index番目(要素番号の位置)の要素を得る。
- Set または SetValue  
index番目(要素番号の位置)の要素を設定する。
- get Length  
配列の要素数を得る。

### GameObject系(QS: System→GameObject GetComponentのみ更にその中のGetComponents内)
※Unity GameObjectで検索すると詳しい情報が得られると思います。
![GameObject関連.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/70a000a2-a457-07d1-f644-04b52a05df85.png)

- get activeSelf  
ゲームオブジェクトのアクテイブ状態を得る。
- get name  
ゲームオブジェクトの名前を得る。
- get transform  
ゲームオブジェクトのTransform要素を得る。
- SetActive  
ゲームオブジェクトのアクテイブ状態を設定する。
- GetComponent  
ゲームオブジェクトにある任意の要素(Component)を得る。ただし、同じ種類の要素が2つ以上ある場合、意図しない動作をする可能性がある。例えば、画像のようにUdonBehaviourが2つ付いていた場合、どちらが参照されるかは分からない。
![Component重複.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/1d4f6ccd-0654-e138-4973-f60aa398f1ef.png)

### Transform系(QS: System→Transform GetComponentのみ更にその中のGetComponents内)
※Unity Transformで検索すると詳しい情報が得られると思います。
![Transform系.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/d40084e7-b128-7ccb-3363-61782a9dd85c.png)

- Find  
子のゲームオブジェクトを名前で探し、得る。(`/`を用いることで孫のゲームオブジェクトなども得られる。)
- get gameObject  
そのTransformを持つGameObjectを得る。
- get position  
座標を得る。ワールドの絶対座標であることに注意。
- get localPosition  
座標を得る。親のゲームオブジェクトに対する相対座標であることに注意。(つまり、UnityのInspectorで見られる数値)
- set position  
座標を設定する。ワールドの絶対座標であることに注意。
- set localPosition  
座標を設定する。親のゲームオブジェクトに対する相対座標であることに注意。(つまり、UnityのInspectorで見られる数値)
- Translate  
現在位置から指定した座標分移動させる。
- GetComponent  
そのTransformを持つゲームオブジェクトにある任意の要素(Component)を名前で得る。ただし、同じ種類の要素が2つ以上ある場合、意図しない動作をする可能性がある。例えば、UdonBehaviourが2つ付いていた場合、どちらが参照されるかは分からない。

回転系の処理は少し複雑なため割愛します..."Unity Transform 回転"などで調べていただければ情報が得られるかと思います。
(いつか別記事に纏められたらなと思います。)

### VRCPlayerApi(QS: VRC→PlayerApi) Networking(QS: VRC→Networking) など
~~量が多いため別の記事に纏めます。~~
纏めました。
[【VRChat】VRCPlayerApi と Networking【SDK3】](https://qiita.com/Sayamame/items/10ea6dc48ebb6d3e8655)

### その他
![その他.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592409/b62e8bee-de00-fd14-dc7b-6d3d704493ad.png)

- UnaryMinus(QS: System→任意の数値系型名)  
数値の正負を反転させる。
- Tostring(QS: System→任意の型名→Other)  
値を文字列に変換する。つまり、Stringが得られる。
- To<任意の型名>(QS: System→Convert)  
任意の型に値を変換する。(例えば、intからfloatなど)
- Const This(QS: Special)  
このノードを置いたUdon Behaviour要素の付いているゲームオブジェクトが得られる。
(例えば、AというゲームオブジェクトのUdon内でThisを用いると、Aが得られます。)
- Const 任意の型名(QS: System→任意の型名)  
任意の型の定数(決まった値)を設定し、得る。
- Is Valid(QS: Special)  
オブジェクトが有効なものであるかどうかで処理を分岐する。 (分かる方向けに言えば、Nullチェックに用います)
- IsValid(QS: VRC→Utilities)  
オブジェクトが有効なものであるかどうかの真偽値を得る。 (分かる方向けに言えば、Nullチェックに用います)

## おわりに
ご覧いただきありがとうございます。
参考になれば幸いです。