この記事は アドベントカレンダー2023 4 日目の記事です。
作ったものはこちらのゲームワールドです。
スケジュール
2022年10月 発案
12月 後期プロジェクトとして発足
2023年3月末に完成予定だったが、3月中旬のGame^3でゲーム性を見直し、内容を変更。
2023年11月 リリース
大変だったところ
予定通りに進まないスケジュール
2022年12月に後期プロジェクトとして発足し、2023年3月中旬での完成を目指した。
案出しの段階では、自分が出した案に対してdiscordにいた部員と案の検討を行った。そのうち1人はプランナー兼リーダーとしてプロジェクトを複数立ち上げており、興味深い意見や仕様書の制作に関するアドバイスを頂いた。
仕様書にはスケジュールも練り込まれていたが、なんと3月中旬のGame^3までは予定より1週間しか遅延しなかった。プロジェクトは予定よりも数ヶ月遅延するのがフツウと聞いていたので、遅延が少なく素晴らしいと思っていた。
ゲーム性の考え直し
Game^3でのお客さんの評価は悪くなかったが、ゲームを改めて遊んでみるとフィールドがコンセプトを活かしきれていないことに気がついた。壁や床を破壊することがそこまで有利に働かないフィールドとわかってしまった。
ゲームシステムの仕様が違った。一番顕著だったのは「アイテムのハンマーで床or壁を1箇所破壊できる」「階段を使うと、1階層上の床まで登れる」「アイテムが1つしか所有できない」というものだった。
このフィールドでは、壁を壊してもあまり逃げる人が有利にならないし、かといって床を壊すには床の面積が少なすぎる・階段はうさみみの下位互換でしかないという欠点があった。
メンバーからの改善案がいくつか出た。採用するとゲーム性が向上するが、その分だけ実装難度が上がり完成時期が伸びる。リーダーとしてどれを選択するか考えるのがむずかしく、多数決で多くのものを採用してしまった。(部内の経験者によると、ゲーム性を決定する際の多数決はアンチパターンらしい)
仕様書の喪失
ゲーム性を考え直したタイミングで、仕様書がなくなってスケジュールの見通しが立たなくなった。いつ何をやるかの予測はもちろん、これから何のタスクが残っているのか・そのタスクはどれくらい時間がかかりそうかといったこともわからなくなった。
自分の方がキャパオーバーになった分だけ、メンバーが様々な部分をフォローしてくれるようになって非常に助かったのを覚えている。
延期に次ぐ延期
4月は新歓で忙しく開発が進まなかった。
5,6月と開発を行うが完成せず、ついに2023年度の前期プロジェクトの所属が行われる。本プロジェクトに参加してくれた人々は他の活動への意欲も高く、活動時間が他の活動に取られてしまうこととなる。
6月末には終わるだろう、7月末には終わるだろうと漠然と考えていたが、終わらない。夏休みを挟んだが、夏休みに入って「待機場所のUIを考えていなかった」ことに気がついてデザインから行ったので時間がかかってしまった。
「プロジェクトはすぐ終わるからいいだろう」と考えてコードレビューをしなくなったがプロジェクトは終わらず、不自然なコードに対して指摘する機会を失ってしまった。
テストプレイは長いよ
夏休み終了ごろ、すべてのタスクが終わった(つもりだった)。ちょっとテストプレイをして公開しようと思ったが、VRChatのテスター方からのフィードバックを受けて以下を修正することになった。
やったこと(長い, 人名は隠している)
- 待機場所の境目が説明されていない([人名]のshaderを借りて領域展開できないか?)
- HMDの追従が遅くなるのは不要, マップが見にくくなってしまう
- speedは初期設定8 / 6がよさそう
- 2F-3F?の階段間にずれてるアイテムスポーンポイントがある
- 爆弾を真下に投げると安定して遠くまで吹っ飛んでしまう
- 待機場所でしゃがむとネームプレートが見えない(多分、OniTeleportAreaとかの[人名]のshader)
- 人が入ると速度などの設定が初期化される
- ResultUIのプレイヤー名が長いと2行になってしまう。abcdefghij...みたいに途中までしか表示されなくてもいいかも
- BGMがちょっと大きい
- ボイスの減衰が強すぎ?
- gameId=1の人が抜けた。gameId={0,2,3,4,5}なのにisOni[1]=trueとなり、鬼が誰も居ない状態に。MiniMapには抜けたはずのgameId=1の人が表示されている。
- 後から来た人もMasterOnlyの情報が同期されているが、鍵マークの見た目のテキストだけ必ず「Only Master can change」になってる
- バリケードを設置してから自然消滅する前に破壊・再設置すると、最初の設置から20秒で自然消滅する
- STARTが押しやすすぎて誰かがうっかり押しちゃう: RESETボタンと同様にする
- (応急処置: ゲーム終了時にのみ治るようにする)修復爆弾のスポーンポイントが消滅して途中から使えなくなった
- 爆弾の挙動をわかりやすくしたい
- (応急処置: ゲーム終了時にのみ治るようにする)バリケードが途中から、同時に複数人が使えなくなった。トリガーを引いてもアイテムが消費されない。どのバリケードも使えなくなる
- ([人名]が前に「どうしても直せなかった」って言ってたやつ)捕まってもcaughtTimeが設定されなかった人は、Resultであたかも捕まらなかったかのように表示される
- 爆弾を長距離飛ばすと、壁や床をすり抜けて落ちていく
- おにのマーカーがトラッカーの関係で変な位置に存在してしまうことがあり、気になる
- おにのマーカーの色はもっと薄くする。色は逃げる人とかぶる青ではなく橙とかにする
- (Huntersの表記が怪しいが、指摘があってから考える)最初の画面で -3 vs 5と表示されるのは変
- ボードがジャマと感じる, ルール説明やリザルト画面をスタート画面の反対側に配置するとか
- スタート位置/スポーン位置/ルール説明がゲーム開始場所の中にある
- 最後に捕まった人のSurvived Timeがlimit+1、つまり181とかになる
- (そもそもそうならないように見えるが……)アイテム一覧の表示よりオブジェクトが表に表示されるのが気になる
- おにが自身であるとすぐ分かるようにしたい。「あなたはおにです」と表示するとか?
- ついでに日本語/英語切り替えしたいかも(~につかまった・あなたはおにです・おにが来るまであと何秒)
- ゲーム開始時におにになる人が偏っている
- おにを1,2人だけにしてもスタート時点で3,4人がクールタイムになることがあり、おに解放前にすぐおにになって他者を捕まえられる。
- 全員が持っていたアイテムを使えなくなる/取れなくなる(このとき、爆弾が小さいまま放置されて全員が観測できる)/次のゲームでも治らない
- 全員が持っていたアイテムを使えなくなる/ストックが入れ替わらない/次のゲームでも治らない
- バリケード/爆弾がもてても使えない。発生頻度が高いので気になる
- 爆弾を2人で同時に取得すると、両方がアイテムを入手したが、手にのっているのは片方だけ? このとき、片方がアイテムを使うと、もう片方が「次のアイテム」をそこに落として、拾うこともできた。
- アイテムスポーンポイントのアイテムが複数重なる?
- アイテム発動のボタンを書いておいてもいいかも
- HMDのUIのおにテキストよりも、アイテムの描画が後になる
- インベントリの入れ替えがしたい(複数人に指摘されてる) 入れ替え不能ならそう主張する 1こ目のアイテムを大きく表示するのがいいかも
- (cameraのクリッピングを近くする)
- うさみみを手に持ってると変な向きになる
- ボムの射的向きが手ではなく、HMDの向き依存になってる
- いつも同じ人がおにになっていそう
- アイテムがコロコロしてる
- アイテムが重なってそう
- ゲーム開始直後に「〇〇(前のおに?)につかまった!」と表示され、クールタイム無しで予期せずおにになる。その後、Hunterボタンのおにが反映されるが、- おには本来より多くなる
- SteamVRの原点にカプセルが表示されてしまってるのが直っておらず、当たり判定もずれそう。Headでとる?
- スタート裏の細い通路のgymの壁に乗れてしまうので、青い壁の位置を少しずらしてもいい
- RFにもカメラがほしい(メモ: プール, 体育館もできたら?)
- 屋上のRFを封じる障害物が、下からだと見えにくいかも
- バリケードを持ってゲームが修了すると、Abandonされずにその場+枠に残る。次のゲームでは使えない状態で残ってしまい、これを押し出す必要がある
- うさみみの手における見た目が変なので修正する
- ゲーム開始直後に爆弾を取ると使えない
クオリティを上げようとしてもきりがないので上記を終えてリリースしたが、未だに若干バグが残っているのでむずかしい。
その後もUIなどの修正を加えてもらいリリースになった。
自分の能力に対して、仕事が多すぎた
ゲーム案を考えて、その中の仕事をすべて可視化して、リーダーになって人々に仕事を振る。それが、プロジェクトのリーダーの仕事だと思っていた。
自分はプログラムを書きたかったが、プロジェクトとしては自分の作りたいものが作りたい。そのような理由でリーダーとプログラマを兼任しているつもりだったが、プロジェクトが逆境に差し掛かったタイミングでキャパオーバーに陥ってしまった。
開発を進めてメンバーと会話する中で、自分がリーダーだと思っていたものは「プランナー」「リーダー」「マネージャ」と分割できることがわかった。
予想外のタスク
3Dモデルのデザイン
レベルデザインとしてフィールドの形は考えていたつもりだったが、「フィールド/アイテムの3Dモデルの見た目はどういった感じなのか、コミカルな感じなのかフォトリアルな感じなのか」という質問を受けて、何も考えていなかったので困った。
フォトリアルな学校のアセットが販売されており、他の事項も検討した末にフォトリアルを選択した。あたかも学校で遊んでいるような臨場感は得られたが、ゲームとして容量が多く・負荷が高まってしまった。より早くこの問題に気がついていればより良い選択肢を探せたかもしれない。
なお、破壊のためのワールド分割・ライトのベイク・オブジェクトの軽量化はグラフィックの人がやってくれたが、仕事として深掘りして与えていない部分だった。グラフィックの人の仕事量は、自身の想像を凌駕していたのである。
レベルデザイン
リアルな学校の間取りをグラフィックの人にお願いして作ってもらったが、ゲームとして遊ぶにはゲーム性の良さを活かしきれないことがわかった。
次のレベルデザインは自分で考えることにしたが、全くもって思いつかなかった。参考になるワールドの間取りを探してBlender上で軽く再現してみたが、そこで手が止まって行き詰まってしまった。
しかし「なにか凄い間取りにしたい」という理想が残っていて、仕事を抱えたままにしてしまった。それでも何もできず結局、レベルデザインは他の人にお願いすることとなった。
自身にすごいものを作る能力がないと感じたら、妥協してそれなりのものを出すか他者にお願いするのがよいと思った。
マネジメント
仕事を掘り出して人に振ることは難しくないと思っていたが、実際は「雰囲気で振ったつもりになっていたタスクを、実際は本人が認識していない」ということが起きてしまった。
人に振ったタスクの進捗が滞ってそうだが、進捗を聞くと相手のペースを乱してしまいそうと思って黙っていたところ、進捗が遅延してしまったことがあった。
締め切りを曖昧にして人にタスクを振っているのに、実際は自分の心の中で「これくらいにやってくれるだろう」という思い込みがあって、それが過ぎるとモヤモヤするということがあった。
締め切りは厳密に振って、メンションを飛ばして進捗を頻繁にチェックしたり仕事の振り分けを再確認しようと思った。
そもそも自分はマネジメントがあまり得意でないと思っているので、次にプロジェクトを回すならマネージャーを募集してもいいと感じている。
人間的な未熟
予想より難しいタスクを受けて、問題解決の方法がまったくわからず手も動かせぬまま・リフレッシュせずに2週間以上考え続けたことがあり、その結果心身に不調を来たしてしまった。また、プロジェクトのチャンネルではなくてtimesチャンネルで疲れをつぶやいてしまって状況がややこしくなった。
常に働き続けるのが必ずしも良い訳では無い。休憩をこまめに取り、メンタルの安定した状態で仕事を行うのが社会人であると学んだ。
テキストでの会話はむずかしい
プロジェクト完成直前で、時間・労力をかけてもっと完成度を上げるかそのまま出すかで少し揉めた。この頃、プロジェクトの完成が迫っている上に集会の頻度が減っており、揉めた際には対面で対話することで事態が収束した。
テキストでの会話は語調が強くなりがちで、対面orDiscordでの会話の方がより情報を柔軟に伝えやすいとわかった。
モダンでない・部にノウハウのない開発環境
(この章はプログラムを書かない人には読みにくいかもしれない)
U#は、C#の文法で書かれたプログラムをVRChat上で動作するUdon Assemblyに変換するコンパイラである(あまり詳しくない)。当時の開発環境はUnity2019.4.31f+U#1.1。
U#への不満を書いていくが、VRChat運営からは2022年冬にUdon 2.0が開発中であるというアナウンスが入ったので、改善の兆しはあるかも?
U#は動作はするが、言語として未熟なところがある
U#は世界中で広く使われている言語ではなく、単にVRChat上のワールドを制作する際に用いられる言語であり、言語として不安定な部分・C#にあってU#にない機能がある。
interfaceやabstruct classが使えず、アイテム実装の際などに困った。
C#で動作するコードがU#では動作しないとつらい。
[UdonSharp] Assets/scripts/UI/Options/SetOniNumber.cs(61,34): Method is not exposed to Udon: 'String.Join(",",snaps)'
今回はあまり問題にならなかったが、U#は遅いらしい。
Udon can take on the order of 200x to 1000x longer to run a piece of code than the equivalent in normal C# depending on what you're doing.
https://udonsharp.docs.vrchat.com/random-tips-&-performance-pointers
U#を通してワールド制作者がギミックを構築できるのは素晴らしいが、非常にコミュニティの大きい主要言語(C#など)と比べると書き心地が良くない面がある(コミュニティの大きさを考えると仕方がない)。
(開発時点では)Unity2019
prefabの変更を一括してprefabに更新?ができなかったけど、最新のリリースではできるらしい?
記事執筆時点でUnity2022に切り替わりそうになっている。
マスターが全員の変数を管理するとコードが爆発する
(厳密にはマスターではなく、ある変数が含まれたプログラムがアタッチされているオブジェクトのオーナーである)
「各プレイヤーについて、あるプレイヤーがおにかどうか?」という情報(変数)をマスターが持っているとすると、マスター以外はこの情報を書き換えられない。
一方、マスター以外がvoid SendCustomNetworkEvent(NetworkEventTarget target, string eventName)
を発火して、eventNameで指定したメソッドをマスターのみに実行させることはできる。これを用いてメソッド内で変数を書き換えれば解決のようだが、実際はeventNameでメソッド名を指定できても引数が指定できないので、誰がこれを発火させたか・変数を何に設定するかがわからない。
それを避けるため、set_IsOni_To_False_By_0()
set_IsOni_To_True_By_0()
set_IsOni_To_True_By_1()
set_IsOni_To_True_By_2()
みたいな名前のメソッドが大量に生まれてしまうこととなった。
もちろん可読性は高くないが、twitterで他者のコードを読んでも同じような実装が行われているので、可読性を諦めた。
余談
あるとき「誰かが捕まった時間も同様に管理したい」という要望が出た。時間は整数値で管理するとする。このとき、時間tを設定するために「人xの捕まった時間を+1するメソッド」をt回実行するのはプログラムに負荷がかかってしまう。そこで、担当者は「1, 2, 4, 8, 16, 32, ...秒増やすメソッドを作ることでlog2(t)回の実行で済まないか?」ということを考えざるを得なくなった(この言語仕様では仕方がない)。
エラーハンドリングできない
プログラムがエラーを吐いた時点でプログラムが終了するが、try-catchなどが実装されていないため万が一のエラーに対応できない。
特にnull pointer exception(以下、ぬるぽ)が多かった。想定外のタイミングでぬるぽが出て落ちる。数人で遊んでいるときに、新しく人が入った瞬間にぬるぽで全アイテムが停止したこともあった。
開発の難易度がそもそも高いかもしれない
このゲームはVRChatのワールドとして制作されたが、以下のような問題で開発の難易度が高かったと感じている。
- 3D空間上のゲーム。特にグラフィックの人が大変
- プログラマのほとんどが経験の浅い22B=2022年入学者(経験が浅いとは書いたが、そもそもUnity+C#の経験者が部にいてもU#の同期などに詳しい人間は居ない)
- 「Unity上でのゲーム開発」というよりか「VRChatのワールド制作」であるために情報が少ない
- U#というVRChat用のメジャーでない言語
- 多人数での同期(VRChatの基盤に乗っているという面では非常に楽だが、それでもラグによる同期・挙動のずれを細かく修正するのが大変)
開発期間を伸ばしてよかったところ
開発期間が伸びてしまい、当初の計画が狂ってしまった。
一方で、完成してみればゲーム性の見直しはクオリティの向上に大きく貢献している。短い開発期間と高いクオリティはトレードオフの関係にあると感じた。
例としてアイテムを挙げてみる。メンバーでの議論の末にアイテムが変更された。
意識したこと
- 使わないアイテムをつくらない(それぞれに独自の強みを持たせる)
- 「学校を破壊」というコンセプトに合ったものにする
ハンマー(選んだ壁1つを破壊)→破壊爆弾(当たった付近の壁を破壊できる)
ハンマーよりもっと大規模を対象にして破壊したい気持ち
板(選んだ壁1つを修復)→修復爆弾(当たった付近の壁を修復できる)
範囲破壊できるのなら範囲修復もできるべきだという気持ち
階段→バリケード
階段を障害物として使うことが多かったため生まれた
ウサ耳(初期~)
初期から続投している唯一のアイテム
ロケットシューズ(ゲーム性変更後~)
ジャンプ力アップできるなら速さもアップできるべきという気持ち
さいごに
開発は非常に大変でしたが、自分の作りたかったものが作れて満足しています。
一緒に開発してくれたメンバーの皆・ゲームを遊んでくださったプレイヤーの方々には感謝申し上げます。
開発環境を整えてくださった方々・アセットの制作者方も並びにありがとうございました。
ここからもワールドの改良が行われるかは未定ですが、メンバーの余裕があれば行われます。
明日のブログ記事の担当は@24takeさんと@cp20さんです! :tanoshimi-_rusk:
おまけ:プロジェクトの規模感
部内Git(Gitea)でレポジトリを共有していました。
コミット数: 870
クローズしたイシュー: 218
クローズしたプルリクエスト: 177
作ったU#のプログラムの個数: 69
作ったU#のプログラムの行数: 5563
作ってもらった3Dモデル: 23
(ボツを含めてアイテム8種類, 理科室の実験器具・机・椅子, PC室のPC・ディスプレイなど)
開いた集会の数: 36