次のシステムは、The Mystery of Duvall Driveのゲームプレイを構築するための基礎でした。
ゲーム状態マネージャー
The ゲーム状態マネージャー / ゲーム状態クライアント は、エクスペリエンスで最も複雑なシステムです。これは、次のことに取り扱います:
- ロビー内のプレイヤーを開始し、グループをメインのゲームプレイエリアにテレポートするまでのカウントダウンを開始し、プレイヤーを予約されたサーバーにテレポートします。
- 破損した部屋をクローンし、並列でストリーミングし、プレイヤーを特定の CFrame コーディネートにテレポートします。
- シールのメカニクスを捕獲して配置する。
- ドアのロックとアンロック。
- 最終カットシーンをプレイするためにフォイヤーにテレポートし、フィニッシングカットシーンを再生します。
私たちは単純な状態マシン (Update 機能) として実装し、状態は デモコンフィグ (ゲームステート枚数) にあります。一部の状態は最初のロビー/予約サーバーのテレポートを処理し、他の状態はミッションを検索し、パズルをトリガーし、ミッションをソリュートすることです
GameStates は、サーバー側が中心ですが、クライアントが何かをする必要があるとき、例えばカウントダウンを表示する、伝承する、またはストリーミングの再生を無効にするなど、サーバーとクライアント (GameStatusClient) は、リモートイベントを通じて GameStateEvent という名前のイベントを通信します
テレポートゲームステート
3つのゲームステートがあり、3つのユニークなカットシーンを実行して、テレポートを破損した部屋
ストリーミングが処理されている間、InFlight は実行され、少しパルスする暗い画面を保持します。<
同様の Warmup、InFlight 、および Cooldown カットシーンは、プレイヤーを通常の部屋の状態にテレポートすると、 TeleportWarmupBack 、 TeleportInFlightBack 、
照明と雰囲気ゲームステート
私たちは、各部屋の通常と破損
ドアのロックゲームステート
イベントマネージャー
イベントマネージャー は、キーフレームなどを使用して、「アクション」を時間ごとに実行することを許可します:
- インスタンスプロパティと属性をインターポリングする。
- スクリプトの実行。
- オーディオを再生しています。
- カメラシェイクを実行しています。
理想的には、トラックベースの UI を使用するツールを使用しますが、このデモでは、キーとプロパティ名を手動で入力しました。 イベントマネージャー システムは、スクリプトとイベント/関数を含む複数のスクリプトで構成されています。
- EventManager - イベントの作成と停止、およびサーバー側のアクションに対する全体的なロジック。
- EventManagerClient - クライアント側アクション。
- EventManagerModule - サーバーとクライアントサイドの両方のアクションの共通コード。
- EventManagerConfig - コマンドデクラレーションが少しの小さなファイル。
- EventManagerDemo - このデモのすべての実際のイベントがゲームスペックのスクリプトで定義される場所。
- EventManagerEvent , EventManagerFunc リモートイベントとバインド可能な関数を実行して、クライアントまたはサーバーからのイベントを停止します。これは、他のシステムがイベントを設定、実行、および停止する方法です。
各イベントには名前、コールダウン、実行時に実行する機能、オプションの情報を含むセクション、イベントパラメーター、セクション、およびオープンなインターポリント (任意のプロパティまたは属性の間で実行をインターポリント) があります。スクリプト (注册スクリプトを実行する keyframe でスクリプトを実行)、カメラシェイク、およびプレイオーディオがあ
インタープレーション
オーバーライドにより、キーフレーム間でジャンプしている間にオブジェクトプロパティと属性をスムーズに変更できます。たとえば、次のコードスナップショットは、 Class.TextLabel.TextTransparency
interpolants = {objectParam = "TextLabel",property = "TextTransparency",keys = {{value = 1},{time = .5, value = 0},{time = 2.25, value = 0},{time = 3, value = 1}}}
次のコードサンプルで示すように、どのオブジェクトプロパティまたは属性が、クライアントでストリーミングをサポートするために使用されている「グループ」に属するかを定義できることを望みました。
object = workspace.SomeFolder.SomeModel
これを実現するために、オブジェクト名で参照を許可し、イベント開始時に名前のパラメーターを渡すことができます。名前のオブジェクト を見つけるには、イベントがこのルートの下で名前で見つけるオブジェクトを指定する必要がありま
params = {["RootObject"] = workspace.Content.Interior.Foyer["Ritual-DemoVersion"],},interpolants = {objectName = "Wander",attribute = "TimeScale",keys = {{value = 0.2}}}
パラメーターセクションのイベントにパラメーターを入れることができ、イベント開始時のスクリプトは既存のパラメーターを変更するか、「参数」テーブルの「参数」を追加することができ
params = {isEnabled = false},interpolants = {{objectName = "FocuserGlow",property = "Enabled",keys = {{valueParam = "isEnabled"}}}
パラメーターは、エクスペリエンスの開始時点ではないオブジェクトに参照できるようにします。たとえば、次のコードサンプルでは、イベント開始時に実行されている関数がオブジェクトを作成し、パラメーターに BlackScreenObject のエントリを設定して、作成されたオブジェクトを指します。
{objectParam = "BlackScreenObject",property = "BackgroundTransparency",keys = {{value = 0},{time = 19, value = 0},{value = 1},}}
イベント、イベントインスタンス、トリガーへの接続
イベントを実行するには、クライアントからリモートイベントを使用するか、サーバーから機能を使用します。次の例では、 RootObject イベントにパラメーターをいくつかのパラメーターを返しました。内部的に、イベントの説明のインスタンスが作成され、パラメーターが実際のオブジェクトに
local params = {RootObject = workspace.Content.Interior.Foyer["Ritual-DemoVersion"]["SealDropoff_" .. missionName],isEnabled = enabled}local eventId = eventManagerFunc:Invoke("Run", {eventName = "Ritual_Init_Dropoff", eventParams = params} )
「Stop」関数を呼び出すことでイベントの実行を停止できます:
eventManagerFunc:Invoke("Stop", {eventInstId = cooldownId} )
「コスメティック」 (シミュレーションの結果をすべてのプレイヤーに変更しないでください) など、「インターポラント」 (すべてのプレイヤーにシミュレーションの結果を変更しないでください) などのアクションは、クライアントで実行できます。これにより、より柔らかいインターポラントが生成される可能性があります。
イベントをトリガーに簡単に接続するには、ConnectTriggerToEvent または ConnectSpawnedTriggerToEvent を使用しました。これは、名前でトリガーを見つけます。eventManagerFunc を使用して、他のトリガーを使用で
イベントパラメータ
スクリプトによって渡されるカスタムイベントパラメーターに加えて、イベントを作成するときにオプションでパスできる他のデータは、プレイヤー、コールバック (イベント終了時に呼び出される) 、およびコールバックパラメーターです。一部のイベントは、クライアントで実行するアクションを含む
イベントは minCooldownTime および maxCooldownTime によってクールダウンが定義されることがあります。ミニとマックスはプレイヤー数に基づくスケーリン
スクリプトの呼び出し
Class.Script|Scripts をスクリプトセクションの特定のキーフレームで呼び出すこともできます。たとえば:
scripts = {{startTime = 2, scriptName = "EnablePlayerControls", params = {true}, onServer = false }}
前の例では、 EnablePlayerControls Script はイベントマネージャーモジュールに登録する必要があります:
emModule.RegisterFunction("EnablePlayerControls", EnablePlayerControls)
クライアントスクリプトでは、クライアントに呼び出された関数のために RegisterFunction を呼び出す必要があり、サーバースクリプトでは onServer = true です。機能自体はイベントインスタンスとパラメーターを取得しますが、この場合は、 パラメーターが true です。
local function EnablePlayerControls(eventInst, params)
オーディオを再生中
We have limited support for playing 非ポジションオーディオ at keyframes in the サウンド section, for example:
sounds = {{startTime = 2, name = "VisTech_ethereal_voices-001"},}
イベント終了コールバックは、イベントの期間が終了するときに発動するのに、オーディオアクションはまだ再生されている可能性があります。
カメラシェイクを実行中
カメラシェイクを カメラシェイク セクションで定義できます。以下のように:
cameraShakes = {{startTime = 15, shake = "small", sustainDuration = 7, targets = emConfig.ShakeTargets.allPlayers, onServer = true},}
「ターゲット」は、イベントをトリガーしたプレイヤー、すべてのプレイヤー、またはプレイヤーInRadiusにのみ初期化できます。 We used a 3rd party script for camera shakes, and the shakes were pre-defined: eventManagerDemo.bigShake および eventManagerDemo.smallShake 。 sustainDuration
ミッションロジック
7つのミッションがあり、そのうち6つのみがシールを使用します。ほとんどのミッションは共通のパラメータを持ちますが、一部はシールとテレポートを使用して損傷した部屋にテレポートするミッションだけです。各ミッションには、DemoConfig スクリプトの入力に、Config.Missions マップの設定のセ
- ミッションルート : オブジェクトの非破損バージョンのフォルダ。
- ドア : プレイヤーがシールを持っているまでドアをロックします。
- SealName / SolvedSealName : 非破損のシール名と壊れたシール名。
- SealPlaceName : 印章を配置する場所。
- PlacedSealPlaceholderName : 印章を入れる場所のオブジェクト。
- TeleportPositionsName : プレーヤーが破損した部屋に移動するとき、または正常なエリアに戻すときのプレイヤーのテレポートポジションと回転を定義するフォルダの名前。 同じ名前は両方の場合に使用されます。
- CorruptRoomName : 破損した部屋の名前 (サーバーストレージに関連) дляCorruptRooms。 破損した部屋のクローンは TempStorage.Cloned で作成され、ミッション開始時に破壊されます。
- MissionCompleteButtonName : ミッションを即座に完了するためのチートボタン。これは デバッグ用途 です。
- CheatKey : 同じチートは、数字または Ctrl Shift [ナンバー] です。
ミッションのロジックの一部は、 GameStateManager スクリプト にあり、シールとドアはメインゲームフローを提供しますが、ミッションの特定のロジックは、 MissionsLogic および 0> MissionsLogicClient 0>
- ロックの鍵を使用する - ドアを開くための最初のミッション。このタイプは LockName 、KeyName によって定義されています。
- アイテムをマッチ中 - 4ミッションのアイテムに一致。このタイプは MatchItems によって定義されています。
- レイヤードな布を使用してマネキンをドレスアップする - 屋根裏にある 1つのミッションでは、3つのアイテムを集めるプレイヤーがいます。このタイプは DressItemsTagList によって定義されています。
- クリックしてアイテムを完了する - 1つのミッションは、ClickTargetName によって定義されています。
各ミッションタイプには、それぞれ StartMissionFunc と CompleteMissionFunc があります。ミッション機能
アイテムのロジックをマッチすると、 PuzzlePieceXX タグを持つアイテムと、 PuzzleSlotYY タグを持つアイテムの間で、「 使用 」(クリックしながら持っている)アイテムを使用
グラビング
オブジェクトをキャラクターの右腕に接続するための単純なグラビングシステムを開発しました。グラビングは GrabServer2
各フレームで、グラブアタイム が進行中かどうかをチェックします。reachDist 内のプレイヤーがある場合、ToolHoldAnim をプレイし始めます。2> maxGrabDistance2> 内のプレイヤーがある場合、クライアントはサーバーにリクエストを発行して、実際にモデルをグラ
サーバー側スクリプトには 2つのメイン機能があります:
- グラブ - モデルをグラブするためのクライアントのリクエストをハンドルします。
- リリース - グラビューモデルをリリースするリクエストを処理します。
各プレイヤーが持っている情報は、 playerInfos マップに保持されます。グラブ機能では、このモデルが他のプレイヤーによってすでにグラブされているかどうかをチェックします。如果そうなる場合 - クライアントに「EquipWorldFail」が送信され、グラブの試行をキャンセルします。
グラビングが許可されている場合、スクリプトは 2つの Attachments を作成します。1つは
GrabReleaseButton ボタンを HUD 画面GUI に接続すると、Connected 機能は、サーバーにイベントを発行します。サーバーで、Attachments と 1>Class.Limit|Limitations1> を処理し、