ボタンを作りました。押して も、何も起きません。
コードを何度も読み返して、それらしいところを直しては試す。1時間たっても直りません。実際の原因は、コードではなく ボタンにColliderが付いていなかったこと でした。
押した操作がそもそも届いていないのか、届いたあとで止まっているのか。 ここを先に決めれば、探す範囲は半分になります。この記事では、その決め方を扱います。
この記事でわかること
- 入口のログで切り分ける順番
- Consoleの見方と、見落としやすいところ
- ClientSim・Build & Test・実機の使い分け
- ログが出ないときの原因
メソッドとカスタムイベント を試した状態から始めます。
中を読む前に、入口を見る
動かないコードを前にすると、中身を読み返したくなります。その前にやることがあります。
メソッドの先頭に、ログを1行だけ置いてください。
public override void Interact()
{
Debug.Log("[DoorButton] 押された"); // 入口のログ
// ...
}
Playして押してみます。このログが出るか出ないかで、世界が2つに分かれます。

| 結果 | 意味 | 見るところ |
|---|---|---|
| 出ない | 押した操作が届いていない | Collider、Udon Behaviourの割り当て、オブジェクトが有効か |
| 出る | 押した操作は届いている | 参照の割り当て、if の条件、同期 |
出ないときは、コードの中を1行も読まないでください。 そこは呼ばれていないので、いくら読んでも原因はありません。
この切り分けが、デバッグでいちばん大きな一歩です。あとは同じことを、少し先で繰り返していきます。
Consoleウィンドウ(Window → General → Console)で気をつけるの は2点です。
- Playする前に赤いエラーが出ていないか。 コンパイルが通っていないと、直す前のスクリプトが動いています
- Collapseがオンだと、同じログがまとまります。 何回押されたかを見たいときはオフにします
3つの実験場を使い分ける
確かめる場所は3つあります。上級・初級の順ではなく、何を確かめたいか で選びます。

| 場所 | 確かめられること | 確かめられないこと |
|---|---|---|
| ClientSim(UnityのPlay) | 入口まで来たか、参照漏れ、if の分岐、表示の切り替え | 同期、VRの手、端末の性能 |
| Build & Test(複数クライアント) | 同期、所有権、途中参加、実際の操作感 | 端末ごとの性能、通信の遅さ |
| アップロードして入る | 実際の見え方、読み込み時間、他の人のアバターとの兼ね合い | ログをその場で読むこと |
ConsoleとDebug.Logが同じ画面で完結するのは、ClientSimだけです。 だからまずここで直します。
同期が絡む問題に見えても、先にClientSimで自分1人の動きを確かめてください。 自分の画面でも動いていないなら、同期の問題ではありません。
実践:動かないボタンを3往復で直す
わざと3か所を壊したボタンを作って、順番に見つけていきます。実際の制作でも、この3つが原因の大半です。

