【VRChat】メソッドとカスタムイベント:SendCustomEventでスクリプト間連携

作成: 2025-12-19

コードの再利用とスクリプト間連携の方法。メソッド定義、SendCustomEvent、SendCustomNetworkEvent、遅延実行(SendCustomEventDelayedSeconds)の活用法。

概要

ギミックが複雑になってくると、すべてのロジックをStartUpdateといった単一のイベント内に記述するのは非効率的で、コードの可読性も低下します。処理を機能ごとにまとめたメソッド(関数) を作成し、それらを呼び出すことで、コードを整理し再利用性を高めることができます。

さらに、UdonSharpでは、あるスクリプトから別のスクリプトの処理を呼び出すためのカスタムイベントという仕組みが提供されています。これにより、複数のギミックが連携する複雑なシステムを構築できます。

本記事では、基本的なメソッドの定義方法から、スクリプト間で連携するためのSendCustomEvent、そしてネットワークを介して全プレイヤーにイベントを送信するSendCustomNetworkEventの使い方までを解説します。

1. メソッド(関数)の基本

メソッドとは、一連の処理を一つにまとめたブロックです。同じ処理を何度も書く代わりに、メソッドを一度定義しておけば、必要な時に何度でも呼び出すことができます。

メソッドの定義

メソッドは以下の形式で定義します。

戻り値の型 メソッド名(引数) { // 実行したい処理 }

  • 戻り値の型: メソッドが処理の結果として返す値のデータ型。値を返さない場合はvoidを指定します。
  • メソッド名: メソッドを識別するための名前。
  • 引数: メソッドに渡すデータ。不要な場合は()の中を空にします。
using UdonSharp;
using UnityEngine;

public class MethodExample : UdonSharpBehaviour
{
    // 引数も戻り値もない、最もシンプルなメソッド
    private void PlaySound()
    {
        // 音を再生する処理...
        Debug.Log("サウンドを再生しました。");
    }

    // int型の引数を2つ受け取り、計算結果をコンソールに出力するメソッド
    private void AddAndLog(int a, int b)
    {
        int result = a + b;
        Debug.Log($"計算結果: {result}");
    }

    // int型の引数を2つ受け取り、その合計値をint型で返すメソッド
    private int GetSum(int a, int b)
    {
        return a + b;
    }
}

メソッドの呼び出し

定義したメソッドは、メソッド名(引数); の形式で呼び出します。

public class MethodCaller : UdonSharpBehaviour
{
    void Start()
    {
        // 同じスクリプト内のメソッドを呼び出す
        PlaySound(); // "サウンドを再生しました。"と表示される
        
        AddAndLog(10, 5); // "計算結果: 15"と表示される

        int sum = GetSum(7, 3);
        Debug.Log($"GetSumの結果は {sum} です。"); // "GetSumの結果は 10 です。"と表示される
    }
    
    // (上記メソッドの定義は省略)
}

2. スクリプト間連携: SendCustomEvent

別のUdonSharpBehaviourのメソッドを呼び出す方法として、SendCustomEventがあります。この仕組みを使うと、ターゲットとなるオブジェクトにアタッチされたUdonSharpBehaviourに対して「イベント名」を送信し、その名前を持つpublicメソッドを実行させることができます。

補足: UdonSharpでは、別のUdonSharpBehaviourの参照を変数として持っていれば、そのpublicメソッドを直接呼び出すことも可能です。SendCustomEventは、メソッド名を文字列で動的に指定したい場合や、後述する遅延実行を利用したい場合に特に有効です。

ターゲットのUdonBehaviour.SendCustomEvent("イベント名");

  • ターゲットのUdonBehaviour: イベントを送りたい相手のUdon Behaviourコンポーネント。
  • イベント名: 実行させたいメソッドの名前を文字列で指定します。

実装例: ボタンとドア

「ボタン」オブジェクトをクリックしたら、「ドア」オブジェクトが開く、という連携を実装してみましょう。

DoorController.cs (ドア側にアタッチ)

using UdonSharp;
using UnityEngine;

public class DoorController : UdonSharpBehaviour
{
    // このメソッドがカスタムイベントとして呼び出される
    public void OpenDoor()
    {
        Debug.Log("ドアが開きます。");
        // ドアを開くアニメーションを再生するなどの処理...
    }
}

ButtonController.cs (ボタン側にアタッチ)

using UdonSharp;
using UnityEngine;

public class ButtonController : UdonSharpBehaviour
{
    // InspectorでドアのUdon Behaviourコンポーネントを割り当てる
    public UdonSharpBehaviour doorUdonBehaviour;

    public override void Interact()
    {
        // doorUdonBehaviourに対して、"OpenDoor"という名前のカスタムイベントを送信する
        doorUdonBehaviour.SendCustomEvent("OpenDoor");
    }
}

この設定により、プレイヤーがボタンをInteractすると、ButtonControllerDoorControllerOpenDoorイベントを送信し、結果としてドアが開く処理が実行されます。これは自分のクライアント内でのみ発生します。

3. 全プレイヤーへのイベント送信: SendCustomNetworkEvent

SendCustomEventがローカルでの連携に使うのに対し、SendCustomNetworkEventインスタンス内の全プレイヤーに対してカスタムイベントを送信します。これにより、全プレイヤーの環境で同時に特定の処理を実行させることができます。

ターゲットのUdonBehaviour.SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.All, "イベント名");

  • NetworkEventTarget.All: 全プレイヤーに送信することを指定します。

