見出し画像

VRChatとCyan Timespace LabとパズルとUDONとあなた

概要

この記事はVRChatのパズルワールドCyan Timespace Labの技術紹介や設定、裏話を語ろうと思います。この記事はパズルゲームクリア済み前提で書くので、まだ本編クリアしてない方でも楽しめる内容だと思いますが多少ネタバレになっちゃうので気を付けてください。

長い記事になってしまったので興味があるチャプターだけを読むか、時間があるとき読んでくださいね。

ワールド紹介

VRChatのCyan Timespace Labワールドリンク

Cyan Timespace Lab(Cyanラボ)はアクションパズルゲームワールドです。雰囲気デザインや設定がValve社の名作Portalシリーズを参考にしてます。Half Life:Alyxのグラビティプルと独自の時間逆流ギミックでパズル15個で構成されます。ValveがなかなかPortal 3出さないからパズル欲求満たすために作っちゃいました。

メインコンテンツのパズルをクリアするまで2~4時間かかります。セーブコードシステムありますので、ワールドに入り直しても途中再開できるようになっています。

起源

VRChatのワールド制作SDKは以前プログラミング使うことができなかったんです。それでも賢い作者たちはUnityのアニメーションでインタラクティブなギミック実装したり、面白いことはそこそこありました。でも正直言うと複雑なシステムを築き上げるのは非常にしんどいのでやろうとは思いません。

ある日、UDONが空から降ってきた。UDONをこねるとどうなる?知らんのか?なんでもできる(当社調べ)。

なにか面白いことできないかなぁと考えてみたら、神ゲーHalf-Life: Alyxと出会い、そのアイテムを引き寄せるシステムに魅了されました。全てのVRコンテンツはこれを採用するべきだ!と思いました。なのでUDON最初に作ったのがこちら

実装できた時の興奮は今でも覚えてますね。VR空間内で全てを思い通りに制御できる力手に入れて、全能になった感じでとても楽しいです。結構便利なので他のワールドにでも使えたらいいなと思って無料配布しました。

ではその次に、このギミックでワールド作りたいなぁと思い、このギミックを一番有効活用できるワールドはなんだろうと考えてたら、パズルしかない!という結論にたどり着いた。

時は2020年5月、なが~いなが~い開発はここから始めた。

(ツイートは開発中の物であり実際のステージ1はまったく違います)

パズルワールド作るのなら、メインギミック一個だけではちょっと単調で足りないと思ったので、その数日後、Cyanラボの特徴の時間巻き戻すシステムを開発しました。

この時点でワールドの大まかな方向性は確定していた。あとは、オブジェクトモデルの用意とUDONとパズルデザインとナレーションだけですね!まぁ、すぐ終わるでしょう!(と思った時期わたしにもありました)

正直途中で開発がしんどくなってたこと(いいパズルを思いつかない・Udonバグがひどい)は何度もありましたが、やはり完成させたい気持ちで頑張りました。えらい?えらい!しんどくなった時はとりあえず一旦放置するのがいいと思います。別のゲームして、VRCして、またワールド作りたくなったら戻りましょう。

パズル要素のモデリング

ゲームワールド作るのなら、まずプレイヤーがインタラクトする物を用意しないといけません、ということはモデリングしないといけません。ですが問題はひとつだけありました、Blenderはわたしと和解してくれてなかったんです。勝てない敵と闘争よりも逃走したほうが効率がいいので、Unity Probuilderに逃げました。ProBuilderはUnity内で完結しローポリのモデル作成に非常に優れてます。Cyanラボ内のパズル要素(ジャンプパッド、ボタン、ドア、エレベーターなどなど)すべてProBuilderでメッシュを作りました。テクスチャは自作なのもありますが、基本はUnity Asset Storeで購入したものです。シェーダーも書けませんので、Booth.pmで使えそうなシェーダーをショッピングしました。あれですよ、時間は有限なので持ってるスキルを最大限発揮して、それでもできないことは素直にAsset StoreとBoothの力借りましょうね。買った素材は使い方次第で千変万化になりますよ、このシェーダーをあとどんなことに使えるのかを考えるのも楽しかったですね。

