4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Udon# 自分用のメモの公開

Last updated at Posted at 2022-06-18

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で工夫なく動かすと一瞬で移動したり回転するので動いてる感がない、アニメーションを編集する方がコンパイルとか要らないなどの理由から。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?