다음 시스템은 The Mystery of Duvall Drive에 대한 게임 플레이를 설정하는 데 기초가 된 시스템입니다.
게임 상태 관리자
게임 상태 관리자 / 게임 상태 클라이언트 일반적으로 경험에서 가장 복잡한 시스템이며, 다음을 처리합니다.
- 로비 내의 플레이어를 시작하고 그룹을 메인 게임 영역으로 순간이동하고 플레이어를 예약된 서버로 순간이동하는 카운트다운을 시작합니다.
- 복잡한 방을 클론하고, 비동기 스트림을 기다리고, 플레이어를 특정 지정된 CFrame 좌표로 텔레포트합니다.
- 메카닉 잡기 및 배치.
- 문 잠금 및 해제.
- 최종 순간 이동을 로비로 초기화하고 완성 씬을 플레이합니다.
우리는 간단한 상태 기계(Update 함수)로 구현했으며 상태는 DemoConfig (GameStatus 열거형)에 있습니다. 일부 상태는 초기 로비/예약된 서버 텔레포트처리하지만, 다른 상태는 미션을 찾고, 퍼즐을 트리거하고, 미션을 해결하는 것을 처리합니다. 잠금
GameStates 는 대부분 서버 사이에 있지만, 클라이언트가 수행해야 할 작업, 예를 들어 카운트다운을 표시하거나 로어 또는 스트리밍 중지 UI를 비활성화하는 경우, 서버와 클라이언트 (GameStatusClient) 는 원격 이벤트를 통해 통신합니다. 대부분의 경우 이벤트 작성에 이벤
순간이동 게임 상태
3가지 게임 상태 그룹이 있으며, 이는 순간이동을 손상된 방으로 숨기는 3가
스트리밍이 처리되는 동안 InFlight는 작은 흐륭한 화면을 유지하고 스트리밍
플레이어를 일반 상태의 방으로 순간이동하면 컬트 신호가 나타나고, TeleportWarmupBack, TeleportInFlightBack 및 TeleportCooldownBack ,
조명 및 대기 게임 상태
우리는 각 방의 일반적이고 �
문 상태 잠금
이벤트 관리자
이벤트 관리자 는 키 프레임을 사용하여 시간에 따라 "액션"을 실행할 수 있게 해 줍니다, 예를 들어:
- 인스턴스 속성 및 특성을 인터폴 합니다.Interpolating instance properties and attributes.
- 스크립트 실행.
- 오디오 재생.
- 카메라 진동 실행.
이 데모에서는 트랙 기반 UI를 사용하는 도구를 사용하지 않지만, 키 및 속성 이름을 수동으로 입력했습니다. 이벤트 관리자 시스템은 여러 개의 스크립트와 이벤트/함수를 포함하여 키 및 속성 이름을 수동으로 입력합니다.
- EventManager - 이벤트 생성 및 중지, 서버 사이드 작업에 대한 전반적인 로직.
- EventManagerClient - 클라이언트 사이드 액션.
- EventManagerModule - 서버와 클라이언트 사이의 모든 작업에 대한 공통 코드.
- EventManagerConfig - 몇 가지 명령 선언이 있는 작은 파일.
- EventManagerDemo - 이 데모의 모든 이벤트가 게임 스크립트에 정의됩니다.
- EventManagerEvent , EventManagerFunc - 클라이언트나 서버에서 이벤트를 실행하고 중지하는 원격 이벤트 및 바인딩 기능. 이는 다른 시스템이 이벤트를 설정하고 실행하고 중지하는 방법입니다.
이벤트에는 이름, 시작 또는 종료에 대한 옵션 정보, 실행 함수, 이벤트 매개 변수 및 이벤트 매개 변수가 있습니다. 이벤트 이름은 시작 또는 종료 시 실행할 스크립트를 지정하는 경우가 있습니다. 카메라 흔들림 및 플레이 오디오를 재생할 때 등록된 스크립트를 실행하는 경우도 있습니다.
인터플래시
이 기능을 사용하면 키 프레임 사이를 점프하지 않고 개체 속성 및 특성을 손쉽게 변경할 수 있습니다. 이 기능은 다음과 같은 시나리오에서 개체 정의
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}}}
이제 이벤트 섹션에서 매개 변수를 이벤트에 전달할 수 있으며, 이벤트 시작 스크립트는 기존 매개 변수를 변경하거나 "param" 테이블에 더 많은 매개 변수
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 를 사용했습니다. 이 중 후자는 이름별로 트리거를 찾습니다. 다른 트리거를 사용하여 동일한
이벤트 매개 변수
스크립트에서 사용자 지정 이벤트 매개 변수를 전달하는 것 외에도 이벤트를 생성할 때 옵션으로 지정할 수 있는 다른 데이터는 플레이어, 콜백(이벤트가 종료될 때 호출되는 콜백 포함), 콜백 매개 변수입니다. 일부 이벤트는 클라이언트에서 실행
이벤트는 minCooldownTime 및 maxCooldownTime 에 의해 정의된 대기 시간을 가질 수 있습니다. 미니 및 맥스는 플레이어 수에 따라 스케일
스크립트 호출
Class.Script|Scripts 를 스크립트 섹션의 특정 키 프레임에서 호출할 수 있습니다. 예를 들어:
scripts = {{startTime = 2, scriptName = "EnablePlayerControls", params = {true}, onServer = false }}
이전 예에서 PlayerControls Script는 이벤트 관리자 모듈에 등록해야 하는 것처럼 보입니다.
emModule.RegisterFunction("EnablePlayerControls", EnablePlayerControls)
클라이언트 스크립트에서 클라이언트에 대해 호출된 함수를 등록 함수라고 하고, 서버 스크립트에서 onServer = true 에 대해 호출된 함수를 서버 함수라고 합니다. 함수 자체는 이벤트 인스턴스 및 매개 변수를 전달하지만, 이 경우 단일 매개 변수만 전달됩니다.
local function EnablePlayerControls(eventInst, params)
오디오 재생
예를 들어 음향 효과 섹션의 키 프레임에서 위치 지정 오디오를 재생하는 것은 지원되지 않습니다.
sounds = {{startTime = 2, name = "VisTech_ethereal_voices-001"},}
이벤트 종료 콜백이 이벤트 기간이 만료될 때 발생하지만 오디오 작업은 여전히 재생될 수 있습니다.
카메라 흔들림 실행
카메라 진동을 카메라 진동 섹션에 정의할 수 있습니다.
cameraShakes = {{startTime = 15, shake = "small", sustainDuration = 7, targets = emConfig.ShakeTargets.allPlayers, onServer = true},}
“타겟”은 이벤트를 트리거한 플레이어, 모든 플레이어 또는 playersInRadius 에 대해서만 시작할 수 있습니다. 우리는 카메라 흔들림에 대한 3rd 파티 스크립트를 사용했으며, 흔들림은 미리 정의되었습니다: eventManagerDemo.bigShake
미션 로직
총 7개의 미션이 있으며, 6개 미션 중 6개만 인장을 사용합니다. 대부분의 미션에는 공통 매개 변수가 있지만, 일부는 잠금과 텔레포트를 사용하여 손상된 방을 복구하는 미션만 있습니다. 각 미션에는 DemoConfig 스크립트에 있는 매개 변수 집합이 포함된 하
- MissionRoot : 모든 비 손상 버전의 개체의 폴더.
- 문은 다른 플레이어가 봉인을 선택할 때까지 잠깁니다. Doors to lock until a player picks up a seal.
- SealName / SolvedSealName : 손상된 씰 및 손상된 씰 이름.
- SealPlaceName : 씰을 넣을 장소.
- PlacedSealPlaceholderName : 봉인할 장소에 대한 자리 표시자 개체.
- TeleportPositionsName : 플레이어가 손상된 방으로 이동하고 일반 영역으로 돌아할 때 순위를 정의하는 자리 표시자 메쉬 이름입니다. 두 경우 모두 동일한 이름을 사용합니다.
- CorruptRoomName : 손상된 방의 루트 폴더(ServerStorage에 대한 상대적인 이름)에 대한 손상된 방의 이름. 미션이 시작되면 임시 저장소에 클론되고 미션이 완료되면 파괴됩니다.
- MissionCompleteButtonName : 복죽 방에 있는 속임 버튼으로 즉시 미션을 완료합니다. 이것은 디버깅 목적입니다.
- 셰이트키 : 숫자 또는 CtrlShift[번호]와 동일한 셰이트입니다.
일부 미션 로직은 GameStateManager 스크립트에 있습니다, 씰과 문은 주요 게임 흐름을 제공하지만, 대부분의 미션에 대한 특정 로직은 MissionsLogic 및 MissionsLogicClient 스크립트에
- 도어를 열기 위한 열쇠 사용 - 첫 번째 문을 열기 위한 첫 번째 미션. 이 유형은 LockName , KeyName 에 의해 정의됩니다.
- 아이템 일치 - 4개의 미션이 아이템을 일치합니다. 이 유형은 MatchItems 에 의해 정의됩니다.
- 층이 있는 천을 사용하여 마네킹 복장 변경 - 맨 위층에 있는 플레이어는 3 개의 아이템을 수집합니다. 이 유형은 DressItemsTagList 에 의해 정의됩니다.
- 항목을 클릭하여 완료하기 - 1개의 미션이 이 입력정의합니다. ClickTargetName 에 의해 정의됩니다.
각 미션 유형에는 자체 StartMissionFunc 및 CompleteMissionFunc 가 있습니다. 시작 함수는 일반적으로 <
아이템 일치 논리는 아이템에 표시된 PuzzlePieceXX 태그를 가진 아이템을 "사용"(클릭하면서 누르고 있음)하여 일치하는 아이템을 찾을 수 있습니다. MatchItems 맵
가비지 수집
We developed a simple grabbing system for holding an object by attaching the object to the character's right arm. Grabbing is implemented in GrabServer2 and GrabClient 각 프레임에서 우리는 잡기 시도가 진행 중인지 확인합니다. 플레이어가 reachDist 내에 있으면 ToolHoldAnim 을 플레이합니다. 플레이어가 maxGrabDist 내에 있으면 클라이언트가 서버에 요청을 발생시켜서 실제로 모델을 1> per
서버 사이드 스크립트에는 2가지 주요 기능이 있습니다.
- 획득하기 - 클라이언트의 요청을 획득하기 위해 모델을 가져옵니다.
- 릴리스 - 잡은 모델을 릴리스하는 요청을 처리합니다.
각 플레이어가 가진 정보는 playerInfos 맵에 저장됩니다. 그리기 함수에서 우리는 이 모델이 다른 플레이어에 의해 이미 건축되었는지 확인합니다. 그렇다면 - Model 이 클라이언트에 보내고, 그리기 시도를 취소
만약 그립을 허용하면, 스크립트는 오른쪽 손에 있는 하나 그리고 클라이언트에서 패스된 그립
잡은 모델을 해제하려면 클라이언트 스크립트는 HUD 스크린 가이드에 있는 GrabReleaseButton 버튼에 연결합니다. Connected 함수는 서버에서 이벤트를 실행하고, 서버에서