アスレチックのワー ルドを作ると、落ちたときの扱いが問題になります。
標準の設定に任せると、スポーン地点まで戻されます。5分かけて登った先で落ちたら、また最初からです。それでは遊ぶ気が続きません。
この記事では、落ちたら直前に通った足場へ戻る 仕掛けを作ります。標準の仕組みとの使い分けも整理します。
この記事でわかること
- 標準の復帰と、自作のチェックポイントの使い分け
- 落下を検知する2つの方法
- 戻した直後にまた落ちる問題への対処
- 無限リスポーンを防ぐ条件
テレポーターを作る と トリガーでエリアを検知する を試した状態から始めます。
標準の復帰で足りる場面、足りない場面
VRChatには、落ちたときに戻す仕組みが最初から用意されています。Scene Descriptorの Respawn Height です。

この高さより下に落ちると、スポーン地点へ戻されます。 設定するだけで動くので、まずはこれで十分な場面が多くあります。
- 平らな部屋のワールド → 標準で十分
- 展示や交流のワールド → 標準で十分
- 長い道のりを進むワールド → 途中から再開したい
チェックポイントが必要になるのは、3つ目です。アスレチック、脱出ゲーム、探索型のワールド。「せっかくここまで来たのに」を防ぎます。
作るものは、この2つの組み合わせです。
- 通過したら記録する: 足場に置いた検知範囲を通るたび、そこを「直前の足場」として覚える
- 落ちたら戻す: 一定の高さより下がったら、覚えている場所へ移動させる
どちらも、ここまでの記事で扱った仕組みで作れます。
実践:チェックポイントに戻る仕掛けを作る
3つの足場を階段状に並べ、落ちたら直前に通った足場へ戻るようにします。
1. 足場とチェックポイントを置く
床のあるシーンに、次を置きます。
| 名前 | 作り方と設定 |
|---|---|
Step0 | Cube。(0, 0.5, 3)、Scale (2, 0.2, 2) |
Step1 | Cube。(3, 1.5, 5)、Scale (2, 0.2, 2) |
Step2 | Cube。(6, 2.5, 7)、Scale (2, 0.2, 2) |

3つの足場が、少しずつ高くなりながら奥へ伸びます。
それぞれの上に、記録用の検知範囲と、戻る位置を置きます。
| 名前 | 親 | 設定 |
|---|---|---|
Checkpoint0 | Step0 の子 | Create Empty。Local Position (0, 1, 0)。Box Collider(Is Trigger オン、Size (2, 2, 2)) |
Checkpoint1 | Step1 の子 | 同上 |
Checkpoint2 | Step2 の子 | 同上 |
足場の子にしておくと、足場を動かしたときにチェックポイントも一緒に動きます。
2. 記録を持つスクリプトを書く
まず、「いまどこが直前の足場か」を覚える側を作ります。「Create Empty」で CheckpointManager を作り、(0, 0, 0) に置きます。
Assets/Scripts で CheckpointManager を作ります。
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
[UdonBehaviourSyncMode(BehaviourSyncMode.None)]
public class CheckpointManager : UdonSharpBehaviour
{
[SerializeField] private Transform defaultPoint; // 最初の戻り先
[SerializeField] private float fallLimitY = -3f; // ここより下がったら落下とみなす
private Transform currentPoint;
private VRCPlayerApi localPlayer;
private void Start()
{
localPlayer = Networking.LocalPlayer;
currentPoint = defaultPoint;
}
// チェックポイント側から呼ばれる
public void SetCheckpoint(Transform point)
{
if (point == null) return;
currentPoint = point;
Debug.Log("[Checkpoint] 記録: " + point.name);
}
private void Update()
{
if (!Utilities.IsValid(localPlayer)) return;
// 高さだけを見る。軽い処理
if (localPlayer.GetPosition().y > fallLimitY) return;
Respawn();
}
private void Respawn()
{
Transform target = currentPoint != null ? currentPoint : defaultPoint;
if (target == null) return;
localPlayer.TeleportTo(target.position, target.rotation);
localPlayer.SetVelocity(Vector3.zero); // 落ちる勢いを消す
Debug.Log("[Checkpoint] 戻しました: " + target.name);
}
}
落下の検知に Update を使っています。 毎フレーム動くので気になるかもしれませんが、やっているのは「自分1人の高さを比べる」だけなので、負荷はごくわずかです。トリガーで検知する方法より確実で、テレポートで飛び越えられる心配もありません。
Networking.LocalPlayer は Start で1回だけ取って、変数に持っています。毎フレーム取り直すより軽くなります。
3. チェックポイント側を書く
次に、通過を知らせる側です。CheckpointTrigger を作ります。
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
[UdonBehaviourSyncMode(BehaviourSyncMode.None)]
public class CheckpointTrigger : UdonSharpBehaviour
{
[SerializeField] private CheckpointManager manager;
[SerializeField] private Transform respawnPoint; // 戻る位置。空ならこのオブジェクト
public override void OnPlayerTriggerEnter(VRCPlayerApi player)
{
if (!player.isLocal) return; // 通ったのが自分でなければ無視
if (manager == null) return;
manager.SetCheckpoint(respawnPoint != null ? respawnPoint : transform);
}
}
isLocal の判定が入っています。他の人が通ったときに自分の記録が書き換わっては困るからです。
respawnPoint を空にしておくと、そのチェックポイント自身の位置へ戻ります。足場の少し上に置いてあるので、そのままで使えます。
4. 割り当てて確かめる
CheckpointManager に Udon Behaviour を追加し、Default Point にスポーン地点のオブジェクトを、Fall Limit Y に -3 を設定します。
Checkpoint0 から Checkpoint2 それぞれに Udon Behaviour を追加し、CheckpointTrigger を指定して、Manager に CheckpointManager をドラッグします。
Playして試してください。
| 操作 | 期待する結果 |
|---|---|
Step0 に乗る | Consoleに 記録: Checkpoint0 |
| そこから落ちる | Checkpoint0 の上に戻る |
Step2 まで登ってから落ちる | Checkpoint2 の上に戻る。最初からやり直しにならない |
| 戻った直後 | その場に立っている(また落ちない) |
3行目が、この仕掛けの目的です。 進んだ分だけ、再開地点も進みます。
戻す先は、判定の線より上
この仕掛けで起きる事故が1つあります。無限リスポーン です。