テーマデザイン

統一感を現すためにワールドテーマである Cyan・シアン色 をたくさん使いました、シアンは使えば勝手に「テクノロジー感」がでる(都合が)いい色です。ナレーションキャラの名前は色々案がありしたが、それもC.Y.A.N.にしました。短くて覚えやすい、発音もそこそこ良く、女の子の名前にもなるからです。

パズルデザイン

パズルワールドの一番重要なパズルの設計です。パズルは難易度のバランスが非常に難しくて、簡単すぎると解いても達成感がないし、理不尽なパズルはやってても楽しくありません。Cyanラボ開発の7割の時間はパズルの開発になっています。いいパズルを作るのなら、妥協はできないからね!

正直、Cyanラボ製作過程の中で一番の苦痛でした。「にゃぁぁぁぁぁあああああ!!!!」と悲鳴を上げながらUnityの空白のステージと睨めっこする時間がとても多かった。ですが、いいパズルができた時の達成感もとても気持ちよかったりします、わたし賢いのでは!?ってなりますね。

いいアクションパズルになるために、いくつかのルールがあると思います

1. プレイヤーはパズルの目標をすぐに理解できる。
  最終的にそこに行く・このボタン押すとこうなる・などなど。プレイヤーが悩むべきとこは「どう解くか」であって「なにを解くか」ではない。
2. 達成手段に複雑性があり、直感を裏切る。
  一捻り入れましょう。Bの行動するためにAの行動するけど、なにも考えず直感的にAをしたらBができなくなる状況を示します。
3. 以前のパズルで得た知識の活用で、徐々に難易度を上げる
  いきなり複雑な行動を要求してもプレイヤーはなんも分からん猫になるだけです。ゲーム全体自体が学習過程になって、少しづつ学ばせましょう。
4. プレイヤーから一定の想像力を求め、ギミック性質に対する理解を問う
  ギミックの数を増やすより、すでにあるキミックの性質を最大限活用しよう。
5. 難しくても理不尽ではない
  いい「難しい」は、考えられて設計された「難しい」です。解けられるように設計しましょう。

以上のルールを心の中に覚えて、パズルを作りました。

実際以上のルールはどう具現化したかというと、わたしのお気に入りのステージを紹介しましょう。クリア済み前提で解説しますので、以下ネタバレですよ

ステージ3

画像1

ここは最初の難関ですね。ステージ1と2はパズル雰囲気の紹介も兼ねてチュートリアルですが、ステージ3は一捻り入れて、ゴールするのに右側のキューブを持っていかないといけないですが、それを持つと道が消えてしまう。プレイヤーは「キューブを運ぶ」目標を理解してるし、直感的な解(キューブを持って橋を渡る)もすぐ浮かべますが、実行してみると橋は消えててできません。このステージは、ゴールにあるキューブを入口のキューブと交換して、入口のキューブをゴールに持って行って、キューブをリスポーンすることで二つ揃うのが解です。「ボタンを押すとキューブはリスポーンする」性質の理解がキモです。この性質は新しい要素ではなくて、すでに知ってる事実を深く掘り下げることでパズルを構成しています。そして「キューブのリスポーン」は、以降のステージにもよく使う重要テクニックなので、ここで「プレイヤーに学習させておく」意味合いもあります。お気に入りです。

ステージ5

画像2

このステージの目標は上にある出口にたどり着くことです、ステージに入ったらすぐ分かります。ジャンプパッドもあるのでそれを使うのもすぐ分かります。ですが、出口まで飛ばしてくれるパッドはありません。上の橋に乗るためにプレイヤーの発想力が求められます。解は「先にキューブをジャンプパッドで飛ばして、タイミングよく飛ぶとキューブがスイッチを押して橋を展開する時、空中にいるプレイヤーが華麗に橋に着地する」ことです。ここのキモは「キューブを飛ばすタイミング」です。キューブを飛ばせること自体は既知の事実で、これもまた旧要素から新発想を求むパズルになりますね。そしてこのテクニックもまた、少し変えて後ほどのステージ8で使うのでここでプレイヤーに学ばせます。

