「この部屋に入ったら案内を出 したい」「橋を渡り始めたら音を鳴らしたい」。エリアに入ったことを検知したい場面はよくあります。
VRChatにはこれ専用のイベントがあります。ただ、そのまま書くと 他の人が入ったときにも自分の画面で反応してしまいます。
この記事では、入った本人だけに案内を出す ところまでを作ります。
この記事でわかること
- トリガーのイベントが誰のPCで呼ばれるか
isLocalの判定が必要な理由- 検知範囲の作り方
- 検知が抜ける場面と対処
変数と参照 を試した状態から始めます。
トリガーは全員のPCで呼ばれる
OnPlayerTriggerEnter(VRCPlayerApi player) は、誰かが検知範囲に入ったときに呼ばれます。

大事なのは、インスタンスにいる全員のPCで呼ばれる ことです。引数の player が「入った人」です。
Aさんがエリアに入ると、Aさんのクライアントでも、BさんのクライアントでもCさんのクライアントでも OnPlayerTriggerEnter(A) が実行されます。
つまり、そのまま案内を出すコードを書くと、Bさんの画面にも「あなたはエリアに入りました」と出てしまいます。

これを防ぐのが isLocal の判定です。
public override void OnPlayerTriggerEnter(VRCPlayerApi player)
{
if (!player.isLocal) return; // 入ったのが自分でなければ何もしない
// ここから先は、自分が入ったときだけ動く
}
player.isLocal は「そのプレイヤーが、いまこのコードを動かしているPCの持ち主か」を返します。自分なら true です。

「誰かが入った」という情報は全員に来る。そこから自分に関係あるものだけを拾う。 これがVRChatのトリガーの基本形です。
逆に、isLocal を入れないほうがいい場面もあります。「誰かが入ったら、全員の画面でランプを光らせたい」なら、判定は要りません。何をしたいかで決めます。
実践:入った人だけに案内を出す
床の一角に見えない検知範囲を置いて、そこに入った人だけに看板を表示します。
1. 検知範囲を作る
「Create Empty」で WelcomeZone を作り、(0, 1, 2) に置きます。
「Add Component」で Box Collider を追加して、次のようにします。
| 項目 | 設定 |
|---|---|
| Is Trigger | オン(これが必須です) |
| Size | (3, 2, 3) |
| Center | (0, 0, 0) |
Is Trigger をオンにするのを忘れないで ください。 オフのままだと壁になってしまい、検知もされません。
Rigidbodyは不要です。プレイヤーの検知には、ColliderとUdonがあれば足ります。
Sceneビューで緑の枠が見えるので、床のどのあたりを覆っているか確認しておきます。
2. 表示する看板を作る
「3D Object → Cube」で WelcomeSign を作り、(0, 2, 2.8)、Scale (1.5, 0.6, 0.05) に置きます。
作ったら、Inspectorの左上のチェックを外して 無効にしておきます。最初は見えない状態から始めます。
3. コードを書く
Assets/Scripts で「Create → U# Script」を選び、WelcomeZoneTrigger を作ります。
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
[UdonBehaviourSyncMode(BehaviourSyncMode.None)]
public class WelcomeZoneTrigger : UdonSharpBehaviour
{
[SerializeField] private GameObject signObject;
private void Start()
{
if (signObject != null) signObject.SetActive(false);
}
public override void OnPlayerTriggerEnter(VRCPlayerApi player)
{
if (!player.isLocal) return; // 入ったのが自分でなければ無視
if (signObject != null) signObject.SetActive(true);
Debug.Log("[WelcomeZone] 入りました");
}
public override void OnPlayerTriggerExit(VRCPlayerApi player)
{
if (!player.isLocal) return;
if (signObject != null) signObject.SetActive(false);
Debug.Log("[WelcomeZone] 出ました");
}
}
Start() で確実に非表示にしています。Inspectorで有効のままビルドしてしまう事故を防ぐためです。
Enter と Exit で対になっているところも大事です。入ったら出るまでを1組で考えます。 片方だけ書くと、出たあとも表示が残ります。
4. 割り当てて確かめる
WelcomeZone に Udon Behaviour を追加し、WelcomeZoneTrigger を指定します。Sign Objectに WelcomeSign をドラッグします。
Playして歩いてみてください。
| 操作 | 期待する結果 |
|---|---|
| 範囲の外を歩く | 看板は見えない |
| 範囲に入る | 看板が現れる。Consoleに 入りました |
| 範囲から出る | 看板が消える。出ました |
| 範囲の中で立ち止まる | 何度もログは出ない |
最後の行も確認しておいてください。Enterは入った瞬間の1回だけ です。中にいるあいだ繰り返し呼ばれることはありません。
5. isLocalを外して比べる
余裕があれば、if (!player.isLocal) return; の行を一時的にコメントアウトして、Build & Testで2人にして試してみてください。
片方が入ると、もう片方の画面でも看板が出ます。 これが isLocal を入れる理由です。確認したら戻してください。
検知が抜ける場面がある
トリガーは万能ではありません。次の場合、検知されないことがあり ます。

