UdonSharp開発Tips パート1 (2024/2版)

京セラコミュニケーションシステム株式会社 技術開発センター
ICT技術開発部 先端技術開発課の小出です。

前回の [UI/UXデザイン時に気を付けた点まとめ](https://qiita.com/kccs_satoshi-koide/items/c6b8247ef2b7e3b3ae69) に続いて2件目のQiita投稿となります。
今回は、VRChatのワールド制作で使用できるUdonSharpの開発Tipsについて記事を執筆いたします。

なお、一部内容については別途、詳細を記述した「パート2」として公開する予定ですのでお楽しみに！

## はじめに

### VRChatワールド "Kyocera Mobile World" について

https://vrchat.com/home/launch?worldId=wrld_16cda762-4503-4074-ae90-45e8bddaf407

先日VRChatで公開され好評をいただいた[Kyocera Mobile World](https://vrchat.com/home/launch?worldId=wrld_16cda762-4503-4074-ae90-45e8bddaf407)ですが、
京セラコミュニケーションシステム株式会社も開発に協力しております。

### 執筆経緯と目的

今回私は初めてUdonSharpに触れたのですが、Unity-C#開発者として詰まった点が多々ありましたので、いくつかピックアップして共有したいと思います。

なお、UdonSharpおよびVRCSDKは日々更新されておりますので、2024年2月現在の情報としてご認識ください。

### 対象読者

- 多少なりともUnity-C#開発経験がある方
- VRChatを普段から使っており、ワールド制作でUdonSharpを使ってみたい方
- UdonSharpを使ってみたいが、実際に組む前に注意点を確認しておきたい方

### 各種バージョン情報

- Unity 2019.4.31
- VRChat SDK Base/Worlds 3.4.2

## 制約系

### 外部から引数での値の受け渡しができない

スクリプト外部から```SetParam(param)```のような形でメソッドを呼ぶことができません。
※外部から呼び出すためのAPI ```SendCustomEvent(string EventName)``` にメソッド名の指定はあるものの、値の設定がありません。

https://udonsharp.docs.vrchat.com/vrchat-api#udonbehaviour


#### 外部向けメソッドを小分けにする

例えば ```Param01()```, ```Param02()``` のように、あらかじめ対応するメソッドを小分けにして作っておき、そのあとの処理でスクリプト内部にて値を設定することはできます。

```cs
// 内部処理用メソッド
// "_"を付けると、publicでもネットワーク経由(SendCustomNetworkEvent)では呼び出しできないようにできる
public void _SetParam(int number){
    //何らかの処理
    Debug.Log("SetParam: " + number);
}

// 外部呼出し用メソッド
// 注意:外部から引数を指定して値の受け渡しはできない
public void Param01(){
    _SetParam(1);
}

public void Param02(){
    _SetParam(2);
}
```

こうしておけば、インタラクトされた時の最終的な処理などを`_SetParam()`内で共通化できます。
ただ、外部呼出し用メソッドを都度作る必要があるのが難点ですね。


### List\<T\>が使えない・多次元配列が使えない

List非対応の為、foreachか配列(Array)を使うことになります。
また、多次元配列も非対応です。



## 最適化・負荷対策・設計系

### UdonBehaviourはなるべく少なくする
※「パート2」にて詳解予定です。

開発スタイル等にもよりますが、Unity-C#開発ではスクリプトを小分けにして可読性を良く(モジュール化)することがあると思います。

UdonSharpでは、主に負荷の面でモジュール化は推奨されず、なるべくひとつのスクリプトに処理をまとめる方が良いです。

例えば、ゲームで弾丸や弓矢を発射する場合、その発射物自体にスクリプトを付けて、着弾時や指定秒数経過後の処理を行うことがありますが、これらが推奨されません。

ひとつのスクリプトが数千行にわたることで可読性が非常に悪くなり、残念ながらメンテナンス性は低下します。



### UdonBehaviourから作成するUdonSharpファイル名は後から変更できない

一旦仮の名前でスクリプトを作っておき、あとで名称変更したくなる場面もあると思います。
ファイル名などが内部で管理されているようで、ファイル名を変更するとエラーになりますし、`UdonSharpProgramAsset`で紐づけられたUdonSharpファイル名は、エディターUI上で変更ができません。

### 同期方式を決める

#### 事象の同期か、状態の同期か

※こちらも「パート2」として詳解予定です。

エフェクト等のイベント発火時のみスポットで同期させるか、
各個人のスコアなどの値自体を同期させたい場合は、プレイヤー毎にスコアオブジェクトのオーナー権限を取得して、その同期変数を自ら書き換える形が良いでしょう。 

全体やチームのスコアなら、インスタンスオーナーに対して、プレイヤーの操作等を通知し、通知された側で値を処理し、書き換える形になると思います。


## 番外編：忘れがち系

直接UdonSharpと関連があるものではないですが、開発時に知っておくと良いことをいくつか挙げます。

### Canvas(uGUI)にはVRC Ui Shapeコンポーネントを付ける

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576163/d78d68a7-0687-5c51-fd67-11e44125abc7.png)

これを付けないとインタラクトできません。

### Canvasの当たり判定をなくしたいとき

CanvasにあらかじめBoxColliderを付けて、```isTrigger```にチェックを入れます。
※ColliderがついていないとVRC Ui Shapeが自動的にColliderを付けてしまいます。



## まとめ

UdonSharpを用いた開発は、普段のUnity-C#開発とは異なる面で気を付けることが多いため、制約を認識したうえで、最初の段階からうまく設計しないと文字通りの スパゲッティ ~~UDON~~ コードになってしまいます。

とはいえVRCSDK2時代と比べて、できることの幅が格段に増えており可能性を感じています。

この記事がVRChatワールド開発の一助となれば幸いです。

お読みいただき、ありがとうございました！


## 参考サイト

**VRChat公式ドキュメント**

https://udonsharp.docs.vrchat.com/


## 所属部署について


### ITエンジニアが活躍する地方拠点「長崎 Innovation Lab」

https://www.kccs.co.jp/contents/nagasaki-innovation-lab/

長崎 Innovation Labでは、IT技術を活用して、工場などものづくりの現場で活用できるシステムの開発に取り組んでいます。自由な発想でこれまでにない社会に役立つ製品・サービスを生み出し、長崎から発信していくことを目指しています。


### XR技術検証

近未来で活用できる技術開発の一環として、XR関連の技術開発を行っています。
XRとは、AR（拡張現実）、VR（仮想現実）、MR（複合現実）など、現実世界と仮想世界を融合する先端技術の総称です。Microsoft HoloLens 2、Meta Quest 2、Google Glassなどの先進的なデバイスを、どのように実務現場に適用できるかという視点で技術開発・検証を行っています。
京セラグループに所属している私たちは、これらの技術を工場DXにいかに適用できるのかに注力しながら活動しています。