【VRChat】初めてUdonをこね始めてからboothにUdonギミックを販売するまで
Udonを触り始めて、乗り物ギミックを作って売るまでの記録です。
↓こんな感じの乗り物ギミックをboothに出品しました。
ツムジボードというどこかで見たことあるような乗り物ギミックです。
初めて作ったUdonギミックですが、既に何人かお手にとって頂けて嬉しい限りです。
ちなみに8/14までセール中です!
ツムジボード単品が750円→450円、フルセット版は1750円→950円!
デモワールドもあります。
開発環境
Udonギミックを作っていた時の環境は以下の通りです。
Unity 2019.4.31f1
VRCSDK3-WORLD-2022.05.25.23.02_Public
UdonSharp_v0.20.3
ProBuilder 4.5.2
Unity上で簡単なモデリングが出来るパッケージCyanEmu.v0.3.10
Unity上でVRChatの動作をエミュレートしてくれるアセット
4月ぐらいに初めてのワールドを作り始めてから現在まで、環境はほとんど変わってません(VRCSDK3のバージョンが変わったぐらい)
最新環境だとVCCやUdonSharp1.0なんかが出ていますが、私はまだ様子見です。
Udonを触る前
ワールド作り始めのころは、既存のペンや動画プレイヤーギミックを設置した普通のワールドを作っていました。
スイッチ類や時計、ペンなど、よく使うギミックはboothで探せばいっぱい見つかります。
なので、最初は自分でUdonを触るつもりはありませんでした。
ところが、広めのワールドを作っている時に、自動車より手頃な移動手段が欲しくなり、坪倉さんのホバーボードのデモを触ってみましたが満足出来ず、今回の乗り物ギミックを作り始めることになります。
Udon事始め
VRChatで「Udon」というと、
パネルを線で繋いでプログラミングしていく(ノードベース)の「VRChat Udon Node Graph」(以下UdonGraph)
本来のUnityでの開発同様、C#でプログラミングしていく「UdonSharp」
のどちらかを指すことが多いです。
私はミニゲームを作る程度にはUnityのC#の知識はありましたが、いきなりUdonSharpに手を出すのは怖かったので、まずはUdonGraphから触りました。
UdonGraphを触ってみる
大抵プログラム系の事始めは、リファレンスや先人の記事を見ますが、私は英語を読んだりググるのが面倒だったので、ケセドさん主催のワールド制作初心者交流会で教えてもらったベイナイトさんの動画で勉強しました。
オブジェクトのオンオフから始まって、銃や拡声器の作り方なども紹介されていて参考になるチャンネルです。
第1弾~第6段をやって大体Udonで出来ることやデバッグ方法が分かったので、本命のUdonSharpに手を出します。
UdonSharpに挑戦
UdonSharpでは、最初にソリさんの動画で勉強していました。
動画のUdonBehaviourが古いので若干見た目が違いますが、基本は同じなので問題なかったです。
ソリさんの動画は以下の3つを最初にやりました。
変数と型 #VRChat_UdonSharpで学ぶプログラミング講座 - YouTube
https://youtu.be/lJwXHc8NpI4
配列とfor文 #VRChat_UdonSharpで学ぶプログラミング講座 - YouTube
https://youtu.be/Q4GALFuDZKQ
コンポーネントを操作せよ! #VRChat_UdonSharpで学ぶプログラミング講座 - YouTube
https://youtu.be/9sIKw-mHv2E
結果、割とUnityゲーム開発と同じようにUdonSharpを書けることが分かってきたので、乗り物ギミックの作成に移りました。
3日ほどUdonをこねこねして、大体それっぽいものが出来ました。
RigidbodyなどUnityのコンポーネントはほとんどUnityと同じように扱えたので比較的ラクに作れました。ただC#周りの機能はUdonで出来ないことが多かったです。
ひとまず、UdonSharp公式のこちらのページを頭に入れておけば大体OKでした。
初Udonで詰まったところ
同期
Udonというかネットワークプログラミングの領域ですが、何も考えずに作ると「自分の環境だと動いているのに他人の環境だと止まっている」みたいなことが頻発しました。後からJoinした人だけ動きが違うとかもよくあります(LateJoiner問題)
同期周りの動作確認は、Build&Testで複数VRChatを立ち上げて一人n役になって確認します。
この時、他人の状態を見る時は「VRC観戦モード」アセットで他人の視点を見れるようにすると便利でした。
今回私が作った乗り物ギミックはVRChat標準のVRC_ObjectSyncコンポーネントを使えばほぼ解決しました。このコンポーネントは自動でオブジェクトの位置や回転を同期してくれるコンポーネントです。
ただ、同期元(Owner)になるのは基本インスタンスに最初に入った人になるので、乗車時にSetOwnerで乗った人にOwnerを移譲してあげる必要があります。
また、VRC_ObjectSyncで同期されない機能(チャージエフェクトのオンオフ)などは、関係する変数に[UdonSync]を付けて、Update関数で再現するようにすればOKでした。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[NonSerialized]
[UdonSynced]
public bool isCharging;
[NonSerialized]
[UdonSynced( UdonSyncMode.Linear )]
public float _chargePower = 0f;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Update()
{
// 共通処理
bool is_local = _ridePlayer == Networking.LocalPlayer;
// 走行音更新
soundEngine.pitch = Mathf.Lerp( minPitchEngineSound, maxPitchEngineSound, ( _currentSpeed * 3.6f ) / maxSpeedPitchEngineSound );
// チャージ音更新
soundCharging.pitch = Mathf.Lerp( minPitchChargingSound, maxPitchChargingSound, _chargePower / maxChargePower );
if( isCharging )
{
if( !soundCharging.isPlaying )
{
StartCharge();
}
}
else
{
if( soundCharging.isPlaying )
{
EndCharge();
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 以後ローカル処理
if( !is_local )
{
return;
}
// 地形情報更新したり
// 操作情報更新したり
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
対戦シューティングとか他人と相互にやり取りが発生するタイプのギミックを作るとまた話は変わってきそうなので、また何かあったら記事を書くかもしれません。
uGUI、AddListenerがつかえない
ButtonやSliderのonClickやonValueChangedプロパティなどが使えないようです。
なのでインスペクタービューからuGUIのコンポーネントに手動でUdonSharpのカスタムイベントを設定する必要があります。しかもカスタムイベントしか受け付けないので、引数が受け取れません。
そこで、コンポーネントの参照を握っておいて、カスタムイベントが呼ばれたら、都度コンポーネントの値を見に行くスタイルにしました。
public void OnChangeFloatingPower()
{
targetMachine.floatingPower = sliderFloatingPower.value;
textFloatingPower.text = sliderFloatingPower.value.ToString( "F" );
}
私は、スクリプト上でイベント登録するスタイルでゲーム制作していたので最初戸惑いました。
乗り物関連で詰まったところ
VRCStationに乗っているとOnPlayerTriggerEnterが呼ばれない
乗り物に座る時はVRChat標準のVRCStationを使うのが一般的ですが、この座っている時の状態がかなり特殊で、当たり判定周りが思ったように動きませんでした。
ゲートを通過したらタイム計測するようなタイムアタックギミックを作るときに最初は公式推奨の「OnPlayerTriggerEnter」を使ったんですが、VRCStationに座っているとこれが呼ばれませんでした。
試行錯誤したら、乗り物に対して「OnTriggerEnter」は呼ばれることがわかりました。
なので、苦肉の策でレイヤーとオブジェクトのオーナーで判定してゴリ押しました…。
コードはこんな感じ。
void OnTriggerEnter( Collider other )
{
if( other.gameObject.layer != 25 ) // LayerMack.NameToLayerは使えない
{
return;
}
if( Networking.GetOwner( other.gameObject ) != Networking.LocalPlayer )
{
return;
}
Debug.Log( "チェックポイント通過" );
timeKeeper.PassCheckPoint( this );
}
デモワールドで遊んでいるとわかりますが、ゲート直前でボードから降りてボードだけゲートをくぐってもタイム計測が始まったりしてしまいます(搭乗しているかは見ていない)
これに関してはもっと良い解決法があったら誰か教えていただけると嬉しいです…。
椅子調整のGUIを付けたら乗り心地が悪くなった
どういうことかと言うと、VRで触れるuGUIにはCanvasにVRC_UiShapeというコンポーネントが必要なんですが、コイツは勝手にBoxColliderを生成します。
それで生成されたBoxColliderと乗り物本来のコライダーがぶつかって、動きが変わってしまう現象が起きました。
私の場合はuGUIのレイヤーをDefaultからPickupにすることで解決しました。
レイヤーの構成によっては、uGUIのボタンなどは使わずUseできるキューブをボタンとして使うなど工夫が必要かもしれません。
(実際、乗り物系のギミックでuGUI使っているものが少ないのは、コレが関係していそう…)
Booth出品について
紹介動画や商品説明画像作るのが大変だった
boothに並べるからには「ちゃんと見栄えを」と意気込んだんですが、いざやってみるとすごい時間かかりました…。
Blenderでボードのモデル作ったり…
エフェクト作り直したり…
紹介動画作るために色々録画したり…
商品説明用にも写真撮ったり…
そもそもアイデアが出ずに数日悩んだり…
ホントに何も思いつかなかったので、他のboothの商品を参考に少しずつ作っていきました。
誰かに依頼した方が良かったかもしれない…。
使っているものが再頒布可能なライセンスか
当初使っていた効果音とフォントに再頒布出来ないものが含まれていたので公開する際に差し替えました。
ワールドで使ったシーンやプロジェクトをそのまま配布は、利用規約に引っかかる恐れがあるので気をつけましょう。
マニュアル作成も大変だった
公開にあたって、マシンパラメータに日本語説明を入れたり、Googleドキュメントでマニュアル書いたりしました。
最初、IwaSyncみたいにバナーをインスペクタービューに出したかったんですが、IwaSyncはゴリゴリにUnityのエディタ拡張をしていたので断念しました…。
ただ、MonoBehaviourでパラメータを設定して、エディタ拡張でUdonBehaviourに適用する方式は、手間やミスを減らせるので、いつかはやりたい事柄です。
おわりに
Udonギミックの動作確認は、VRChatの性質上、最終的には多人数で行う必要があります。なので、イベント終わりとかにフレンドに声をかけたりしてワールドのデバッグを手伝ってもらったりしました。
開発初期は「Qvペンで書いた線に機体が当たる」バグが出て、逆に好きなコースを作れて楽しいんじゃないかと盛りあがったりしたのはいい思い出です。
協力頂いたフレンドの皆さんにはこの場を借りてお礼申し上げます。ありがとうございました!そしてまたワールド更新した時はよろしくお願いします!
ツムジボードこれからについて
さて、今後はもうちょっと対戦出来る感じのツムジボードレースワールドを作ろうかと思っています。
最終的にシティ◯ライアルを作るのが目標なんですが、対戦ゲーム制作の知見が無いので、前段階としてカウントダウンや順位が見れるようなレースワールドを作る予定です。
おそらく同期周りで沼りそうですが、その時のポイントをまた記事に出来たらいいなと思います。
また、レースワールド公開時に作るであろうカウントダウンや順位ギミックはboothのツムジボードフルセット版に同梱予定です。
8/14までセール中なので、興味のある方は今のうちにお買い求めください!!!
宣伝もしたところで、今回の記事は以上になります。
最後までお読み頂きありがとうございました。