【VRChat】ワールドギミック作成TIPS【U#】
ギミック作成時のTIPSや不具合対策が溜まってきたのでまとめます。 VRChatの開発環境は絶えず更新されていくため情報が古くなっている可能性があることはご留意ください。 (ご指摘のコメントお待ちしています)
UdonSharp (U#)
Class Exposure Tree
U#で使用できるビルドインのC#クラスを確認できます。 ビルトインメソッドはU#よりも遥かに高速なのでパフォーマンスが向上します。
使用できるクラスは緑色、使用できないクラスは赤色で示されます。 ]
公式ドキュメント Class Exposure Tree | UdonSharp
不具合対策:同期変数の初期化待ち
2022年末頃からジョイン時の同期変数の初期同期が完了するまでstart()から10秒程掛かるようになっています。 その前に同期変数を操作するとギミックが壊れる可能性があるため、ギミックは同期待ち処理が必要です。
① 単純に10秒後に同期変数操作を呼ぶ場合:
//Start void Start() { //------------------your process------------------ //------------------start wait sync------------------ SendCustomEventDelayedSeconds(nameof(ChangeSyncValue), 10.0f); //value is sync after 10sec. You can change sync value. }
② 定期的に同期完了をチェックする(初期操作に時間が掛かる場合):
//stopwatch for waiting sync value private System.Diagnostics.Stopwatch syncWaitSw = new System.Diagnostics.Stopwatch(); private const int WAIT_SYNC_VALUES_MSEC = 10000; //10sec wait //Start void Start() { //wait sync stopwatch start syncWaitSw.Restart(); //------------------your process------------------ //------------------start wait sync------------------ SendCustomEventDelayedSeconds(nameof(WaitSyncValuesAndUnlock), 0.2f); } /// <summary> /// wait to sync /// </summary> public void WaitSyncValuesAndUnlock() { if (syncWaitSw.ElapsedMilliseconds >= WAIT_SYNC_VALUES_MSEC) { //value is synced. You can change sync value. syncWaitSw.Stop(); ChangeSyncValue(); } else { SendCustomEventDelayedSeconds(nameof(WaitSyncValuesAndUnlock), 0.2f); //yet sync. call self } }
同期変数テンプレート
定型化した私の書き方です。
① 通常:
[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)] public class SyncTest : UdonSharpBehaviour { [UdonSynced, FieldChangeCallback(nameof(SyncValue))] private int _syncValue; public int SyncValue { get => _syncValue; set { _syncValue = value; ApplySyncValue(); Debug.Log("SyncValue is:" + _syncValue); } } private void ApplySyncValue() //"Apply" + property name { //process when sync value is changed. for all user. } public void SetSyncValue(int value) //"Set" + property name { TakeOwner(); SyncValue = value; RequestSerialization(); } /*----------------------------util--------------------------------------------*/ private void TakeOwner() { if (!Networking.IsOwner(Networking.LocalPlayer, this.gameObject)) Networking.SetOwner(Networking.LocalPlayer, this.gameObject); } }
② 同値反映: 同期変数を設定するとき前回と同じ値でも全員に反映処理をさせたいときが稀にあります。 その場合はSetSyncValueとApplySyncValueを以下のように書き換えます。
public void ApplySyncValue() //"Apply" + property name { //process when sync value is changed. for all user. } public void SetSyncValue(int value) //"Set" + property name { if (_syncValue != value) { TakeOwner(); SyncValue = value; RequestSerialization(); } else { SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.All,nameof(ApplySyncValue)); } }
ワールド全般
Whitelisted World Components
ワールドで利用できるコンポーネントのリストです。 docs.vrchat.com
記載されているが使えないコンポーネント:
- PuppetMaster (2021年からVRChat上で動かない。Canny)
記載されていないが使えるコンポーネント:
- Cinemachine系(CinemachineVirtualCameraなど。タイムラインで使用)
uGUI
Textの文字崩れ問題
動画の通りTextが突然崩れました。(音声無し) youtu.be
状況をまとめると以下の通りです。
・動的に文字列を変更する(した)Textが一度に壊れる。 ・半角・全角は関係ない ・発生の要因になる再現性のある操作は見つからなかったが、3分操作した3割程度の人に発生した。 ・動画後半のように文字化けが復旧することもあるが条件は不明。
対策:TextMeshProを使う 「Textの代わりにTextMeshProを利用する」ことで文字崩れは発生しなくなりました。
ただTextMeshProは標準では日本語に対応しておらず、日本語フォントを含めると15MB以上ワールド容量が増加するというデメリットがあります。ただこれはフォールバックフォントを利用して回避できます。 簡単にいうとワールドのアップロード時に空のフォントを設定しておくとVRChatのアプリ(クライアント)自身が持っている日本語フォントを使ってくれるという仕組みです。
2023/06/11現在のフォールバックフォントの見た目は以下の画像のようになります。 (文字は全てフォールバックフォント)
フォールバックフォントの設定方法(VRChat) まず以下の空っぽのフォント(匿名提供)をダウンロードして全てのTextMeshProに設定します。
以上でVRChat上でフォールバックフォントが適用されます。
フォールバックフォントの設定方法(Unity) ただこのままだとUnity上(ClientSim)で文字化けしてしまうのでUnity上でのフォールバックフォントを別途設定します。 この例ではNotoSansJPフォントを作成して設定しています。(TextMeshProの日本語フォント作成方法は多くの他記事があるので各自調べてください)
以上Textの文字化け対策でした。 (フォールバックフォントについてはHaï~さんのツィートを元にさせて頂きました。https://twitter.com/vr_hai/status/1464343863708065794)
その他
処理した地雷(?)達をtwitterから引用します。Editor拡張で解決して配布することも多いです。
デスクトップモードのugui視点対応
Button(Unity uGUI)などのUI部品に対して、VRChatのデスクトップモードの視点ポインタが重なったときに色が変わるようにHighlight設定をしたかったのですが解決が大変だったのでメモを残します。
— ヌルヲ (@nuruo789) 2022年6月1日
まず、普通にUIのHighlightカラーの設定はEditor上では動作しますがVRChat上では機能しませんでした。
TextMeshProがフォールバックフォントになる
DeactiveなTextMeshProコンポーネントをActiveにすると解決します。 (配布ギミックを受け取った時など一度もActiveにされない場合に問題になる)
Unityシーンにある全てのオブジェクトのActiveを一瞬トグルして元に戻す虚無のエディタ拡張を作りました。インポートしたTextMeshProコンポーネントのフォントが正しく設定されないバグに役に立ちます。https://t.co/Nc78M1fm1x pic.twitter.com/byJ1Sco4qK
— ヌルヲ (@nuruo789) 2022年12月31日
TextMeshProで日本語対応するときに使う文字だけ抜き出す
ワールド容量削減策です。
Editorコード書いた。TextMeshProの文字列をシーンから全部吸い出してクリップボードにコピーする。
— ヌルヲ (@nuruo789) 2022年7月25日
使用用途はFontAssetCreaterでCustom Charactersとして指定する。結果的にフォントアセットのサイズが削減できる。(自分の環境では10%まで小さくなった)
(続) pic.twitter.com/UkKRjXT6fZ
大量の名前重複オブジェクトがある場合の名前修正
オブジェクトの重複名を解決するエディタ拡張です。開いているシーンの全てのオブジェクトが対象です。Unityに置くとエディタタブ、Tools/Nuruwo/FixDuplicateNameが出現します。
— ヌルヲ (@nuruo789) 2022年9月10日
購入したアセットに重複名が1000個以上有ったため作成しました。https://t.co/Ilv2UYhgmT pic.twitter.com/z2Lkb5r0LR
大量のボタンイベントに対応するためのU#コード生成
SendCustomEventに引数が渡せない痛みを和らげるやつです。タグモードではコンポーネント側の処理も生成します。
U#で大量のボタンなどのプッシュイベントを処理する必要があるときに役立つエディタ拡張を配布します。
— ヌルヲ (@nuruo789) 2022年10月20日
画像の通り、UIの数を指定して各々に対応したpublicメソッド (ButtonのOnClickに指定) を生成して、一つのprivateメソッドにまとめるコードを出力します。https://t.co/OsXDuf4qvf pic.twitter.com/K01PBCD2nG
png画像の縦横サイズを4の倍数にする。
クランチ圧縮の仕様に収めるためのものです。
Unityのクランチ圧縮のため、pngを指定色でパディングして4の倍数のサイズにするアプリを配布します。
— ヌルヲ (@nuruo789) 2023年3月4日
ルートフォルダを指定、パディングが必要なpngを検出します。画像を寄せる方向も指定可能です。
良かったら使ってみてください。僕のワールドは10MBくらい軽くなりました。https://t.co/c73QvWd9Q4 pic.twitter.com/Lx70lyEfnK
まとめ
- 色々やると色々問題も出てくるけど解決できると気持ちいいね。
- 拡張エディタを書いてる間だけはU#から自由になるよ!
- 頼むー!PuppetMaster使えるようにしてくれー!
それではワールド製作やっていきましょう!
更新履歴
順次内容を書き足していく予定です。
2023/03/24 初稿。