UDONの同期を試した
ランダムにスタート位置とゴール位置を決めて速度を与え、ゴール位置にたどり着くと再度スタートとゴールを決めて速度を与えるのを繰り返すという仕様のオブジェクトをUDONで同期した。同期する変数はスタート位置のベクターとゴール位置のベクターの二つの要素をもつ配列、現在位置情報のベクター。
概略
start()(オーナー)→OnPlayerJoined()(オーナー)→RequestSerialization()(オーナー)→OnDeserialization()(非オーナー)→RequestSerialization()(オーナー)→OnDeserialization()(非オーナー)のループ。
詳細
オブジェクトのオーナーがまずオブジェクトのインスタンス化後に呼ばれる関数?Start()内で、スタート位置とゴール位置を決め、同期用のベクター配列にコピーと、オブジェクトの位置、速度を設定する。プレイヤーがジョインしたときに呼ばれる関数OnPlayerJoined()内でオーナーが現時点のオブジェクトの位置情報を同期用の変数にコピーし、同期を発火する関数RequestSerialization()を実行する。次に、RequestSerialization()が呼ばれたときや、その他同期が発火されたときに呼ばれる関数OnDeserialization()内で非オーナーが同期されたスタートゴールの情報で速度と位置を設定し、現在の位置情報をそれに上書きする。ゴールにたどり着くと、オーナー、非オーナー両方で次のスタートとゴールを決める、速度と位置を設定し、RequestSerializetion()を実行する。OnDeserialization()内で非オーナーが同期されたスタートとゴールの情報で速度と位置を上書きする。以下ループ。
実装された運用
using System;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
using UdonSharp;
using UnityEngine;
using UnityEngine.UIElements;
using VRC.SDKBase;
using VRC.Udon;
[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class Cube : UdonSharpBehaviour
{
public float speed = 0.278f;//20km/hをスケール調整で1/20にした速度のm/s
public float minxNegative = -400;
public float maxxNegative = -300;
public float minxPositive = 300;
public float maxxPositive = 400;
public float minz = 200;
public float maxz = 400;
[UdonSynced(UdonSyncMode.None)] public bool xMinusStartFlag = true;
[UdonSynced(UdonSyncMode.None)] private Vector3[] startAndEndPositions;
[UdonSynced(UdonSyncMode.None)] private Vector3 positionTemp;
/*
xNegativeとzで囲まれた領域と、
xPositiveとzで囲まれた領域から2点取得し、どちらかがスタートでどちらかがエンドとする。
xNegativeでスタートした時は、xPositiveを超えたとき、
xPositiveでスタートした時は、xNegativeを下回った時にエンドとなる。
startSideFlagがtrueのときnegativeスタート
*/
void Start()
{
startAndEndPositions = getStartAndEndPositions();
setTurn();
}
public override void OnPlayerJoined(VRCPlayerApi player)
{
if (Networking.GetOwner(this.gameObject) == Networking.LocalPlayer)
{
positionTemp = transform.position;
RequestSerialization();
}
}
public override void OnDeserialization()
{
if (Networking.GetOwner(this.gameObject) != Networking.LocalPlayer)
{
setTurn();
transform.position = positionTemp;
}
}
private void Update()
{
//xMinusスタートならエンドxより大きくなった時に次ターンに移行
if (startAndEndPositions[0].x < 0)
{
if (startAndEndPositions[1].x < transform.position.x)
{
startAndEndPositions = getStartAndEndPositions();
setTurn();
RequestSerialization();
}
}
else
{
if (startAndEndPositions[1].x > transform.position.x)
{
startAndEndPositions = getStartAndEndPositions();
setTurn();
RequestSerialization();
}
}
}
private void setTurn(){
transform.position = startAndEndPositions[0];
Vector3 direction = (startAndEndPositions[1] - startAndEndPositions[0]).normalized;
Vector3 velocity = direction * speed;
transform.GetComponent<Rigidbody>().velocity = velocity;
transform.forward = direction;
}
private Vector3[] getStartAndEndPositions()
{
float xNegative = UnityEngine.Random.Range(minxNegative, maxxNegative);
float xPositive = UnityEngine.Random.Range(minxPositive, maxxPositive);
float z1 = UnityEngine.Random.Range(minz, maxz);
float z2 = UnityEngine.Random.Range(minz, maxz);
if(xMinusStartFlag){
Vector3 startPosition = new Vector3(xNegative, 0, z1);
Vector3 endPosition = new Vector3(xPositive, 0, z2);
xMinusStartFlag = false;
return new Vector3[2] { startPosition, endPosition };
}
else
{
Vector3 startPosition = new Vector3(xPositive, 0, z1);
Vector3 endPosition = new Vector3(xNegative, 0, z2);
xMinusStartFlag = true;
return new Vector3[2] { startPosition, endPosition };
}
}
}