【Unity/VRChat】変数の同期方法

Unity

はじめに

この記事では VRChat でスクリプトの中の変数を同期する方法を具体例を交えて解説します。

今回の検証環境はこの画像のようなシンプルなワールドで、テキストを表示できるディスプレイと床のみがあります。
今回は変数の同期を利用して同じワールドにいる全てのプレイヤーがディスプレイで同じテキストを見れるようにしようと思います。

表示するテキストは「自分が入室した時のプレイヤー数」とします。
最初に入室したプレイヤーはディスプレイに「1」と表示されます。
2人目のプレイヤーが入室するとディスプレイのテキストは「2」となり、それが同期されて1人目のプレイヤーも「2」と見えるようになります。

検証

早速試してみましょう!

同期できない場合

まずは同期できない場合の例を見てみます。
以下のスクリプトはディスプレイの GameObject にアタッチしているものです。

処理内容は非常にシンプルで、ローカルプレイヤーがワールドに参加した時にプレイヤー数を取得してそれをテキストに設定しています。

using UdonSharp;
using UnityEngine;
using UnityEngine.UI;
using VRC.SDKBase;

public class DisplayController : UdonSharpBehaviour
{
    [SerializeField]
    private Text txtDisplay;

    void Start()
    {
        int playerCount = VRCPlayerApi.GetPlayerCount();
        txtDisplay.text = playerCount.ToString();
    }
}

この内容で実行してみるとこの画像のようになりました。

1人目のプレイヤーが左のウィンドウで2人目のプレイヤーが右のウィンドウなのですが、変数の同期ができていないので各々がワールドに参加した時のプレイヤー数を表示ししたままになってしまっています。
つまり、ディスプレイに表示されているテキストがプレイヤーによって違うという状態になってしまっています。

同期できる場合

ではどのようなコードにすればディスプレイのテキストを同期して全てのプレイヤーで同じ見え方になるのでしょうか?

コードが少し長くなってしまいましたが、例えば以下のようなコードにすると変数の値を同期して同じテキストをディスプレイに表示できるようになります。

using UdonSharp;
using UnityEngine;
using UnityEngine.UI;
using VRC.SDKBase;

//同期モードを「手動」に設定する
[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class DisplayController : UdonSharpBehaviour
{
    [SerializeField]
    private Text txtDisplay;

    //同期変数として登録する
    [UdonSynced]
    private int playerCount;

    void Start()
    {
        //ディスプレイの所有者が自分ではないなら
        if (!Networking.IsOwner(gameObject))
        {
            //ディスプレイの所有者を自分に設定する
            Networking.SetOwner(Networking.LocalPlayer, gameObject);
        }

        //ワールドに入室した時のプレイヤー数を取得して同期変数に代入する
        playerCount = VRCPlayerApi.GetPlayerCount();

        //同期する
        RequestSerialization();

        //ディスプレイのテキストを更新する
        UpdateDisplayText();
    }

    /// <summary>
    /// 同期変数の値が更新された時に呼び出される
    /// </summary>
    public override void OnDeserialization()
    {
        //ディスプレイのテキストを更新する
        UpdateDisplayText();
    }

    /// <summary>
    /// ディスプレイのテキストを更新する
    /// </summary>
    private void UpdateDisplayText()
    {
        //プレイヤー数をディスプレイのテキストに設定する
        txtDisplay.text = playerCount.ToString();
    }
}

この内容で実行するとこの画像のように1人目のプレイヤーも2人目のプレイヤーも同じテキストが表示されるようになりました。

変数の同期に成功したこのコードのポイントは以下の通りです。

  • 値を同期したいメンバ変数があるクラスではそのクラスの名前の上に「[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]」と記述して同期モードを「手動」に設定します
  • UdonSynced 属性を使って同期したい変数を「同期変数」として登録します
  • 同期変数の値を変更したり、変更後の値を同期できるのはその GameObject(メンバ変数の中に同期変数が含まれているスクリプトがアタッチされている GameObject)の所有者のみなので、自分がその GameObject の所有者かどうかを確認して自分が所有者でなければ Networking.SetOwner() でその GameObject の所有者を自分に設定する必要があります
  • 同期変数の値を変更した後は同期変数の値を利用する処理を実行したり、RequestSerialization() を呼び出したりします
  • 同期変数の値を利用する処理は OnDeserialization() の中でも実行するようにします

最後に

参考記事

お問い合わせ

    タイトルとURLをコピーしました