VRChatのワー ルドで、自分の書いたコードを初めて動かす。その一歩が、触ると反応するCubeです。
ただ、いきなり色まで変えようとすると、動かなかったときに困ります。押せていないのか、コードが違うのか、色の指定を間違えたのか、区別がつきません。
この記事では、まず「押せているか」をログで確かめてから、色を変える処理を足します。順番に切り分けられる形で作ります。
この記事でわかること
- C#ファイル・Program Asset・Udon Behaviourの役割
- Interactが動いたことを、色より先にログで確かめる方法
- 反応しないときに見る順番
- Inspectorに出した値を、コードを触らずに変える感覚
床のあるシーンから始めます。まだなければ 最初のワールド で作れます。
作られるのは3つ。ノートと、翻訳カードと、名札
U# Scriptを作ると、ファイルが2つできて、Inspectorに3つ目が現れます。最初はここで混乱しがちなので、先に整理します。

- C#ファイル(
.cs) は、自分が書くノートです。「押したら色を変える」はここに書きます - Udon Sharp Program Asset は、そのノートをVRChatが読める形に翻訳したカードです。保存すると自動で更新されるので、中を開く必要はありません。消さないでください
- Udon Behaviour は、Cubeに付く名札です。「このCubeは、あのカードのとおりに動きます」という意味になります
直すのはノートだけです。保存すればカードが更新され、名札はそのカードを見ているだけです。
だから、同じノートを何個のCubeに貼っても、中身は共通になります。ただし「いま何色か」という状態は、Cubeごとに別々に持ちます。
実践:押すと色が変わるCubeを作る
完成すると、Cubeに近づいて操作するたびに、青とオレンジが交互に切り替わります。
1. Cubeとマテリアルを置く
Playを止めた状態で作業します。Play中に変えた設定は、停止すると元に戻ります。
Hierarchyで「3D Object → Cube」を作り、名前を ColorCube にします。
| Transform | X | Y | Z |
|---|---|---|---|
| Position | 0 | 1 | 1 |
| Rotation | 0 | 0 | 0 |
| Scale | 1 | 1 | 1 |
床の上面がY=0なので、中心をY=1にすると下端が0.5になり、床に埋まらず操作しやすい高さになります。Box Colliderはそのまま、Is Triggerはオフのままにします。Rigidbodyは追加しません。 Interactに必要なのは、Colliderとプログラムだけです。
次に色を入れる器を用意します。Assets に Materials フォルダを作り、「Create → Material」で ColorCubeMaterial を作って、Shaderを Standard にします。作ったマテリアルを ColorCube へドラッグしてください。
2. U# Scriptを作る
Assets に Scripts フォルダを作り、右クリックから 「Create → U# Script」 を選びます。
ここが最初の分かれ道です。「C# Script」ではなく「U# Script」 を選んでください。C# Scriptを選ぶと普通のUnityスクリプトができてしまい、Cubeに付けてもUdonとしては動きません。隣にProgram Assetが作られないので、そこで気づけます。
名前は ColorChanger にします。ファイル名と、コードの中の class の名前は必ず一致させてください。 ずれているとコンパイルが通りません。日本語やスペースを含む名前も避けます。
3. まずログだけ出す
いきなり色を変えず、押せているかどうかだけ を確かめます。ColorChanger.cs を開いて、次の内容にして保存してください。
using UdonSharp;
using UnityEngine;
[UdonBehaviourSyncMode(BehaviourSyncMode.None)]
public class ColorChanger : UdonSharpBehaviour
{
// 「使う」操作を受け取る入口。public override を外すと呼ばれない
public override void Interact()
{
Debug.Log("[ColorChanger] 押されました");
}
}
public override void Interact() の書き方に注意してください。void Interact() だけ書いてもコンパイルは通りますが、エラーも出ないまま一生呼ばれません。これは原因に気づきにくい定番の失敗です。
Unityに戻り、コンパイルが終わるのを待ちます。次にCubeへ付けます。
- Hierarchyで
ColorCubeを選ぶ - 「Add Component」で Udon Behaviour を追加する
- Program Source へ、Projectの
ColorChangerの Program Asset をドラッグする
ここで一度Playします。Gameビューをクリックして操作を移し、Cubeに照準を合わせてください。操作案内が出たら、デスクトップでは左クリック です。
Consoleに「押されました」が出れば成功です。 ここが通ってから、色の処理を足します。
4. 色を変える処理を足す
Playを止めて、コードを次の内容に置き換えます。
using UdonSharp;
using UnityEngine;
[UdonBehaviourSyncMode(BehaviourSyncMode.None)]
public class ColorChanger : UdonSharpBehaviour
{
[SerializeField] private MeshRenderer targetRenderer; // 色を変える相手
[SerializeField] private Color startColor = Color.blue;
[SerializeField] private Color changedColor = new Color(1f, 0.5f, 0f);
private Material instanceMaterial; // このCube専用のマテリアル
private bool isChanged; // いま切り替わっているか
private void Start()
{
if (targetRenderer == null)
{
Debug.LogWarning("[ColorChanger] Target Rendererが未設定です。");
return;
}
instanceMaterial = targetRenderer.material;
instanceMaterial.color = startColor;
}
public override void Interact()
{
if (instanceMaterial == null) return;
isChanged = !isChanged; // 真偽を反転する
instanceMaterial.color = isChanged ? changedColor : startColor; // 条件で選ぶ
}
}
コードは3つに分かれています。
設定する値 が最初の3行です。[SerializeField] が付いているので、private でもInspectorから設定できます。
最初の準備 が Start() です。相手が未設定なら理由をConsoleに出して止まります。設定されていればマテリアルを取り出し、最初の色にします。
押されたときの処理 が Interact() です。isChanged は true か false を持つ変数で、! を付けると反転します。条件 ? A : B は、条件が真ならA、偽ならBを選ぶ書き方です。
| 操作 | isChanged | 表示される色 |
|---|---|---|
| 起動直後 | false | 青 |
| 1回目 | true | オレンジ |
| 2回目 | false | 青 |
毎フレーム動く Update() は使っていません。押された瞬間だけ処理が走ります。
targetRenderer.material を使っているのには理由があります。これは そのRenderer専用のマテリアル を取り出します。もし sharedMaterial を書き換えると、同じマテリアルを使っている他のCubeまで一緒に色が変わってしまいます。
5. 参照を割り当てる
Unityに戻ると、Udon Behaviourに設定欄が増えています。

