我々は、以下のシステムを使用して、基本的なゲームプレイシステム および主なデザイン要件のどちらもサポートしました。
使用マネージャ
UseManager は、収集したオブジェクトをマネキンに衣装の一部のように適用するためのシンプルな APIを提供しました。この API のメイン機能は UseManager.AddUse (タグ、ターゲットオブジェクト、距離、onSuccess、onNothingEquipped、onWrongEquipped、追加データ) で、タグのセットを ターゲットオブジェクト にバインドします。プレイヤーがタグの 1つを持つオブジェクトを持っており、ターゲットオブジェクトをクリックすると、onSuccess 呼び出し機能が呼び出されます。他の呼び出し機能により、クリックが行われずに捕まえられたアイテムがないか、または間違ったタイプのアイテムで行われた場合、プレイヤーに追加の視覚情報を表示できました。
通常、ミッションが終了したり、特定のアイテムが "使用"されたりしたときに役立つ UseManager.RemoveUse を使用して「使用」を削除できました。また、AddUseTargets と RemoveUseTargets でターゲットを追加または削除できます。
ハイライト
プレイヤーが興味のあるアイテムの近くにいるとき、シールのように、そのアイテムを周囲の環境から際立たせたいと考えました。これを実装するために、LocalScript と呼ばれる ハイライトアイテム を作成し、Touched および TouchEnded イベントに接続して、プレイヤーの周りの球を使用して他のメッシュを検出する。getHighlight 関数は、タッチされたメッシュまたはその親に使用する GetTaggedObjectUpHierarchy ヘルパー関数を使用して、複数のタグをチェックします。ハイライトが必要ない場合、 ハイライトなし タグを使用して強制的に削除できます。しかし、必要であるが、さまざまな他のタグにはまっていない場合、 重要 タグを使用して強制することができます。
この LocalScript は、オブジェクトの概要を描画し、またはオブジェクトの内部を定義された色で満たす新機能 Highlight を使用しています;この機能の使用方法に関する詳細は、オブジェクトの強調 を参照してください。 とマウスカーソル OnItemIndicator システムは一緒に働き、メッシュがハイライトが必要かどうかを決定するだけでなく、 メッシュの種類も提供します。
HighlightItemsFunc は、他のクライアントシステムとの通信に使用されます。たとえば、イベントマネージャは、 有効化 コマンドを使用して、特定のカットシーンでHighlightまたは無効化し、 オンアイテムインディケータ は、タイプのオブジェクトを尋ねるためにGetType。破損したルームが破壊されたように、アイテムがもう存在しないときを検出するには、CollectionService.GetInstanceRemovedSignal に接続します。
ロアと思考バブル
ロア と 考えのバブル は2つの似たシステムです。ロアは、子供のサイズとスケーリングを制御するために、ScreenGui を画面上のUIコンテナとして使用し、子供の Frame と TextLabels 、および ImageLabels を制御し、ロアはプレイヤーが画面のどこかをクリックするのを待ちます。同様に、思考バブルは子供の BillboardGui を使用して非ロアのオブジェクトに TextLabel を表示し、テキストが画面全体を占有しないで指定された期間とクールダウン期間の間の 3D 空間に対話を表示します。これらのシステムの背後にあるデザインについて詳しくは、ロアと考えのバブルを参照してください。
ロアは LoreManger の LocalScript で実装されています。クリックまたはタッチすると、ヘルパー関数 utils.RaycastAlongPointingDir を使用してレイキャストを発射し、 NoPlayerCollision グループを使用します。クリックの下のメッシュまたは親の 1つで ロア または 思考バブル タグがある場合、UIを表示します。テキスト、キャプション、画像は、オブジェクトの LoreText、LoreCaption、および LoreImage 属性によって定義されます。
非接触かタッチかに応じて、Camera.ViewportPointToRay または Camera.ScreenPointToRay を使用してレイを構成することに注意してください。座標は若干異なる座標システムにあります。マウスの場合、MouseButton1 から Class.UserInputService.InputEnded``:Connect 、タッチデバイスの場合、Class.UserInputService.TouchTapInWorld``:Connect から取得します。
考えの泡は全体的に似ており、レイキャストを使用してメッシュまたはその親が 考えの泡 タグを持っているかどうかをチェックします。また、テキストには ThoughtText 属性を使用し、世界にUIを配置するために使用されるプレースホルダーオブジェクトを指す ThoughtBubble タグを使用します。同じ位置オブジェクトを使用しているが、異なるテキストを使用する思考バブルには、異なるクールダウンがあります。
特別なケース
ロアにはいくつかの特別なケースがあり、そのうちの 1つが損傷したシールです。プレイヤーが破損したシールをクリックすると、ロアUIが表示され、クリックを待ってミッションを開始し、ゲームフローに影響します。これは、バインド可能な を使用してリロー UIをリクエストする によって処理されます。コールバックは、GameStateClient によってロアシステムに提供され、プレイヤーによってロアが「閉じられた」時を知ることができます。もう一つの特別なケースは、 ThoughtBubbles と Lore タグが同じオブジェクトにあるときです。この場合、知識と思考バブルの重複を避けるために、ロールが閉じた後、思考バブルを実行します。 LoreManager は、プレイヤーが部屋の封印を拾うまでロックされた無効なドアをクリックすると、小さなカットシーンを表示する特別なケースも処理します。
オンアイテムインジケーター
プレイヤーが特定の関心のあるアイテムを見ているときに、画面の中央に異なるアイコンを表示したいと思います。クライアントスクリプト OnItemindicator はカメラ沿いでレイキャストを行い、結果を分析します。結果に基づいて、OnItemIndicator2 ScreenGui に画像を設定します。
関心のあるアイテムがヒットしないと、デフォルトのアイコンは小さなドットです。We could set any icon by adding an オンアイテムインディケーター 文字属性 to a specific mesh, using the names from onItemIndicatorImages , such as Hand, Eye, or DoorCurrentlyLocked.属性はレアな場合にのみ必要であり、ほとんどの場合、既存のタグやシステムのほとんどがアイコンの種類を提供します。詳細については、Update 機能を参照してください。
タイプチェックは、優先状況位の一部をチェックします。OnItemIndicator オーバーライドの後、utils.CanGrabModel(model) または utils.GetTaggedObjectUpHierarchy("Drawer2", model) を介して「手」アイコンのグラブ可能かどうかをチェックします。その後、 がハイライトステータス、アイテムの種類、使用するアイコンを決定します。例えば:
highlightItemsFunc:Invoke({"GetType", curInst})
ロアとThoughtBubble タグは、タグをチェックして後でチェックされます。ドアには、2種類の異なるアイコンがあります: DoorCurrentlyClosed と DoorAlwaysLocked 。 DoorManager > は、開いたり閉じたりできるドアに真偽の DoorEnabled 属性を設定し、属性の存在と値を使用します。ドアのように見えて開かないオブジェクトには、 ドアロック タグがあります。
ドア管理者
ドアマネージャは、ドアタグとドアを使用して、開口と閉口を管理します。ドアには、タッチと touchEnded イベントで接続する前面と後面のトリガーがあります。私たちはティーンを作って、前面と後面からドアを開け閉めするようにしました。我々は playersNear マップ (プレイヤーがトリガーに触れる、フロントとバックの両方のために別々。
各ドアには単純な状態システムがあり、DoorState (閉じる、開く、開く、閉じる)、移行に使用されるティーンがあります。We could enable or disable a door's ability to open or close from external systems by calling DoorManager.EnableDoor , which sets a DoorEnabled 属性。
マスターアニメーター
The マスターアニメーター LocalScript は、テレビ画面をアニメートするために使用していたアニメーテッド画像 (テクスチャアトラス) を再生します。画像をスクロールするには、パラメータのセットを知る必要がありました:行と列の数、フレームの合計、期間、画像のサイズ、および画像IDのセット。システムは、複数の画像をアニメーション化し、それぞれがサブ画像の行と列に分割される可能性がありました。このデータを属性または値で提供できますが、このエクスペリエンスでは、ヘルパースクリプトを使用しました。UpdateImageAnimations(dT) は、時間とパラメータを使用して表示する必要のある画像やサブ画像を計算します。新しい画像に変更する必要がある場合は、Image を設定します。もし任意のサブイメージを変更する必要がある場合、ImageRectOffset を設定します。
アニメーテッドの SurfaceGui を持つオブジェクトには、主にすべてのパラメータを返す ModuleScript 機能を提供するための Animator Animator.GetParams がありますこれは、 画像アニメーション タグと を使用するマスターアニメーターに、そのようなオブジェクトを収集し、その下でアニメーターを見つけるのを助けます。次に、pcall を使用してアニメーターを要求し、ModuleScript に呼び出し、GetParams を呼び出します。
ローカルスペースアニメーション
The ローカルスペースアニメーション LocalScript は、X、Y、または Z軸の周りで回転速度と遅延を持つ主に「コスメティック」オブジェクトを回転させるために ローカルスペース回転 タグを使用します。これは、プレイヤーが相互作用しない遠隔オブジェクトまたは、シミュレーションにほとんど影響しない小さなオブジェクトに使用しました。パラメータは、Speed、Delay、および Axis の値を通じて定義されます。実装詳細は、回転クラウドメッシュ を参照してください。
ヘッドランプマネージャー
The ヘッドランプマネージャー LocalScript は、ユーザーが画面上の ImageButton を選択して、頭上のスポットライトをオンまたはオフに切り替えるときに処理し、ヘッドランプイベントを使用してサーバーにコメントを発射し、オンとオフの切り替えサウンドをプレートします。キャラクターが追加されたり、Head が変更されたりすると、giveCharacterHeadlamp 機能は templateHeadlamp ランプをクローンし、 FaceFrontAttachment からのオフセットと回転を使ってランプの位置を変更します。
シートマネージャ
プレイヤーが座ることができるオブジェクトの近くに自動的に座ることはしません。代わりに、ユーザーが座るために近くのシートをクリックするように要求したい。 シートマネージャー スクリプトは、 を基に シート タグを追加し、クリックすると を呼び出します。ルームの通常と損傷状態間でプレイヤーをテレポートするとき、CFrame の協調変更が機能しないため、プレイヤーが座っていることはできません、そのため、 SeatManager には、テレポートの 前と後の数秒前に座席を無効化または有効化する機能があります。
ドロワーマネージャー
ドロワーマネージャー スクリプトは、 Drawer2 タグと を使用して、ドロワーをクリックして開いたり閉じたり、対応するオーディオを再生します。開始と閉じるアクションは、ターゲットポジションを PrismaticConstraint に設定して行われます。
キルボリューム
メインのゲームプレイエリアの数ヶ所で、電気スパークや道の始まり付近の水など、プレイヤーが Humanoid.Health を 0 に設定できるのは、 KillVolume タグを持つボリュームに入るときです。 キルボリューム スクリプトは、Touched:Connect を使用して、プレイヤーがボリュームに入るタイミングを決定し、その後体力を 0 に減少させます。
プレイヤーミッションリスポーン
The PlayerMissionRespawn スクリプトは、 RespawnVolume タグと CollectionService を使用し、タッチするとプレイヤーがリスポーンするボリュームを処理します。多くのミッションには、プレイヤーが落ちる可能性のある空白や移動プラットフォームがあるため、これらのボリュームを破損したルームの下に配置しました。タッチすると、スクリプトは小さな テレポート_ジャンプ カットシーンを再生し、 コマンドで呼び出します。
When processing GameEvents.PlayerRespawn , the script can use RespawnPositions , if mission config がそれを提供する場合。そうでない場合は、特定のミッションのために TeleportPositions を使用します。「チェックポイント」システムは持っていないので、CalcClosestTeleportPos はプレイヤーが **** にヒットした場所から、唯一の横方向、"2D"距離を使って最も近い リスポーン または RespawnVolume スポットを選択します。
小さなヘルパーシステム
ピアノマネージャ
ピアノマネージャ スクリプトは、 ピアノ タグと CollectionService を使用して、キーボードをクリックすると、ClickDetectors を追加し、ピアノのサウンドの 1つを再生します。
儀式サポート
プレイヤーがシールを配置するフォイヤーには、各シールが定義された場所に配置されるたびに変更される複雑な装置があります。たとえば、配置されたシールの数に応じて、特定のイベントが光とビームを有効化/無効化したり、特定のオブジェクトの透明度を変更したりするなど、The 儀式支援 ModuleScript は、特定のシールが配置された内容に応じて、EventManager:Invoke 呼び出しに対するパラメータを提供する小さなラッパーで、それらのイベントに参加する "根オブジェクト" を指定するなど、依存するパラメータをイベントに提供します。
復元可能なマネージャRestorableManager
いくつかの掴みやすいオブジェクトは、シールなどのゲームプレイに重要であり、プレイヤーがどこかに落とした場合に失われるのは望ましくありませんでした。オブジェクトに 復元可能 タグがある場合、 RestorableManager スクリプトは、復元システムに追加されたときに変換を記憶します。プレイヤーがそのようなオブジェクトをドロップすると、採取システムが restorableManager.StartTracking を呼び出します。オブジェクトが 5秒以内に再びピックアップされない場合、 RestorableManger スクリプトはオリジナルの変換に位置づけ、トレース時間をリセットします。
ポータル
数ミッションで、プレイヤーを回転プラットフォームから落ちる プレイヤーのリスポーン など、ミッション内で短距離をテレポートします。この種類のテレポートを設定するのを簡素化するために、スクリプトで「ポータル」と呼んでいるものを、デモユーティリティ ProcessPortal のヘルパー関数 **** が使用されます。たとえば、P1 が最初のトリガーを定義するパーツであり、P2 が目的地プレイヤー変換を定義するパーツである場合、次のコードスニペットは次のポータル機能を定義できます:
P1.Touched:Connect(function(otherPart) utils.ProcessPortal(otherPart, P2) end)
プロセスポータル は、他のパーツが人間であることをチェックし、プレイヤーを CFrame 座標変更でテレポートし、 Teleport_Jump イベントで移行を隠す小さなカットシーンを呼び出し、イベントマネージャー で。
構成スクリプト
いくつかの構成、データ定義、および共通の機能スクリプトがあります: デモ構成 。ミッションの定義。ゲーム状態の列挙、クライアントサーバー通信のイベント。 DemoGlobalSettings 。1つの場プレースで開発し、他の場所でリリース (およびプレイテスト) します。スクリプトは placeID をチェックし、さまざまなチートとデバッグ機能を有効化/無効化します。 デモユーティリティ 。さまざまなユーティリティ機能。変換を処理する。視認性を設定したり、固定されたり他のプロパティを設定したりします。箱内のポイントをチェックしています。「ドット付き」名前で階層のオブジェクトを見つける。一時的にモデルを「遠くの場所」に移動して戻すことができる TempStorage を管理する (後で戻すことができます)。クリック検出ヘルパーをクリックします。サポートを捕捉中。タグのチェックをサポート(特に階層沿い)。トリガーをイベントマネージャーに接続しています。 AudioUtils 。セットから重み付きランダムサウンドを再生する複数の機能。 GrabUtil 。グラブ用のヘルパー機能。