1. わざと壊れたボタンを作る
床のあるシーンに、AnimatorとUdonで扉を動かす と同じ扉を用意します。DoorPivot にAnimatorがあり、IsOpen というBoolのパラメータがある状態です。
「Create Empty」で DoorButton を作り、扉のそばに置きます。Cubeではなく空のオブジェクトです。 ここが1つ目の仕込みです。
Assets/Scripts で DebugDoorButton を作ります。
using UdonSharp;
using UnityEngine;
[UdonBehaviourSyncMode(BehaviourSyncMode.None)]
public class DebugDoorButton : UdonSharpBehaviour
{
[SerializeField] private Animator doorAnimator;
[SerializeField] private bool locked = true; // 2つ目の仕込み
private bool isOpen;
public override void Interact()
{
Debug.Log("[DoorButton] 押された");
if (locked)
{
Debug.Log("[DoorButton] 鍵がかかっている");
return;
}
Debug.Log("[DoorButton] animatorがある: " + (doorAnimator != null));
isOpen = !isOpen;
doorAnimator.SetBool("IsOpen", isOpen);
}
}
DoorButton に Udon Behaviour を追加して、このスクリプトを指定します。Door Animatorは空のままにしておきます。 これが3つ目の仕込みです。
2. 1往復目:入口のログが出ない
Playして、DoorButton があるはずの場所に近づきます。
そもそもインタラクトの表示が出ません。 Consoleにも何も出ません。
入口のログが出ない。ここで見るのは3つです。
| 見るところ | この場合 |
|---|---|
| Colliderが付いているか | 付いていない |
| Udon Behaviourが正しいオブジェクトにあるか | ある |
| オブジェクトが有効か | 有効 |
DoorButton に「Add Component → Box Collider」を追加して、Sizeを (0.4, 0.4, 0.4) にします。
もう一度Playすると、今度は押せて、[DoorButton] 押された が出ます。押した操作が届くようになりました。
空のオブジェクトにはColliderがありません。Cubeから作れば最初から付いてきます。「押せない」の原因は、たいていここです。
3. 2往復目:入口は出るが、その先に進まない
押すとログは出ますが、扉は動きません。Consoleをよく見 ます。
[DoorButton] 押された
[DoorButton] 鍵がかかっている
2行目が答えです。 自分で書いた if で止まっています。
Inspectorで Locked のチェックを外します。これで先へ進みます。
ログを読むときは、最後の1行を見てください。 どこまで進んだかが、そこに書いてあります。
4. 3往復目:進んだのに動かない
もう一度押すと、こう出ます。
[DoorButton] 押された
[DoorButton] animatorがある: False
False です。参照が割り当てられていません。
Inspectorの Door Animator に DoorPivot をドラッグします。
押すと、扉が開きます。
| 往復 | 症状 | 原因 |
|---|---|---|
| 1 | ログが出ない | Colliderがない |
| 2 | 途中で止まる | 自分で書いた if |
| 3 | 最後まで来るのに動かない | 参照が None |
この3つで、動かないボタンの原因の大半が説明できます。 順番に見ていけば、どれかで必ず引っかかります。
5. ログを片付ける
直ったら、ログを消すか減らします。全部残すとConsoleが埋まって、次に困ったときに読めなくなります。
残すなら、エラーになりうるところだけ にします。
if (doorAnimator == null)
{
Debug.LogWarning("[DoorButton] Door Animatorが未設定です");
return;
}
Debug.LogWarning は黄色いアイコンで表示されるので、普通のログに埋もれません。「あとで自分が困るところ」に置いておく と、次のときに助かります。
ログが出ないときは
- Consoleに何も出ない → Playする前に赤いエラーがないか確認します。コンパイルが通っていません
- 同じログが1回しか出ない → ConsoleのCollapseがオンです。オフにします
- 押せない → Colliderがないか、Is Triggerがオンになっています。インタラクトには通常のColliderが要ります
- 近づかないと押せない → インタラクトには距離の制限があります。もっと近づきます
- Pickupを付けたら押せなくなった → 掴む操作が優先されます。押す物と掴む物は分けます
- UIのボタンが反応しない → Interactではなく、CanvasのOn Clickの設定とVRC Ui Shapeを見ます
- ビルドしたワールドでだけ動かない → ここで初めて同期と所有権を疑います
おまけ:先に知っておくと良いこと
- VRChatの中のログはファイルに残る: Consoleは見られませんが、クライアントがログを書き出しています。WindowsならAppDataのLocalLowにあるVRChatのフォルダに、テキストで残 ります。アップロード後にしか起きない問題は、ここを見ます
- ログにはタグを付ける:
[DoorButton]のように名前を付けておくと、Consoleの検索欄で絞り込めます。仕掛けが増えたときに効いてきます - 値も一緒に出す: 「通った」だけでなく、
"count=" + countのように値を添えると、次の一往復が省けます - 1つずつ直す: 3か所まとめて直すと、どれが効いたか分かりません。1つ直して、試して、次へ進みます
- ワールド内に表示する手もある: TextMeshProに状態を出すと、VRChatの中でも見えます。同期の確認では、この方法が便利です
まとめ
直し方の順番は、いつも同じです。
- メソッドの先頭にログを1行置く
- 出ないなら、押した操作が届いていない。中身は読まない
- 出るなら、参照・条件・同期を順に見る
- 確かめる場所は、何を知りたいかで選ぶ
困ったときの問いかけは、「入口のログは出ているか」 です。ここに答えられれば、探す範囲はもう半分になっています。
Udonで書けないC#に出会ったら Udonで使えるC#と使えないC#、症状から探すなら 困ったときの逆引き へ進んでください。