ステージ6

画像3

このステージもキューブをゴールまで運んで二つ揃うのが目標ですね。ここのキモは二つ、一つは「グラビティプルでキューブを直接ゲットできなくても位置を変えられることが重要」、それでキューブAを橋の上まで位置調整できます。そして、ゴールエリアではBキューブを取ったら橋が消えてAキューブも落ちて消えますが、Aキューブの落下を防ぐためにボタンを同時に二つも押さないといけません。ですが使えるキューブは一つだけ、ならどうする?のがキモです。「プレイヤー自身がボタンを押すこともできる」の概念を利用しています。一見キューブが足りなくて不可能が問題でも、プレイヤーの発想力を求め、ある閃きで解けるようになるパズルですね。

ステージ11

画像4

ステージ9と10が新しい要素時間逆再生のチュートリアルで、11からは時間逆再生の最初の難関になりますね。キューブを取ったら、ドアは全て閉じるので、どうやってキューブを真ん中の部屋に置く上に、最初に部屋に戻れるのが問題です。このステージは、時間記録してる段階で予めボタンの上に止まることで、逆再生中、キューブをボタンに置くことがキモになってます。時間記録の段階で未来の行動を先に計画するのがこのステージで習得できるテクニックで、これからのステージもよく使います。

ステージ13

画像5

来ましたね!多数のプレイヤーにとって瞬間難易度一位、時間操作1回でどうやってキューブを2個も上に持って行くかの問題です。簡単に言ってしまえば順番の問題ですが、全てのギミックが全部お互いの「制限」になっていて、キューブAを取ったら時間逆再生が止まり、キューブBを取ったら橋が消えて戻れなくなる。時間操作中の状況を予め考えて、その中で全て矛盾しない解を探すのがこのパズルの難しいとこです。時間操作の原理を最大限利用したパズルになります。ここの解は実は数パターンがあります。その中でプレイヤーが2回ジャンプパッド踏む/キューブの位置交換/キューブをジャンプパッドで発射などがありますが、あなたはどの解にたどり着いたのでしょうか?

ステージ14

画像6

ここはわたしの一番すきなステージです。チャンバー自体は広くないですがそこそこの難易度、コンパクトで深いパズルですね。タイムストップネットの「既知の仕組みをどこまで深く理解してるか」のがキモですね。チャンバー全体見て、ゴールまでの流れを考えてみたらあることに気づきます。あれ?重い方のキューブをゴールに持って行く方法なくない?橋は建ててでも、結局消去バリアあるので、重いキューブを持って行けない。そうなんです、これはタイムストップネットの機能を利用して、橋の上に時間操作解除されて華麗に橋に着地するのが正解です。CYANちゃん曰く「物の性質を理解したら、障害物も有用なツールになります」ということです。その「性質」をプレイヤーに「気づかせる」こと自体が「パズル」ですね。

アクションパズルを作る時の思考回路はこうです。まず「プレイヤーになにをさせたい・なにを考えさせたい」、「このステージのキモなにを用意しよう」から始めてます。プレイヤーにやってほしいことから、パズルの要素を展開していく感じです。例えばステージ3の「キューブ交換とリスポーン」、ステージ14の「空中で時間操作解除」など、(チュートリアル以外)どのステージも必ず「やってほしい・気づいてほしい」ことが1個や2個あります。このポイントが存在するからこそ初めてパズルはパズルになります。ここで難易度のコントロールをしてます。この「難しいポイント」が多すぎると、プレイヤーは解けないし、簡単すぎると、そもそもパズルにならない。パズルを解くための材料は全て提供して、後はプレイヤーが閃くのを待つだけです。プレイヤーがそれをできた時は多大な達成感を感じるのでしょう。

開発の段階で、できたステージを自分やフレンドにテストプレイさせたら結構別解が発見されます。もしその別解がわたしの「やってほしいこと」をスキップできるルートだったら、その別解を防ぐための修正をします、あとは完成するまで「テストプレイ>修正」の振り返しです。その中で没になったステージもありましたよ。

UDONとゲームシステム