- テレポートで範囲を飛び越えた: 移動の途中を通らないので、EnterもExitも呼ばれません
- 非常に速く通り抜けた: 1フレームの間に範囲を通過すると、判定に引っかからないことがあります
対処は2つです。
1つ目は、範囲を厚くする。 通路を横切る検知なら、進行方向に厚みを持たせます。薄い板のような範囲は抜けやすくなります。
2つ目は、別の方法と併用する。 落下の検知なら、トリガーだけに頼らず高さを見る方法もあります(落下復帰とチェックポイント で扱います)。
もう1つ、テレポートで入った場合は、Exitだけが呼ばれない ということも起こります。「入ったまま出られない」状態を避けるには、範囲の外に出たことを別の方法でも確認できるようにしておきます。
うまくいかないときは
- 何も反応しない → ColliderのIs Triggerがオンか、Udonが同じオブジェクトに付いているかを確認します
- 他の人が入っても反応す る →
isLocalの判定が抜けています - 出ても表示が残る →
OnPlayerTriggerExitを書いていないか、そこにもisLocalの判定が要ります - 範囲が見えない → SceneビューでGizmosがオンになっているか確認します。Playすると緑の枠は消えます
おまけ:先に知っておくと良いこと
OnPlayerTriggerStayは重い: 中にいるあいだ毎フレーム呼ばれます。使うなら中身を軽くします。多くの場合、EnterとExitで足ります- 物のトリガーは別のイベント: プレイヤーではなくオブジェクトを検知したいときは
OnTriggerEnter(Collider other)を使います。こちらはUnityの標準です - 範囲は複数置ける: 部屋ごとに検知範囲を置けば、「いまどの部屋にいるか」を追えます。BGMを切り替える仕掛けなどに使えます
- これはローカルの処理です: 看板を全員に見せたいなら、同期の仕組みが必要です。ネットワーク同期入門 で扱います
- 使いどころはいろいろ: 交流ワールドの部屋ごとの案内、脱出ゲームのスイッチ、アスレチックのチェックポイント、展示ワールドの作品解説。どれも同じ形で作れます
まとめ
トリガーは、範囲に入ったことを知らせてくれます。
- イベントは全員のPCで呼ばれる。引数が「入った人」
- 自分だけに反応させるなら
isLocalで絞る - ColliderのIs Triggerがオン、Rigidbodyは不要
- テレポートや高速移動では抜けることがある
書く前の問いかけは、「この反応は、入った本人だけか、全員か」 です。本人だけなら isLocal を入れます。
次は、検知した場所から別の場所へ飛ばします。テレポーターを作る へ進むか、落ちたときに戻す仕掛けなら 落下復帰とチェックポイント が入口です。