N高でVR学園空間を運営する前にVRChat UdonでQuest対応のキーボードを作ってみた

# はじめに

N高等学校 Advent Calendar もついに5回目になりました。N高等学校の副校長の吉村総一郎 (@sifue)です。この記事は[N高等学校 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/n-highschool)の1日目の記事となります。

自分は[N高 Advent Calendar 2016](https://qiita.com/advent-calendar/2016/n-highschool)から4年にわたり[N高](https://nnn.ed.jp/about/)のプログラミング教育を担当してきましたが、現在はプログラミング教育の責任者を @ohataken に任せ、学園全体のITに関わることや副校長として学園全体に関わる業務を行っています。また来年からはS高の校長に就任予定です。N高も生徒数が1万6000人となり、現在では高校生のプログラマコミュニティとしても日本一の規模であると考えています。

この記事では、2021年度から実施されるVRをつかった学びの[普通科プレミアム](https://nnn.ed.jp/learning/premium/)の取り組みについて説明し、この度作った VRChat Udon 製の Questでも利用できるキーボードについて紹介したいと思います。

# VRを使った学び、普通科プレミアムについて

今まではN高といえば、PC・スマホ・タブレットで授業とレポートとスクーリングをこなして単位取得し高校卒業資格を得るというものでしたが、この[普通科プレミアム](https://nnn.ed.jp/learning/premium/)に学び方を切り替えることで、[授業の部分をVRデバイスで受ける](https://www.youtube.com/watch?v=0H5mb1KEDBw)ことができます。
![2020100719360945.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382/5b680c48-231f-9972-feb0-9c80c652498a.jpeg)
普通科プレミアムの生徒には、VRでの授業コンテンツを利用するために[Oculus Quest2](https://www.oculus.com/quest-2/)を配布します。また、学費に関しても就学支援金の補助により年収590万円程度以下の方は、実質負担額がほとんど変わりません。そのため、**全生徒1万6000人の半分近い生徒たちが、Oculus Quest2を利用した新しい高校生活を送るものと想定**しています。

VR を利用した授業は、Oculus Quest2 版の[バーチャルキャスト](https://virtualcast.jp/)と[N予備校](https://www.nnn.ed.nico/)を利用して行われるわけなのですが、それ以外の要素については現在模索中です。この12月から1月にかけて実施される Oculus Quest2 の生徒への体験会などを通じて、最終的なデザインを固めて行こうと思っています。過去、N高等学校ではネット部活やネット遠足、ネット運動会というものを運営してきたわけですが、今度は新たにVR学園生活というものを作っていくことになります。

なおバーチャルキャストを使った授業内では、カスタムキャストを使って、N高/S高生向けの様々なバリエーションの制服が配布され、 THE SEED ONLINE で利用できる予定です。生徒たちにはVR学園空間にて自分らしさを手軽に表現してもらえればと思います。

![スクリーンショット 2020-11-22 103506.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382/ec16a4d6-76f6-1371-068c-97532a04b57a.jpeg)
![スクリーンショット 2020-11-22 103534.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382/4389d71a-c038-d10c-4f4f-6d9a7f249c57.jpeg)
![スクリーンショット 2020-11-22 102954.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382/725353fe-ff06-10b0-8403-655e3492657e.jpeg)
![スクリーンショット 2020-11-22 103020.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382/fc70f307-5a9e-f9fa-4612-de6d0bcaca06.jpeg)
注、制服は開発中のものであり、リリース時には変更される可能性があります。

# VR学園生活で利用するメタバースについて

既に学内では、コミュニケーションツールとして Slack や Zoom、G Suite for Education があり、ネットを通じた一般的なコミュニケーションは現在はこれらで行われています。

VRはどちらかというと Slack や Zoom を超えた、よりリアルイベントに近いコミュニケーションとして利用できるものではないかと考えており、その中身については現在検討中です。なお現在VRの学園イベントを行うにあたって候補となっているメタバース(すべてが相互につながった仮想世界)としては、

- [バーチャルキャスト](https://virtualcast.jp/)
- [VRChat](https://hello.vrchat.com/)
- [RecRoom](https://recroom.com/)
- [AltspaceVR](https://altvr.com/)
- [Facebook Horizon (未リリース)](https://www.oculus.com/facebook-horizon/?locale=ja_JP)

以上の Oculus Quest2 で動くアプリが有力候補となっています。

ただ問題として、バーチャルキャスト以外は英語のUIとなっており、一般的な日本の中学校卒業生では抵抗感を覚えることが多いことがあります。また VRChat では、アバターが自由に設定できることもあり、特定の生徒/保護者にとって性的に不快感を覚える見た目をしたアバターがあることが課題となっています。
![スクリーンショット 2020-11-22 111859.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382/b0ef0c93-275b-68d4-27e9-e2b01e3210b0.jpeg)
とはいえ、事実上 VRChat が現状VRメタバースの中では日本では最も普及しており、導入候補としては有力なものとなっています。

# VRChat Udon で作る Quest に対応したパスワード入力可能なキーボード

そういうこともあって、今回はアドカレのネタとして **VRChat 上のビジュアルプログラミング言語である Udon を 用いて、Quest でも利用可能なパスワード入力キーボードを作成**しました。
![0.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382/bf010f91-c1dd-7f4a-0dcb-e65f247b4a43.jpeg)
実際に、「[NHIGH UNOFFICIAL 非公式N高生交流所](https://vrchat.com/home/launch?worldId=wrld_5808c522-243a-4813-a2f8-93fac79b100e)」
![スクリーンショット 2020-11-08 040047.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382/bc3d61ba-8c87-f6fa-8465-015f9dc9422c.jpeg)
という以上のワールドを現在コミュニティラボに立ち上げており、N高の Slack 内で共有されているパスワードを入力するとテレポートして入室できる部屋として運用しています。

また完成したQuest対応パスワード入力キーボードは、**[GitHub](https://github.com/sifue/UdonGraphKeyboard) で Prefab として配布中**ですので、もしよければ改造して利用してみてください。ライセンスは MIT License となっています。設定したパスワードを入力して Enter キーを押すと、特定の座標にワープさせるという機能が実装されています。

それでは Udon と実装の説明に移ります。

# Udon とは

まず「Udon」は「うどん」と読みます。Udon は、 VRChat 開発チームによって作られたビジュアルプログラミング言語です。Udon Graph というノードグラフを使って Unity 上でフロー、入力、出力を接続してプログラミングをします。VRChat 上における様々なオブジェクトの動作や性質をプログラミングすることができます。まだアルファ版での公開となっています。

Scratch では必ず上から下に向かってブロックを組み合わせていきますが、Udon では、ノードにフローのワイヤー(Nudles)があるのでそれをつなぎ、更に入力と出力のワイヤーを他のノードとつなぐことによって処理を作成します。

ハローワールドは以下のようになります。

![helloworld.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382/a14a239f-977a-7f2f-76f1-60d825e0641a.jpeg)
![use.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382/97c3ab29-8cc1-3a51-ff28-eb9017cb3c76.jpeg)

実際にこの Udon Graph Program Asset がUdon Beheivior のコンポーネントとして割り当てられた上の Cube に対してここでは Use のアクションを行うと、 `C:\Users\{ユーザー名}\AppData\LocalLow\VRChat\VRChat` のフォルダの `output_log_16-08-33.txt` という形式のテキストファイルに、

```
2020.11.22 10:16:46 Log        -  Hello World!
```

以上のようなログが出力されます。

なお Udon の使い方は、VRChat SDKが定めるUnityのCurrent Version(ここでは `2018.4.20f`)をインストールしてプロジェクトを作り、Worlds SDK3(ここでは `VRCSDK3-WORLD-2020.10.28.15.57_Public.unitypackage` )をImport packageでインポートすれば実行環境が構築できます。

Udon の実行環境は VRChat でワールドを作成するために SDK3 をセットアップすると勝手にその実行環境が付随してきます。また、実際のワールドの作り方などは、「[3歳でも出来るVRChatのワールドの作り方](https://www.youtube.com/watch?v=IxJ_mNxqvzQ)」の動画を見てもらえればと思います。

なおこの Udon を C# で実装できるようにする [Udon Sharp](https://github.com/MerlinVR/UdonSharp) というライブラリがあり、ある程度の規模で Udon の開発を行っている人たちはこれを使っています。しかし C# の全ての文法が使えるわけではなく扱いも難しいため、今回は Udon Graph のみを利用して開発しました。またこの度説明する Udon は、[公式サイト](https://docs.vrchat.com/docs/getting-started-with-udon)で、英語で解説されているものになります。

# Udon Graphのノードの種類
Udon は Unityにおける GameObject に Udon Behavior の Component を付けた後、そこにUdon Graph Program Asset として設定して、利用します。そして Udon Graph Program Asset 自体は、Udon Graph Editor を使って編集していきます。基本的にはすべてマウスと右クリックメニューだけで実装していくことが可能です。

なお World SDK3 の中には、Udon を利用した `UdonExampleScene` というシーンがあるため、基本的にはそのシーンの GameObject に割り当てられた Udon Graph を見ながら実装方法を学んで行きます(公式動画でもそのように勧められています)。また、`UdonProgramSources` フォルダの中には、沢山の実装サンプルがコメント付きで実装されているためそちらを参考にすることもできます。
![スクリーンショット 2020-11-22 174143.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382/895af904-63d9-96f1-be90-7d3807919810.jpeg)

まずはノードの種類を説明していきます。

### [Event ノード](https://docs.vrchat.com/docs/event-nodes)
Interact や OnPickup など、何かしらのイベントが VRChat で実行されたときに、イベントのフローが発火するノードです。基本的にこれが全ての起点になります。非常に多種多様なノードがあるのでドキュメントの[イベント一覧](https://docs.vrchat.com/docs/event-nodes)を見てみるのが良いかなと思います。
![スクリーンショット 2020-11-22 174454.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382/b6fc5632-e42a-6804-2342-aefc1e5a8e02.jpeg)

### [Type ノード](https://docs.vrchat.com/docs/type-nodes)
Unity や VRChat の API における型がノードとして用意されています。インスタンスを渡すとそのメソッドを呼び出すことが可能です。またクラスのインスタンス自体もこの Type ノードで作ることができます。
![スクリーンショット 2020-11-22 174554.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382/db706576-664e-a6ab-5abd-fe3a2780d6a6.jpeg)

### [Group ノードと Comment ノード](https://docs.vrchat.com/docs/graph-elements)
ノードをまとめたグループを作りそこに名前を付けることができます。またコメントを日本語でつけたノードを作ることが可能です。
![スクリーンショット 2020-11-22 175033.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382/4edd1423-f460-6057-69c5-0b4971f382ce.jpeg)


### [Special ノード](https://docs.vrchat.com/docs/special-nodes)
いわゆる制御文や特殊値です。

| ノード名  | 機能 |
|---|---|
| Block | フローを複数にフォークします。Pythonのfork()のような動作をします。|
| Branch | if文による分岐です。 |
| Const Null | null値です。 |
| Const This | GameObject自身の参照です。 |
| EventCustom | 文字列で指定したカスタムイベントになります。なおUdon Sharpではメソッド名の呼び出しになります。 |
| For | 繰り返しを行うfor文です。 |
| Get/SetVariable | コンポーネントにつけた変数を取得できます。型変換ができないので、この変数にインスタンスを入れて特定の型の情報を取ったりします。 |
| While | 繰り返しを行うwhile文です。 |

以上これだけの情報があれば基本的には何でも実装ができます...ですが、思いもよらぬ落とし穴があるので以下にハマりどころと実装として紹介します。 
![スクリーンショット 2020-11-22 175617.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382/1a031130-840e-3e40-a90f-e515e3deeedf.jpeg)

# ハマりどころと実装の紹介
自分自身がこのキーボードを作るにあたってハマったところを紹介します。

### インスタンスのキャストがないため変数を設定して取ってくる必要がある

Get/SetVariable ノードでも説明しましたが、インスタンスのキャストがないので、欲しいインスタンスは Unity のUI上で設定したりして変数から取ってくるのが簡単です。またものによっては、Type ノードのメソッドの型を使ってうまく取得できることがあります。
![スクリーンショット 2020-11-22 180014.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382/e7f55283-efd3-62f0-10e7-e6e2c0ae9568.jpeg)

### Udon Graph は大体30ノードぐらいが限界

正直100ノードを超えてくると重くて編集ができないです...。以下のスクリーンショットのノードを実装してみましたが、Corei7/RTX2070のゲーミングPCでも編集が困難過ぎました。
![スクリーンショット 2020-11-08 230757.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382/a239bd13-e2c7-f3d4-0828-f4a4d0d29683.jpeg)

### GameObject の変数をうまく利用して同じ Udon Graph を使い回すと、ノード数が減らせる

一つの GameObject に大量のノードの実装を置くことが Udon Graph Editor の性能上できないため、変数で分岐するようにして大量の GameObject に同じ抽象化された Udon Graph を利用するよう実装するのがコツかなと思いました。実は全部のキーボードのキーのCubeには、以下の同一の Udon Graph を付けて対応しています。どうしてもこのような工夫が必要となります。
![スクリーンショット 2020-11-22 180308.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382/affff0b4-2905-34c9-b2f5-b93983c25d49.jpeg)

### ある程度の実装をするなら Udon Sharp が必要
この度は Udon Graph で実装しましたが、ちょっと大きな処理を書こうとおもうとかなりコツがいる上に、それでも保守性がすごく悪い状態になります。
Unity の Udon Graph のエディタの制約上保守性の悪いコードを書かざるを得ないため、本当に大規模な処理を書くなら C# で Udon を実装できる [Udon Sharp](https://github.com/MerlinVR/UdonSharp) の利用がオススメです。
ただボタンを押したりエリアに入ることによって駆動するような単純なギミックであれば Udon Graph はとても役に立つのではないかと思います。なお、 Enter キーでパスワードがあっていたらテレポートするという動作ですら以下の図の大きさの Udon Graph となるので参考にされるとよいかもしれません。
![スクリーンショット 2020-11-22 180557.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382/fc080831-5e83-43a8-48ca-bf9a6b6f02d1.jpeg)

# Quest 対応でハマったところ
基本的に Build Settings を Android にしてビルドするだけなのですが、UIInputField が使えないというトラブルがありました。そのため、最終的にこのキーボードは Cube と Text と Mobile 用のシェーダーだけでは実装されています。

# 最後に
以上が Udon Graph を用いて作った Quest 対応のパスワード入力キーボードの実装とハマりどころの紹介でした。VRChat は Udon のプラットフォームができたことで非常に面白いワールドを沢山作れるようになったため、今後の成長も楽しみです。面白そうだと思った方、ぜひチャレンジしてみてくださいね。

長くなりましたが、ここまで読んでくださった方、ありがとうございました。

追伸、N高生が流行らせた[湯婆婆プログラミング](https://qiita.com/Nemesis/items/c7192a7c510788d2cba2)を Udon Graph で実装しようと思ったのですが思ったより UI 作成が大変だったので断念しましたw どなたかよろしくお願いします！