CyanラボのUDON濃度が非常に高く、U#スクリプトは100個以上、ワールド全体は、プレイヤーが見えてる物と見えてない物合計数百個くらいUDONがついてるオブジェクトがあります。

わたしの母国語はC#なので、U#を書いてる時は楽しかったです(小並感)。やはり自分の手で世界のルールを制御して、VRを被ってその「自分の世界」に入るのは楽しくて楽しくて最高でした。折角作るのなら、クオリティは妥協したくないという精神でした。現代UDONワールドの新スタンダードを作る気でコード書いてました。

でも待ってください!UDONが書けるようになったらなんでもできると言ったな?あれは嘘だ。UDONは肝心なとこに手が届かないことがたまによくあって、バグも発生しやすく、デバッグも難しくて、すぐUDONとの死闘が始まります。特に古いバージョンだとエラー次第でUDONオブジェクトが全て壊れることもあったので、毎回プロジェクト開く前にバックアップを取るのが基本でした。SDKのバージョンアップは毎回苦労しましたよ。とは言っても、最近のSDK3 UDONとU#もアプデ重ねて相当使いやすくなりました。UDONをこねるのにいい時期です。

ところでわたしのヒエラルキーを見てくれ... こいつをどう思う?

画像7

すごく (System系オブジェクトが) 多いです...

GameManager?Unityゲームでも作ってるの?

画像8

Cyanラボは「GameManager」が全ての核心で全て重要なことを管理し、全てのサブシステムが調和するように設計されてます。全ての処理を同じクラスに入れると、コードマネジメントがとても難しくなります。オブジェクト指向の基本ですね。ですが、UDONは他のクラスの関数を呼ぶ時はオーバーヘッドが発生します。なのでクラスを作りすぎてもパフォーマンスに影響しますので程よいバランスを探しましょう。

まずプレイヤーが認知できてるUDONを数個だけ紹介しましょう。

両手に物を同時に掴むと片方は強制的に離されてCyanちゃんに怒られます。それはデスクトップは同時にキューブ一個しか持てないためのバランス調整です。

両手のPickup状況をチェックし続けて、両手もPickupしてる場合片方をドロップするように処理しています

キューブを投げようとすると水平スピードが0になり遠くまでは飛ばせない処理をしています。キューブ投げられるとパズルデザインの難易度が65535倍跳ね上がるからです。

キューブのPickupのステータス解除した瞬間、水平スピードを0にする

足音のUDONもあります。足音が聞こえるだけでワールド全体の完成度が上がるのでオススメです。それ以外に、時間逆流する時、足音も逆再生するようにしてるので雰囲気作るのに役に立ちます。

プレイヤーの座標を記録し、ある程度距離が離れたら足音を再生するようになります。Cyanラボでは足音が4種類(+4 種類逆再生用)あり、直近再生された音以外の3つの音の中でランダム一個を再生する仕組みです

それ以外に、プレイヤーは多分気づいてないUDONの処理を紹介しましょう。

ジャンプパッド踏んだプレイヤーに「上昇」する力与えると、上に飛ばされますが、もしそこで天井にぶつかると頭が痛たたになって落下するのが「自然」ですね。ですがVRCのデフォだと、「上昇するスピードがなくなるまで、上昇を試し続けて、結局天井に張り付いて水平に進み続ける」ようになっているので、「ちゃんと自然に」落ちようにUDONの処理があります。ステージ5とかですね。

画像9

解決案は「プレイヤーが空中にいる時、座標をチェックし、もし数フレームも水平移動してるけど垂直移動してない場合、垂直スピードを0にする、それで重力で落下し始める」


負荷減らすために、全てのチャンバーはDisabledになってます。プレイヤーがエレベーターを乗って、チャンバーの入り口のエレベーターにテレポートされた瞬間チャンバーがActiveになり、全てのキューブがリセットされます。前のチャンバーはまたDisabledになります。なのでエレベーターに乗ってる時なんか聞こえる音がキューブリセット時の音です。

VRCは空中にいる時は多少進行方向変えられるのはご存知ですね、ジャンプパッド踏んで飛んだ時、プレイヤーが動けなくなるように処理してます。空中に自由に動けたら破綻するステージが多いので、結構重要な処理ですね。

