【VRChat】ドアギミックを作る:自動ドア・手動ドアの同期実装

作成: 2025-12-19

動的オブジェクトの基本となるドアの実装方法。近づくと開く自動ドア、クリックで開閉する手動ドア、アニメーション連携とネットワーク同期。

概要

ドアは、空間を区切り、プレイヤーの移動を制御する基本的な建築要素であり、ワールドにインタラクティブ性をもたらす最初のステップとして最適なギミックです。ドアが自動で開いたり、プレイヤーのアクションで開閉したりすることで、ワールドは格段に没入感を増します。

本記事では、ドアのギミックを実装するために不可欠なアニメーションの基本から解説し、以下の2つの実践的なドアの制作方法をステップバイステップで紹介します。

  1. 同期自動ドア: プレイヤーが近づくと自動で開き、離れると閉じる。その状態は全プレイヤーで同期される。
  2. 同期手動ドア: ドアノブなどをクリック(Interact)すると開閉し、その状態が全プレイヤーで同期される。

ステップ1: Unityエディタでのドアとアニメーションの準備

まず、UdonSharpで制御するためのドアのモデルとアニメーションを用意します。

1. ドアのGameObject構造

  • 回転するドアを正しく動作させるため、GameObjectの親子関係を工夫します。まず空のGameObjectを作成し「Door_Pivot」と名付けます。これがドアの回転軸(蝶番)になります。
  • 次に、3Dモデルのドア本体を「Door_Pivot」の子オブジェクトにします。ドア本体のローカル座標を調整し、回転軸がモデルの端に来るようにします。
  • こうすることで、「Door_Pivot」を回転させるだけで、ドアがリアルに開閉するようになります。

2. 開閉アニメーションの作成

  • Door_Pivotオブジェクトを選択した状態で、Unityのメニューから [Window] > [Animation] > [Animation] を開き、Animationウィンドウを表示します。
  • 「Create」ボタンを押し、新しいアニメーションクリップを作成します。まず「Door_Open」という名前で保存します。
  • 録画ボタン(赤い丸)を押し、アニメーションの記録を開始します。
    • 0フレーム目で、Door_PivotTransform > Rotationプロパティを初期状態(例: Y=0)でキーフレーム登録します。
    • 60フレーム目(1秒後)で、Rotationをドアが開いた状態(例: Y=90)に変更し、キーフレームを登録します。
  • 録画を停止します。これでドアが開くアニメーションができました。
  • 同様の手順で、「Door_Close」アニメーションも作成します(0フレーム目がY=90、60フレーム目がY=0)。

3. Animator Controllerの設定

  • Projectウィンドウで右クリックし、[Create] > [Animator Controller] を選択、「Door_Animator」という名前で作成します。
  • 作成したDoor_AnimatorをダブルクリックしてAnimatorウィンドウを開きます。
  • Projectウィンドウから「Door_Open」と「Door_Close」のアニメーションクリップをAnimatorウィンドウにドラッグ&ドロップします。
  • Animatorウィンドウの左側にある「Parameters」タブで、「+」ボタンから「Trigger」を選択し、「Open」と「Close」という名前のトリガーを2つ作成します。
  • EntryステートからDoor_Closeへ矢印(トランジション)を引きます。これはデフォルトでドアが閉まっている状態にするためです。
  • Door_CloseからDoor_Openへトランジションを引き、そのトランジションを選択してInspectorでConditionsに「Open」トリガーを設定します。
  • Door_OpenからDoor_Closeへトランジションを引き、Conditionsに「Close」トリガーを設定します。
  • 最後に、Door_PivotオブジェクトにAnimatorコンポーネントを追加し、Controllerフィールドに作成したDoor_Animatorを割り当てます。

これで、UdonSharpから「Open」または「Close」のトリガーを呼び出すことで、対応するアニメーションが再生される準備が整いました。

パターン1: 同期自動ドア

プレイヤーが近づくと開き、離れると閉じるドアです。誰かが近づいた場合、全プレイヤーの視界でドアが開くように同期させます。

トリガーの設定

  • Door_Pivotオブジェクトに、Box Colliderコンポーネントを追加します。
  • Box Colliderのサイズを調整し、プレイヤーがドアに近づいたことを検知したい範囲(ドアの前後の空間)を覆うようにします。
  • Box ColliderのInspectorで、**Is Trigger**プロパティにチェックを入れます。これにより、物理的な壁ではなく、侵入を検知するセンサーとして機能するようになります。

スクリプト: SyncedAutoDoor.cs

