Poniższe systemy były podstawą w tworzeniu gameplay'u, który chcieliśmy dla Tajemnicy Duvall Drive .
Menedżer państwa gry
GameStateManager / GameStateClient jest prawdopodobnie najbardziej skomplikowanym systemem w doświadczeniu, ponieważ zajmuje się:
- Począwszy graczy w lobby, rozpoczynając liczdownik teleportacji grupy do głównej gry, i teleportacji graczy na zarezerwowane serwery.
- Klonowanie uszkodzonych pokoi, przesyłanie ich równolegle i teleportowanie graczy do i z określonego przydzielonego CFrame koordynatu.
- Łapanie i umieszczanie mechanizmów uszczelnień.
- Zablokowanie i odblokowanie drzwi.
- Początkowa inicjatyzacja teleportacji do foyer i gra w końcowej scenie.
Zaimplementowaliśmy go jako prostą maszynę stanu (funkcję aktualizacji), a stanami są w DemoConfig (ensemblem GameStates). Niektóre stanowe deal with initial lobby / reserved server teleportować się, while others deal with finding a mission, triggering the puzzle, and solving the mission. Note that in addition to seals, we tried to not have mission-specific code in the GameStateManager.
GameStates jest w większości przypadków serwerem, ale gdy klient musi zrobić coś, na przykład pokazać licznik, zasady lub wyłączyć pauzę UI, serwer i klient (GameStateClient) komunikują się za pośrednictwem zdalnego wydarzenia zwanego GameStateEvent. W większości przypadków wartość parametru ma typ "wpisywać" (Config.GameEvents) jako pierwszy parametr, a następnie dane włas
Stany gry w teleportacji
Istnieje grupa 3 stany gry, które wykonują trzy unikalne cutscenen, które ukrywają teleportację do zniszczonego pokoju: Warm
Podczas gdy serwer przetwarza zapis, wtedy InFlight uruchdza się, utrzymując nieco pulsujący ciemny ekran. Gdy zarówn
Podobny zestaw cutscen z Warmup, InFlight i Cooldown następuje, gdy teleportujemy gracza do normalnego stanu pokoju, TeleportWarmupBack, TeleportInFlightBack i TeleportCooldownBack
Stany gry w oświetleniu i atmosferze
Wiedzieliśmy, że chcemy, aby każ
Zablokowanie drzwi - stan gry
Ch
Menedżer wydarzeń
EventManager pozwolił nam uruchomić "akcje" w czasie, wykorzystując klatki kluczowe, takie jak:
- Łączenie właściwości i cech instancji.
- Wykonanie skryptów.
- Odtwarzanie dźwięku.
- Kamera drga.
Idealnie używamy narzędzia z interfejsem opartym na ścieżce, ale dla tej demonstracji wpisaliśmy ręcznie klucze i nazwy właściwości. System EventManager składa się z kilku skryptów i funkcji wydarzenia, w tym:
- EventManager - ogólna logika tworzenia i zatrzymywania wydarzeń, a także działań serwera.
- EventManagerClient - działania strony klienta.
- EventManagerModule - Common code dla obu serwer i strony klienta.
- EventManagerConfig - Mały plik z kilkoma deklaracjami komend.
- EventManagerDemo - Gdzie wszystkie rzeczywiste wydarzenia dla tej demonstracji są zdefiniowane w grze w określonym skrypcie.
- EventManagerEvent , EventManagerFunc - zdalne wydarzenie i funkcja wiązania, aby uruchomić i zatrzymać wydarzenia z klienta lub serwera. To jest, jak inne systemy mogą ustawić, uruchomić i zatrzymać wydarzenia.
Każde wydarzenie ma nazwę, sekcję z opcjonalnymi informacjami o czasie odnowienia, funkcję do uruchomienia na początku lub na kończyć, parametry wydarzenia i sekcje z interpolantami (interpolowaniem dowolnej liczby właściwości lub atrybutów w ciągu czasu), skrypty (uruchomione rejestrowane skrypty na kluczowych klatkach) i grę w dźwięk.
Przerobienie
Interpolacja pozwala na swobodne zmienianie właściwości i atrybutów obiektu z jednej wartości na inną, zamiast skacznieć pomiędzy kluczowymi ramkami. Definiowaliśmy interpolator, aby zmienić różne efekty wizualne; na
interpolants = {objectParam = "TextLabel",property = "TextTransparency",keys = {{value = 1},{time = .5, value = 0},{time = 2.25, value = 0},{time = 3, value = 1}}}
Podczas gdy moglibyśmy zdefiniować, która właściwość lub atrybut obiektu należy do tego, jak w następującym przykładzie kodu, chcieliśmy, abyśmy mogli ponownie używać tych samych wydarzeń na różnych "grupach obiektów", aby umożliwić działanie z płynnością na klientach i z obiektami utworzonymi podczas uruchomienia.
object = workspace.SomeFolder.SomeModel
Aby to osiągnąć, pozwoliliśmy na referencję przez imię obiektu i przekazanie imienia parametru na rozpoczynaćwydarzenia. Aby znaleźć obiekty z imieniem, pozwoliliśmy określić korzeń dla wydarzenia, który pozwala na znalezienie obiektów z imieniem "Wander" gdzieś pod workspace.
params = {["RootObject"] = workspace.Content.Interior.Foyer["Ritual-DemoVersion"],},interpolants = {objectName = "Wander",attribute = "TimeScale",keys = {{value = 0.2}}}
Umożliwiliśmy przesuwanie parametrów do wydarzeń w sekcji parametrów, a skrypty uruchamiane na początku wydarzenia mogą zmieniać istniejące parametry lub dodawać więcej parametrów do tabeli parametrów. W następnym przykładzie mamy
params = {isEnabled = false},interpolants = {{objectName = "FocuserGlow",property = "Enabled",keys = {{valueParam = "isEnabled"}}}
Parametry pozwalają nam odnieść się do obiektów, które nie istnieją nawet na początku doświadczenia. Na przykład w następnym przykładzie kodu funkcja uruchomiona na początku wydarzenia stworzy obiekt, a ustawi BlackScreenObject wejścia w parametrach, aby wskazać na stworzony obiekt.
{objectParam = "BlackScreenObject",property = "BackgroundTransparency",keys = {{value = 0},{time = 19, value = 0},{value = 1},}}
Konfiguracja wydarzeń, instancji wydarzeń i połączenie z triggerami
Aby uruchomić wydarzenie, będziemy używać zdalnego wydarzenia z klientów lub funkcji z serwera. W następnym przykładzie przekazaliśmy kilka parametrów na RootObject i isEnabled wydarzenia. Wewnętrznie utworzono instancję opisu wydarzenia, parametry zostały rozwiązane na rzeczywistych obiektach, a funkcja zwróciła identyfikator dla instancja
local params = {RootObject = workspace.Content.Interior.Foyer["Ritual-DemoVersion"]["SealDropoff_" .. missionName],isEnabled = enabled}local eventId = eventManagerFunc:Invoke("Run", {eventName = "Ritual_Init_Dropoff", eventParams = params} )
Możemy zatrzymać uruchomienie wydarzenia, wysyłając funkcję „Stop”:
eventManagerFunc:Invoke("Stop", {eventInstId = cooldownId} )
Interpolants lub inne akcje, które są "kosmetyczne" (nie zmieniaj wymiaru symulacji dla wszystkich graczy), można wykonać na klientach, co może powodować gładkszą interpolację. W opisie wydarzenia możemy zapewnić domyślną wartość dla wszystkich akcji jako naServer = prawdziwy (bez niego domyślna jest klient). Każda akcja może go przeciągnąć poprzez ustawienie jej własnej naServer.
Aby łatwo połączyć uruchomienie wydarzenia z uruchomieniem triggera, użyliśmy funkcji pomocniczych ConnectTriggerToEvent lub ConnectSpawnedTriggerToEvent, z których ten drugi znajduje trigger według nazwy. Aby umożliwić tę samą wydarzenie, aby zostać ur
Parametry wydarzenia
Oprócz parametrów wydarzenia niestandardowych przekazanych z skryptów, inne dane, które można opcjonalnie przekazać podczas tworzenia wydarzenia, obejmują gracza, wzwanie (do zadania po zakończeniu wydarzenia), i wzwanie parametrów. Niektóre wydarzenia powinny być uruchomione tylko dla jednego gracza (zdarzenia z aktywnymi działaniami na klient), podczas gdy inne powinny
Wydarzenia mogą mieć okres regeneracji zdefiniowany przez minCooldownTime i maxCooldownTime. Min i max dostarczają zasięg do skalowania w zależności od liczby graczy, ale nie używaliśmy go w tym demonstracji. Jeś
Wywoływanie skryptów
Możemy nazwać Scripts na określonych kluczowych ramach w sekcji Skrypty . Na przykład:
scripts = {{startTime = 2, scriptName = "EnablePlayerControls", params = {true}, onServer = false }}
W poprzednim przykładzie EnablePlayerControls Script musiałby być zarejestrowany z modułem kierownika wydarzeń, tak jak w następujący sposób:
emModule.RegisterFunction("EnablePlayerControls", EnablePlayerControls)
Funkcja RegisterFunction musi być wezwana w skrypcie klienta dla funkcji wzywanych na klient, a w skrypcie serwera dla funkcji onServer = true. Funkcja ta sama otrzyma instancję zdarzeń i parametry, ale w tym przypadku jeden parametr zostanie przesłany z prawdziwą wartością.
local function EnablePlayerControls(eventInst, params)
Odtwarzanie dźwięku
Mamy ograniczoną pomoc dla gry w niepozycyjne audio na kluczowych ramach w sekcji Dźwięki , na przykład:
sounds = {{startTime = 2, name = "VisTech_ethereal_voices-001"},}
Uwaga: wezwania końcowe wydarzeń zakończą się, gdy czas trwania wydarzenia dobiegnie końca, ale działania audio mogą nadal odtwarzać się po tym czasie.
Kamera drga podczas uruchomienia
Możemy zdefiniować drżenie kamery w sekcji kameraShakes , tak jak w następujący sposób:
cameraShakes = {{startTime = 15, shake = "small", sustainDuration = 7, targets = emConfig.ShakeTargets.allPlayers, onServer = true},}
„targets” można zainicjować tylko dla gracza, który wywołał wydarzenie, allPlayer, lub playersInRadius do gracza, w którym wywołano wydarzenie. Użyliśmy 3-stronnego skryptu dla drgań kamery, i drgań były zapisane: eventManagerDemo.bigShake i eventManagerDemo.smallShake . sustainDuration</
Misje Logika
W sumie jest 7 misji, a tylko 6 z nich używa znaków. Większość misji ma wspólne parametry, choć niektóre tylko dla misji z znakami i teleportacją do uszkodzonych pokoi. Każda misja ma wejście w skryptie DemoConfig z ustawieniem parametrów w mapie Config.Missions :
- MissionRoot : Katalog wszystkich niezakorumpowanych wersji obiektów.
- Drzwi: : Drzwi do zablokowania, aż gracz podniesie pieczątkę.
- SealName / SolvedSealName : Niezależne nazwy pieczątki i zepsucie nazw pieczątki.
- SealPlaceName : Miejsce, w którym należy umieścić pieczątkę.
- PlacedSealPlaceholderName : Obiekt Placeholder w miejscu, aby umieścić pieczątkę.
- TeleportPositionsName : Nazwa katalogu z miejscemholderem, aby zdefiniować pozycje teleportu gracza i obroty, gdy się poruszasz do uszkodzonego pokoju i powrotu do normalnej obszarze. Ten sam nazwa jest używana w obu przypadkach.
- CorruptRoomName : Nazwy głównych katalogów korzeni (w stosunku do ServerStorage) dla zepsucia pokoi. Klony zepsucia pokoi podczas misji zostaną usunięte po zakończeniu misji.
- MissionCompleteButtonName : Przycisk oszustwa w zepsutych pokojach, aby natychmiastowo zakończyć misję. Jest to dla celów debugowania .
- CheatKey : Ta sama cheat jak liczba lub CtrlShift[Numer] .
Niektóre z logiczki misji jest w GameStateManager skryptach, ponieważ zapieczątki i drzwi zapewniają główny przepływ gry dla większości misji, ale większość logiki misji-specific jest w MissionsLogic i MissionsLogicClient skryptach, które okreś
- Użyj klucza na zamku - Pierwsza misja otwarcia drzwi. Ten typ jest zdefiniowany przez LockName , KeyName .
- Zgadiwanie przedmiotów - 4 misje zgadują przedmioty. Ten typ jest zdefiniowany przez MatchItems .
- Ubieranie manekinu używając warstwowego płótna - 1 misja na poddaszu ma graczy zbiera trzy przedmioty. Ten typ jest zdefiniowany przez DressItemsTagList .
- Kliknij na przedmiot, aby ukończyć - 1 misja ma ten wpisywać, który jest zdefiniowany przez ClickTargetName.
Każdy typ misji ma swoją własną StartMissionFunc i CompleteMissionFunc. Funkcja uruchamiana zwykle czytuje parametry z mapy
Logika dopasowywania pozwala na "używanie" (klikaj, gdy przytrzymujesz) przedmiotów oznaczonych PuzzlePieceXX tagami nad przedmiotami z PuzzleSlotXX tagiem. Są kilka dostępnych opcji jako parametrów w MatchItems mapie
Łapanie
Rozwinięliśmy prosty system chwytu dla trzymania obiektu poprzez przyczepienie obiektu do prawego r
Na każdym klatku sprawdzamy, czy próba chwytu jest w toku. Jeśli gracz jest w zasięgu ręki, zaczynamy grać ToolHoldAnim. Gdy gracz jest w maksymalnym zasięgu ręki, kliент wysyła prośbę do serwera, aby właściwie złapać model (funkcja 2> paramètres).
Skrypt strony serwera ma 2 główne funkcje:
- Chwytuj - Przyjmuje prośbę klienta o chwytanie modelu.
- Wypuść - Przyjmuje zapis w wersji gry w wersji gry.
Informacje o tym, co każdy gracz trzyma, są utrzymywane w mapie playerInfos . W funkcji grabu sprawdzamy, czy ten model jest już chwycony przez innego gracza. Jeśli tak - wysyłany jest "EquipWorldFail" do klienta, a anuluje podejmować próbęgrabienia. Uwaga, że musieliśmy zaradzić sytuacjom, w których gracze grabią różne czę
Jeśli można go chwyć, skrypt tworzy dwa Attachments, jeden na ręce prawnej i jeden na obiekcie używając prz
Aby uwolnić uchwycony model, skrypt klienta połączy się z przyciskiem GrabReleaseButton w HUD ScreenGUI. Funkcja Connected wysyłuje wydarzenie na serwer. Na serwerze, uwolnij usuwa Attachments i