vrc-udon について
vrc-udonは、UdonSharpでVRChatワールドのスクリプトを書くための開発スキルです。ネットワーク、所有権、同期、途中参加プレイヤーの処理を中心に扱います。
主な機能
- 01UdonSharpの構文とパターン
- 02ネットワークと変数同期
- 03所有権移譲の指針
- 04途中参加プレイヤーの状態処理
- 05イベント駆動のスクリプト通信
活用シーン
- 01VRChatワールド向けのUdonスクリプト作成
- 02ネットワーク上のプレイヤー間で状態を同期
- 03同期変数の変更前に所有権を処理
- 04途中参加プレイヤーに正しいワールド状態を表示
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ alexanderstephenthompson/ claude-hub --skill vrc-udonインストール後、Claude Code で/vrc-udonを入力して読み込まれたか確認します。
同梱ファイルreferences/networking.mdassets/udon-checklist.md
詳細
VRChat Udon スキル
Version: 1.0 Stack: VRChat SDK, UdonSharp
Udonは、ネットワーキングを追加するまでは通常のUnityスクリプトのように見えます。しかし、ネットワーキングを追加すると、すべてが変わります。所有権がない状態で同期変数を変更しても、何のエラーも警告もなく、ただ何も起こらずに失敗します。RequestSerializationを忘れると、変更内容が自分のマシンから送信されません。エディターでテストしても、プレイヤーが1人しかいないため、ネットワーキングのバグを検出できません。再シリアライズを明示的に処理しない限り、後から参加したプレイヤーには現在の状態ではなく、デフォルトの状態が表示されます。
このスキルに含まれるすべてのルールは、Udonのデフォルト動作が暗黙のうちに失敗するものであることを踏まえています。
対象範囲と境界
このスキルの対象:
- UdonSharpの構文とパターン
- ネットワーキングと同期
- プレイヤーとのインタラクション
- ワールドイベント
- Udonの一般的な動作
以下は他のスキルを参照してください:
unity-csharp:C#のパターンとパフォーマンス最適化vrc-worlds:ワールドのセットアップと最適化
このスキルを使う場面: VRChatワールド用のUdonスクリプトを作成するとき。
基本原則
- ネットワークの認識 — 同期変数にはそれぞれ帯域幅のコストがかかります。
- オーナーモデル — 同期変数を変更できるのはオーナーだけです。
- 後から参加するプレイヤー — 後から参加するプレイヤーに対しても、状態が正しく保たれる必要があります。
- ローカルとグローバル — ローカルかネットワーク経由かを明確にしてください。
- イベント駆動 — ポーリングではなく、SendCustomEventを使ってください。
パターン
基本的なUdonSharpスクリプト
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
public class MyBehavior : UdonSharpBehaviour
{
[UdonSynced] private bool _isActive;
public override void Interact()
{
// Take ownership before modifying synced var
Networking.SetOwner(Networking.LocalPlayer, gameObject);
_isActive = !_isActive;
RequestSerialization();
}
public override void OnDeserialization()
{
// Called when synced vars update from network
UpdateVisuals();
}
private void UpdateVisuals()
{
// Update based on _isActive state
}
}
所有権の移譲パターン
public void TakeOwnershipAndModify()
{
// Always check and transfer ownership first
if (!Networking.IsOwner(gameObject))
{
Networking.SetOwner(Networking.LocalPlayer, gameObject);
}
// Now safe to modify synced variables
_syncedValue = newValue;
RequestSerialization();
}
後から参加するプレイヤーへの対応
[UdonSynced] private bool _doorOpen;
public override void OnPlayerJoined(VRCPlayerApi player)
{
// If we're owner, re-serialize state for the new player
if (Networking.IsOwner(gameObject))
{
RequestSerialization();
}
}
public override void OnDeserialization()
{
// Late joiners get current state here
SetDoorState(_doorOpen);
}
カスタムイベントによる通信
// Script A - sends event
public UdonBehaviour targetScript;
public void OnButtonPress()
{
targetScript.SendCustomEvent("HandleButtonPress");
}
// Script B - receives event
public void HandleButtonPress()
{
// Handle the event
}
// Network event (all players)
public void TriggerGlobalEvent()
{
SendCustomNetworkEvent(NetworkEventTarget.All, "OnGlobalEvent");
}
public void OnGlobalEvent()
{
// Runs on all players
}
アンチパターン
| アンチパターン | 問題 | 修正方法 |
|---|---|---|
| 所有権なしで同期変数を変更する | 暗黙のうちに失敗する | 先にSetOwnerを呼び出してから変更する |
| RequestSerializationを忘れる | 変更が同期されない | 同期変数を変更した後は必ず呼び出す |
| 同期するデータが多すぎる | ネットワークの遅延 | 同期変数を最小限にする |
| ネットワークの確認にUpdate()を使う | パフォーマンスの無駄 | OnDeserializationやイベントを使う |
| 後から参加するプレイヤーへの処理がない | 参加者に正しくない状態が表示される | プレイヤーの参加時に再シリアライズする |
チェックリスト
- 同期変数を変更する前に所有権を移譲した
- 変更後にRequestSerializationを呼び出した
- OnDeserializationで視覚的な状態をすべて更新する
- 後から参加するプレイヤーに対応した(OnPlayerJoined + serialize)
- グローバルなトリガーにネットワークイベントを使った
- 同期変数の数を最小限にした
参考資料
references/networking.md— Udonのネットワーキング、同期、所有権のパターン
アセット
assets/udon-checklist.md— Udonスクリプト開発のチェックリスト
コメント
Markdown 対応