Udonのメモ
自分用メモを公開、引っかかったところでドキュメントにまとまってないものを書く
Event
全体で実行されるかどうかの扱いに違いがある? -> ある
対象のEventが発生したらログに出力するようにして、ひとりのプレイヤーが発生させたとき他のプレイヤーでもログが出力されるかどうかで試した。
結果は以下
Event | 結果 |
---|---|
OnPlayerJoined | 全プレイヤーで実行 |
Interact | インタラクトしたプレイヤーだけ |
InputJump | アクションを実行したプレイヤーだけ |
OnPickup | アクションを実行したプレイヤーだけ |
OnDrop | 実行プレイヤーだけ |
OnPlayerRespawn | 実行プレイヤーだけ |
OnPlayerLeft | 全プレイヤー |
OnPickupUseUp | 実行プレイヤーだけ |
OnPickupUseDown | 実行プレイヤーだけ |
OnPlayerTriggerEnter | 全プレイヤー |
全部は検証してないけど引数でVRCPlayerApiを取るものは全てのプレイヤーで実行されるっぽい。
同期するかどうかやローカルで実行すべきかどうかに影響がある。
OnPlayerTriggerEnterの中でVRCPlayerApi.Immobilizeを呼ぶとエラー起こすのに引っかかった。
オブジェクトのレイヤー
厳密にはUdonじゃない。
VRCPickUpのコンポーネントを付けるとオブジェクトのレイヤーが変わってOnPlayerTrigger*系に反応しなくなる。
同期関連
VRChatワールドの同期処理まとめ
ここの項目見るより上のリンク先の方が正しくて分かりやすい、上のEventの項目で書いたローカル実行のみかどうかも参考にするとだいぶやりやすいと思う。
上記の内容も踏まえつつ修正した。
実行されている環境の判定
Eventにて書いたとおりOnPlayerJoined
はjoinしてきたプレイヤーだけでなく全体で実行される。
joinしてきたプレイヤーにだけ特定の処理(例えばjoin時点でのワールドの状態の同期)をしたい場合は、
// Networking.LocalPlayer.playerIdは現在このコードを実行しているプレイヤー
// playerはjoinしてきたプレイヤー
if (Networking.LocalPlayer.playerId == player.playerId) DoSomething();
などで、現在そのコードが実行されている環境を判定する必要がある。
全プレイヤーの環境で処理を実行
SendCustomNetworkEventを使えば、全プレイヤーの環境上でメソッドを実行できる。
例えばOpenというメソッドを全プレイヤーに実行させたいのなら以下のようになる。
SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.All, nameof(Open));
メソッドに引数を渡して実行することはできない。
また、後からjoinしたプレイヤーに現在の状態が同期されたりはしない。
例えば、ドアを開ける処理をしたあとにjoinすると、その人は開ける処理を実行しないので閉まったままに見えるみたいなことが起こる。
当然だけど全てのユーザーにはローカルの自分自身も含むので、Openを実行してからSendCustomNetworkEventで全プレイヤーでOpenを呼ぶと自分だけ二重に実行されるので注意。
変数同期
変数を同期したいときは[UdonSynced]
を付ければいい。
[UdonSynced] private bool _isExecuted = false;
こうすると変更は自動的に全ての環境で同期される、ただし同期のタイミングが微妙っぽい?
普通のワールドでスイッチを押したらドアが開くとかそのぐらいなら問題なかった。
変数が同期されたときに実行したいならOnDeserializationが使える?
まだ使ったことがないので調べる:TODO
-> FieldChangeCallbackを使った方がいい
同期モード
Sync ModeをManualにしてRequestSerializationを使うとすぐに[UdonSynced]
を指定した変数の値を同期できる。
Transformが変化しないと同期されないみたいな話もあるのでなぜか値が同期されないときなどに指定してみるといいかもしれない。Sync MethodがManualじゃなくても動作する?
Sync MethodがManualだとObject Syncが付けられないため、位置を同期する場合は必然的にContinuousを使わないといけない。
それか自前で位置同期を実装する必要がある。
VRCPlayerApi
VRCPlayerApi.Immobilizeをインスタンス化されたオブジェクトが示すプレイヤー以外で実行するとエラーが起きる?
一部の処理はVRCPlayerApiが示すプレイヤーの環境で実行しないとエラーを起こすらしい。
例えばBさんの実行環境で、Aさんの情報を持つVRCPlayerAPi A
に対しA.Immobilize()
を実行すると、Bさんの実行環境だけ例外を出す。
当然といえば当然だけど、Udonだと例外の確認がしにくくて気付きにくかった。
Bの環境だとAがnullになっているわけでもなく、その点についてのドキュメントも特にみつからなかった。
Unityだと普通の実装なのだろうか?
VRCPlayerApi
のメソッドについても要調査:TODO
Playerの判定
VRCApiPlayer.playerIdで比較すべき。
インスタンス同士の比較だと正しく判定できないこともあるらしいのと、処理が重い。
IDの比較なら処理が軽いし正しく判定できないことはまずない。
Udonがアタッチされたコンポーネントの取得
this.gameObjectでアクセスできる。
特定のコンポーネントが欲しいときは
Animator anim = (Animator)this.gameObject.GetComponent(typeof(Animator));
のようにすることでコンポーネントに対応したクラス名で取得ができる。
子のコンポーネントをサーチしたり取得することもできる、この辺のメソッドとかクラスの情報はUnityの公式ドキュメントから得られる。
オブジェクトの移動など
基本的にアニメーションを作ってAnimation Contorollerでパラメータを変えた方がいい?
なんでかというとUdonで工夫なく動かすと一瞬で移動したり回転するので動いてる感がない、アニメーションを編集する方がコンパイルとか要らないなどの理由から。