戻す先の高さが、落下と判定する高さ(fallLimitY)より 低い と、こうなります。
- 落ちる
- 戻される
- 戻った場所がまだ判定の線より下
- また落ちたと判定される
- 以下、無限に繰り返す
画面が点滅して、身動きが取れなくなります。
防ぎ方はシンプルです。戻す先は必ず判定の線より上に置きます。 今回の例では、 いちばん低い Checkpoint0 がY=1.5あたりにあり、fallLimitY は -3 なので、十分に離れています。
もう1つ、戻した直後に速度をゼロにする ことも忘れないでください。SetVelocity(Vector3.zero) がないと、落ちる勢いのまま戻されて、次の瞬間にまた線を割ります。結果は同じく無限リスポーンです。
判定の高さを決めるときは、いちばん低いチェックポイントより、さらに数メートル下 を目安にします。
うまくいかないときは
- 戻らない →
CheckpointManagerのFall Limit Yが低すぎないか。足場から落ちても届かない値になっていませんか - 点滅して動けない → 無限リスポーンです。戻す先の高さと判定の高さを見直します
- 戻ってもまた落ちる →
SetVelocity(Vector3.zero)が抜けています - 記録されない → チェックポイントのColliderがIs Triggerか、Managerが割り当てられているかを確認します
- 他の人が通ると自分の記録が変わる →
isLocalの判定が抜けています
おまけ:先に知っておくと良いこと
- 標準のRespawn Heightも残しておく: この仕掛けが何かの理由で動かなかったときの保険になります。判定の高さより、さらに下に設定しておきます
- 記録は各自が持つ: このコードは同期していないので、チェックポイントは1人1人が別々に持ちます。アスレチックではこれが正しい動作です
- 戻る位置に向きも付けられる: チェックポイントのRotationを調整すると、戻ったときの正面を決められます。次に進む方向を向かせると親切です

- 戻ったことを知らせる: 音を鳴らしたり短い表示を出したりすると、「戻された」ことが伝わって親切です。ボタンで切り替える の音の扱いが使えます
- チェックポイントは戻さない: 一度先に進んだあと、手前のチェックポイントを通っても記録を戻さない、という作りもできます。番号を持たせて、大きいほうだけ記録します
まとめ
チェックポイントは、2つの部品の組み合わせです。
- 通過したら記録する(トリガー+
isLocal) - 落ちたら戻す(高さの監視+
TeleportTo) - 戻した直後に
SetVelocity(Vector3.zero)で勢いを消す - 戻す先は、必ず落下判定の線より上に置く
作ったあとの問いかけは、「戻った場所は、判定の線より上にあるか」 です。ここを外すと無限リスポーンになります。
移動の仕組みをもっと使うなら テレポーターを作る、エリアの検知を広げるなら トリガーでエリアを検知する へ進んでください。