ジャンプパッド踏んだらlocalPlayer.Immobilize(true)に設定し、localPlayer.IsPlayerGrounded()になったらlocalPlayer.Immobilize(false)に戻す。

メインのUDONシステムの紹介しましょう

字幕システムはカメラ使ってUI Canvasを常に頭の前に表示するようにしてます。字幕を作る時一番重要なのは可読性です。字幕が近すぎるても遠すぎてもVRはとても読みにくくなります。本当に大事です。Cyanラボのは1.5m離れてますが字幕のサイズにもよるので作るときは実際VRで色々試してみてくださいね。

字幕が重ねないように、内部では配列があります。例えばセリフAが終わる前にプレイヤーがセリフBが発生するボタンを押したら、Bは疑似Listに保存されます。そうなんです、あのList<>です、が、今のUDONではまだ使えませんので別の方式で実装しました。

字幕たちの親になるオブジェクト作って、VRCInstantiate()で新しい字幕情報を持ってるオブジェクトを親の一番後ろの子供にして、transform.GetChild(i)でアクセスして実際の字幕を出します。用済みのオブジェクトはDestroy()されます。

これでダイナミックな配列Listができますね。割とごり押しな方法なので、多少パフォーマンスに影響は出そうですが、字幕は常に出てるわけではないし、基本処理要らないのでヨシとします。

また、U#コードに日本語のstringを書くと文字化けになってしまうので、.txtファイルを用意して、U#で読み込んでいます。

UnityEngine.TextAssetというクラスです。せぷねこさんに教えて貰いました。

字幕の発動方式は色々あるけど、一番多いのはプレイヤーのコライダーが透明の(紫)のコライダーに入ると発動します。

だsだs

ちなみに開発しやすくために、アバター自体のコライダーは一切触ってません。代わりに透明のコライダーをプレイヤーの足に付けてて、そのコライダーでプレイヤーに関する判定をしています。なのでアバターのサイズに関わらず、スイッチを押すと時の判定の大きさが同じという公平性もあります。

グラビティプルは、Half Life:Alyxのを再現しようと努力しました。ターゲットを探す方法はRayCast、VR手の動きの探知は、まずプレイヤーの手の位置を記録し、次のフレームと比較する。ある程度動きが大きいと内部counterが上昇し、counterが一定値になったら(数フレーム手が動き続けたら)放物線の計算して飛ぶスピードと角度をキューブに適用する。デスクトップなら、「E」キーが入力検知です。ソースは300円で公開してますので興味がある人はどうぞ

時間操作のタイムキーパーは、椅子です。CYANちゃん曰く、椅子はVRCの技術の究極な答えです。蓋を開けたら仕組みはとても簡単。プレイヤーの座標と回転角度を記録し、椅子に座らせて椅子の座標を記録の逆再生するように動かせるだけです。最初は椅子ではなくPlayerのTeleportで試したが、Teleportで空中の座標を指定するとその地面にスナップしちゃうのでだめでした。時代はやはり椅子ですね。肝心なのは演出です。時計のチクタクの音、時間操作中の画面のPost-processing、時間のタイマー表示、足音の逆再生など、雰囲気を築き上げたら結構それっぽくなりました。Editorだとこんな感じです。

画像10

Post-processingについて。UDONは直接Post-processingを制御できません(多分、少なくともわたしの開発してた時は)。なのでPost-processingを制御するためのアニメーションを作って、アニメーションをUDONで制御してます。

バックグラウンドのPost-processingのBloomについて。Bloomは「とりあえずたくさんBloom付けたらワールドは勝手に綺麗になる」魔法の道具ではありません。

Bloom付けすぎるとVRはとても目が痛くなります!!Bloomは魔法ではありません!Bloomが眩しすぎるワールドに入ると、みんな最初にすることは「Bloomを切るボタンを探す」ことです!!

もちろんBloomを正しく使えばいい道具になります。CyanラボもBloomがあります、設定は以下です。Bloomのおかげで眩しくなるべきなレーザーが眩しくなり見栄えがよくなります。特殊な状況でもない限り、Bloomは結構控えめでいいんです!!