実装例: 全員で一斉に再生するサウンド

ゲームマスターがボタンを押すと、全プレイヤーのクライアントで「ゲーム開始」のサウンドが鳴るギミックです。

SoundPlayer.cs (各プレイヤーのクライアントで音を鳴らす役割)

using UdonSharp;
using UnityEngine;

public class SoundPlayer : UdonSharpBehaviour
{
    public AudioSource startSound;

    // SendCustomNetworkEventによって全プレイヤーでこのメソッドが呼び出される
    public void PlayStartSound()
    {
        startSound.Play();
    }
}

GameMasterButton.cs (ゲームマスターが押すボタン)

using UdonSharp;
using UnityEngine;
using VRC.Udon.Common.Interfaces;

public class GameMasterButton : UdonSharpBehaviour
{
    // InspectorでSoundPlayerのUdon Behaviourを割り当てる
    public UdonSharpBehaviour soundPlayerUdonBehaviour;

    public override void Interact()
    {
        // 全プレイヤーに対して"PlayStartSound"イベントを送信
        soundPlayerUdonBehaviour.SendCustomNetworkEvent(NetworkEventTarget.All, "PlayStartSound");
    }
}

重要: SendCustomNetworkEventは、あくまで「処理のきっかけ」を全員に送るだけです。オブジェクトの状態(ドアが開いているか、など)を同期させたい場合は、前回の記事で学んだ[UdonSynced]変数とシリアライゼーションを使用する必要があります。

4. 遅延イベント: SendCustomEventDelayedSeconds

一定時間後にイベントを実行したい場合は、SendCustomEventDelayedSecondsを使用します。これは、UdonSharpがコルーチンをサポートしていないため、タイマー処理を実装する際に非常に重要なメソッドです。

// 3秒後に"PlayExplosion"メソッドを実行する
SendCustomEventDelayedSeconds("PlayExplosion", 3.0f);

// 5フレーム後に"CheckStatus"メソッドを実行する
SendCustomEventDelayedFrames("CheckStatus", 5);
  • SendCustomEventDelayedSeconds("イベント名", 秒数): 指定した秒数後にイベントを実行します。
  • SendCustomEventDelayedFrames("イベント名", フレーム数): 指定したフレーム数後にイベントを実行します。

これらはローカルでの実行であり、Update内でフラグをチェックし続ける代わりに使用することで、パフォーマンスを向上させることができます。

イベント送信方法の比較

メソッド実行範囲通信主な用途
直接呼び出し同じスクリプト内ローカル内部処理の整理、コードの再利用
SendCustomEvent指定したオブジェクトローカル同じクライアント内でのスクリプト間連携
SendCustomEventDelayedSeconds自分自身ローカルタイマー処理、遅延実行
SendCustomNetworkEvent全プレイヤーネットワーク全プレイヤーに同じ処理を同時に実行させる

まとめ

  • 処理をメソッドにまとめることで、コードが整理され、再利用しやすくなります。
  • 他のオブジェクトの処理を呼び出すには、SendCustomEvent("イベント名")を使用します。これはローカルで実行されます。
  • 全プレイヤーに同じ処理を実行させるには、SendCustomNetworkEvent(NetworkEventTarget.All, "イベント名")を使用します。これはネットワークを介して実行されます。
  • 一定時間後に処理を実行するには、SendCustomEventDelayedSecondsを使用します。UdonSharpではコルーチンが使えないため、タイマー処理に不可欠です。
  • ローカルのSendCustomEventでは直接引数を渡すことはできないため、値の共有には同期変数など別の仕組みが必要です。

メソッドとカスタムイベントを使いこなすことで、個々のギミックを連携させ、より大規模で体系的なシステムを構築することが可能になります。次の記事では、プレイヤーの参加や退出といった、プレイヤー自身に関するイベントの扱い方について解説します。