- Target Renderer へ、Hierarchyの
ColorCubeをドラッグする(同じオブジェクトのMesh Rendererが入ります) - Start Colorが青、Changed Colorがオレンジになっていることを確認する
- Interaction Text を
色を変えるにする - シーンを保存する
Interaction Textは、近づいたときに表示される案内です。空でも押せます。押しやすくするための表示なので、何が起きるかが分かる短い言葉にします。
6. ClientSimで確かめる
Playして、Gameビューをクリックしてから、Cubeに近づきます。
| 操作 | 期待する結果 |
|---|---|
| Cubeに照準を合わせる | 「色を変える」の案内が出る |
| 操作する(左クリック) | 青からオレンジへ変わる |
| もう一度操作する | 青へ戻る |
| Playを止めてもう一度始める | 青から始まる |

以前の作例を撮影したものです。この記事のコードでは、青とオレンジの2色で切り替わります。
SceneビューでCubeをクリ ックするのと、Gameビューでプレイヤーとして操作するのは別です。 クリックして枠が光るだけなら、編集画面のほうを触っています。
反応しないときの見る順番
上から順に確かめると、どこで止まっているかが分かります。

- 照準を合わせて、案内が出るか → 出ないなら、Colliderがあるか、遠すぎないか、手前に別のオブジェクトがないか
- Consoleに押したログが出るか → 出ないなら、
public override void Interact()の書き方か、Program Sourceが空か - Consoleに赤いエラーが出ていないか → 出ているなら、いちばん上のエラーのファイル名と行番号を見る
- Target Rendererが
Noneになっていないか → 起動時に警告が出ているはずです - 色が変わらないなら、2色が同じ値になっていないか
よくある失敗をもう2つ挙げます。空の親オブジェクトにプログラムを付けて、Colliderは子のCubeにある 場合、Interactは動きません。同じオブジェクトに両方が必要です。もう1つは、Play中にInspectorを編集して、停止したら消えた というものです。設定はPlayを止めてから入れて保存します。
値を変えて確かめる
動いたら、2つ試してみてください。コードを触らずに結果が変わることが実感できます。
Changed Colorだけ緑に変える。 コードは1文字も変えていないのに、2回目の色が変わります。Inspectorの値がそのまま処理に渡っていることが分かります。
Cubeをもう1つ置いて、Target Rendererに2個目を指定する。 1個目を押すと、2個目の色が変わります。操作を受け取る場所と、結果が出る場所は別にできる という、これから何度も使う考え方です。
ここまでで、イベント・状態・参照の3つを使いました。
おまけ:先に知っておくと良いこと
- Debug.Logは最初の相棒: 動かないときに「ここまで来ているか」を確かめられます。処理の入口に1行入れるだけで、原因が半分に絞れます
- Interactは近づかないと押せない: 既定の距離はおよそ2mです。遠くに置いたオブジェクトが反応しないときは、まず近づいてみてください
- VRC Pickupと一緒に付けない: 掴む操作が優先されて、Interactが動かなくなります
- 同期はまだ考えない: このコードは押した人の画面でしか色が変わりません。全員に伝えるのは ネットワーク同期入門 の話です
- Play中の変更は保存されない: 色や位置をPlay中に調整したら、値をメモして、停止してから入れ直します
まとめ
最初のUdonSharpは 、3つのつながりでできています。
- ノート(C#ファイル)を書くと、翻訳カード(Program Asset)が自動でできる
- そのカードを、Cubeの名札(Udon Behaviour)に差す
- 色より先に、ログで「押せているか」を確かめる
public override void Interact()の書き方を外すと、エラーなしで無反応になる
うまくいかないときの問いかけは、「案内は出るか、ログは出るか」 です。この2つで、原因が入力側かコード側かに分かれます。
プログラミングが初めてなら、次は プログラムの4つの部品 で変数・if・for・関数を通しでつかんでください。書き方が分かっているなら 変数と参照 や メソッドとカスタムイベント へ進みます。