画像13

その他、パズル要素ももちろん全てそれぞれのUDONがついてます

スイッチはこんな感じです。全てのスイッチのコードが統一していて、スイッチとリンクしたい別の物(ドアなど)のUDONクラスをスイッチに関連することで作動します。例えばこのスイッチだと、押されたらDoor(1)が開きます。

画像11

ナレーションCYANちゃん

もちろん元ネタPortalのAIを模倣するために作り上げたのがCYANちゃんです。プレイヤーの行動に反応して色々喋ります。セリフは約200個あります。言語の選択で字幕が英語か日本語になります。

VRChatのワールドなので、できる限り「VRCの色」を加えました。ポリゴンの話とか、UDONの話とか、アバターと話をすると、結構「VRChat」感がでますよね。

Cyanちゃんはプレイヤーに大切なルールや情報を伝えるためにある、はずですが、とても生意気な子です。プレイヤーのことをナルシストと呼ぶけど実は一番のナルシスとはCYANちゃんだったりします。そんなCYANちゃんの発言でワールドの色を付けられたらいいなぁと思いながら、プレイヤーがそのセリフでくすっと笑ってくれたらいいなぁと思いながら設計しました。ですが、人によってはちょっとやりすぎかなぁと後悔してる部分もあります。もしCYANちゃんの発言でイライラになった人がいたら本当に申し訳ございません..

CYANちゃんを調教したので今後は多少大人しくなります。いつかデレる日が来るといいですね。CYANちゃんはこれから作るワールドに出す予定があったりなかったりしますよ。

小ネタ

「重そうなキューブ™」はあくまで「重そう」なだけで、重くありません。証拠は、だれでも片手で持ち上げられるからです。グラビティキューブとどう分別するかで「重そう」と伝えたらわかりやすいと思ったからです。

グラビティアンカー(重力の錨)という没になった装置があります。アンカーにグラビティプル使うと、「プレイヤー自身が」アンカーに引っ張られます。ですが、プレイヤーの移動を制限しづらいのでパズル作成の難易度が上がり没になりました。やはり時代はジャンプパッドですよ。

画像14

実績システムはSteam実績のように、やりこみ要素です。簡単に全て獲得できる前提で用意してるわけではありません。やりこみたい人向けの要素です、が、それでもそこそこな人が全コンプしていて驚きましたね。攻略組を甘く見てはいけません...(対戦ありがとうございます)

チャンバー11の最後の橋のスイッチは実は使わなくてもクリアはできますよね。実は古いバージョンではそれは必須でしたが、開発中ある時パズルのアプデで必須ではなくなりました。そしてわたしはリリースまでも気づかなかったのです。

チャンバー8もあるスイッチは使わなくてもクリアできる(ちょっとだけ)短縮ルートがあります。わたしを含め大体の人は普通にそのスイッチを利用しますが、ある人のプレイを見て「はっ!賢い!」となってまさかの作者も気づかなかった新ルートが存在していた。

Save-Codeのチョイスは制御文字x86命令リスト+ノイズでできてます。例えばステージ1の「STX1」のSTXは「テキスト開始 Start of Text」ですね。

最後に

Cyan Timespace Labをプレイしてくださった方、このながーいブログを読んでくださった方、本当にありがとうございます。リリース直後の一週間は毎晩数百人が遊んでくださってそれはもう嬉しかったですよ。

Unityでこの規模の「ゲーム」を作るのはわたしも初めてでした。わたし一人で、スタンダードを高く、できる限りクオリティが高いワールドに仕上げたい気持ちで頑張りました。楽しんでくれたら幸いです。「面白かった」とツイートしてくれるだけで作ったかいがあった~と思います。エゴサの魔人なので見てますよ。

まだ遊んでいない人は是非遊びに行ってみてください、クリア済みの人はフレンドを拉致してラボに投げ込んでください!フレンドがパズルで悩むとこを見るのも一興ですよ。

アバター用のCyanラボバッジ(無料)もありますのでよかったらどうぞ

この記事が気に入ったらサポートをしてみませんか?