using UdonSharp;
using UnityEngine;
using VRC.SDKBase;

public class SyncedAutoDoor : UdonSharpBehaviour
{
    [Tooltip("制御するドアのAnimatorを割り当てます。")]
    public Animator doorAnimator;

    // 誰かがトリガー内にいるかどうかを同期する
    [UdonSynced]
    private bool isSomeoneInside = false;

    // トリガー内にいるプレイヤーの数をローカルでカウントする
    private int localPlayerCount = 0;

    // プレイヤーがトリガー範囲に入ったときに呼び出される
    public override void OnPlayerTriggerEnter(VRCPlayerApi player)
    {
        // ローカルプレイヤーが入った場合のみ処理
        if (!player.isLocal) return;

        localPlayerCount++;
        // 自分が最初の一人として入った場合、所有権を取って状態を更新
        if (localPlayerCount == 1)
        {
            Networking.SetOwner(Networking.LocalPlayer, this.gameObject);
            isSomeoneInside = true;
            RequestSerialization();
            UpdateDoorState();
        }
    }

    // プレイヤーがトリガー範囲から出たときに呼び出される
    public override void OnPlayerTriggerExit(VRCPlayerApi player)
    {
        if (!player.isLocal) return;

        localPlayerCount--;
        // 自分が最後の一人として出た場合、所有権を取って状態を更新
        if (localPlayerCount == 0)
        {
            Networking.SetOwner(Networking.LocalPlayer, this.gameObject);
            isSomeoneInside = false;
            RequestSerialization();
            UpdateDoorState();
        }
    }

    public override void OnDeserialization()
    {
        UpdateDoorState();
    }

    private void UpdateDoorState()
    {
        if (doorAnimator != null)
        {
            if (isSomeoneInside)
            {
                doorAnimator.SetTrigger("Open");
            }
            else
            {
                doorAnimator.SetTrigger("Close");
            }
        }
    }
}

Unityでの設定

  1. SyncedAutoDoor.csを作成し、Door_PivotオブジェクトにアタッチしたUdon Behaviourに割り当てます。
  2. Door Animatorフィールドに、同じくDoor_PivotにアタッチされているAnimatorコンポーネントをドラッグ&ドロップします。

パターン2: 同期手動ドア

ドアまたはドアノブをクリックすることで開閉するドアです。

スクリプト: SyncedManualDoor.cs

using UdonSharp;
using UnityEngine;
using VRC.SDKBase;

public class SyncedManualDoor : UdonSharpBehaviour
{
    [Tooltip("制御するドアのAnimatorを割り当てます。")]
    public Animator doorAnimator;

    [UdonSynced]
    private bool isOpen = false;

    void Start()
    {
        UpdateDoorState();
    }

    public override void Interact()
    {
        Networking.SetOwner(Networking.LocalPlayer, this.gameObject);
        isOpen = !isOpen;
        RequestSerialization();
        UpdateDoorState();
    }

    public override void OnDeserialization()
    {
        UpdateDoorState();
    }

    private void UpdateDoorState()
    {
        if (doorAnimator != null)
        {
            if (isOpen)
            {
                doorAnimator.SetTrigger("Open");
            }
            else
            {
                doorAnimator.SetTrigger("Close");
            }
        }
    }
}

Unityでの設定

  1. SyncedManualDoor.csを作成し、クリックさせたいオブジェクト(ドア本体や、ドアノブとして作成した別オブジェクト)のUdon Behaviourに割り当てます。
  2. そのオブジェクトにColliderが付いていることと、Udon BehaviourのInteraction Textが設定されていることを確認します。
  3. Door Animatorフィールドに、Door_PivotオブジェクトのAnimatorコンポーネントをドラッグ&ドロップします。

まとめ

  • ドアギミックの核心は、Animator ControllerとUdonSharpの連携です。UdonSharpからSetTriggerを呼び出してアニメーションを再生させます。
  • 自動ドアOnPlayerTriggerEnter/Exitと、トリガーとして設定したColliderを使用します。
  • 手動ドアInteractイベントを使用します。
  • どちらのパターンでも、開閉状態を[UdonSynced]変数で管理し、状態が変化した際にRequestSerialization()を呼び出すことで、全プレイヤーでドアの動きを同期させることができます。

ドアは、アニメーション、トリガー、同期というUdonSharpギミック制作の重要要素を学ぶのに最適な題材です。この知識を応用すれば、動く床や隠し通路など、様々な動的オブジェクトを制作できるようになります。