W tej sekcji zaprezentowano, w jaki sposób określić i dostosować drużyny i klasy dla graczy.
Używane urządzenia:
-
2 x kreator klas
-
2 x wybieracz klas
Ustawienia i ekwipunek drużyny
Użyj urządzeń ustawień i ekwipunku drużyny, aby ustawić nazwy drużyn i kolory do wyświetlania na tablicy wyników.
Umieść po jednym urządzeniu dla każdej drużyny w miejscu niewidocznym dla graczy. Aby skonfigurować drużynę rekwizytów, należy ustawić Opcje użytkownika zgodnie z poniższą tabelą.
| Opcja | Wartość | Wyjaśnienie |
|---|---|---|
| Nazwa drużyny | Rekwizyty | Określa ciąg znaków identyfikujący drużynę na tablicy wyników oraz elementach interfejsu w grze. |
| Kolor drużyny | Lazurowy | Przypisuje kolor, którym wybrana drużyna będzie zaznaczana na tablicy wyników, w interfejsie w grze oraz w niektórych urządzeniach. |
| Drużyna | Indeks drużyny: 1 | Określa, której drużyny dotyczą ustawienia tego urządzenia. |
Aby skonfigurować drużynę łowców, należy ustawić Opcje użytkownika drugiego urządzenia zgodnie z poniższą tabelą.
| Opcja | Wartość | Wyjaśnienie |
|---|---|---|
| Nazwa drużyny | Łowcy | Określa ciąg znaków identyfikujący drużynę na tablicy wyników oraz elementach interfejsu w grze. |
| Kolor drużyny | Pomarańczowy | Przypisuje kolor, którym wybrana drużyna będzie zaznaczana na tablicy wyników, w interfejsie w grze oraz w niektórych urządzeniach. |
| Drużyna | Indeks drużyny: 2 | Określa, której drużyny dotyczą ustawienia tego urządzenia. |
Kreator klas
Użyj kreatora klas, aby zmodyfikować utworzone drużyny.
Umieść dwa urządzenia kreatora klas, po jednym dla każdej drużyny, w obszarze niewidocznym dla graczy. Aby dostosować drużynę rekwizytów, skonfiguruj Opcje użytkownika zgodnie z poniższą tabelą.
| Opcja | Wartość | Wyjaśnienie |
|---|---|---|
| Nazwa klasy | Rekwizyt | Określa nazwę tej klasy. |
| Opis klasy | Ukryj się przed łowcami. Przetrwaj. | Ustawia opis tej klasy. |
| Identyfikator klasy | Slot klasy: 1 | Ustawia unikatowy identyfikator dla tej klasy. |
| Maks. zdrowie | 1 | Określa maksymalny poziom zdrowia graczy podczas gry. Rekwizyty będą likwidowane jednym trafieniem. |
| Lista przedmiotów | Rekwizytomat | Ustawia listę przedmiotów, które ta klasa będzie posiadać. |
| Wyposaż przyznany przedmiot | Pierwszy przedmiot | Określa, który przedmiot z listy zostanie przyznany. |
Aby dostosować drużynę łowców, skonfiguruj Opcje użytkownika dla drugiego urządzenia zgodnie z poniższą tabelą.
| Opcja | Wartość | Wyjaśnienie |
|---|---|---|
| Nazwa klasy | Łowca | Określa nazwę tej klasy. |
| Opis klasy | Znajdź rekwizyty. Zlikwiduj ich. | Ustawia opis tej klasy. |
| Identyfikator klasy | Slot klasy: 2 | Ustawia unikatowy identyfikator dla tej klasy. |
| Lista przedmiotów | Pistolet z latarką | Ustawia listę przedmiotów, które ta klasa będzie posiadać. |
| Wyposaż przyznany przedmiot | Pierwszy przedmiot | Określa, który przedmiot z listy zostanie przyznany. |
Wybieracz klas
Połącz kreator klas z wybieraczem klas, aby zarządzać niestandardowymi klasami i drużynami, które tworzysz.
Wraz z Verse, ustawienia z tego urządzenia powodują, że gracze na slocie klasy 1 są przenoszeni na slot klasy 2 po respawnie.
Umieść dwa wybieracze klas, po jednym dla każdej drużyny, w obszarze niewidocznym dla graczy. Aby zarządzać drużyną rekwizytów, użyj ustawień z poniższej tabeli, aby skonfigurować Opcje użytkownika dla tego urządzenia.
| Opcja | Wartość | Wyjaśnienie |
|---|---|---|
| Zmiana na klasę | Slot klasy: 1 | Określa klasę, którą powinien otrzymać gracz. |
| Widoczność podczas gry | False | To urządzenie nie będzie widoczne w trakcie gry. |
| Dźwięk strefy | False | Określa, czy wybieracz klas ma odtwarzać efekty dźwiękowe, gdy gracze wchodzą do strefy. |
| Zmiana na drużynę | Indeks drużyny: 1 | Określa drużynę, do której trafi gracz. |
| Wyczyść przedmioty po zmianie | True | Określa, czy przedmioty mają zostać usunięte z ekwipunku gracza po zmianie. |
| Widoczność przestrzeni podczas gry | False | Określa, czy przestrzeń urządzenia ma być widoczna podczas gry. |
| Wyświetlaj efekty wizualne przy aktywacji | False | Określa, czy to urządzenie ma tworzyć efekt wizualne przy zmianie klasy lub drużyny gracza. |
Aby zarządzać drużyną łowców, użyj ustawień z poniższej tabeli w celu skonfigurowania Opcji użytkownika dla tego urządzenia.
| Opcja | Wartość | Wyjaśnienie |
|---|---|---|
| Zmiana na klasę | Slot klasy: 2 | Określa klasę, którą powinien otrzymać gracz. |
| Zmiana na drużynę | Indeks drużyny: 2 | Określa drużynę, do której trafi gracz. |
Tworzenie funkcjonalności drużyny za pomocą Verse
W grze Chowany-przebierany udział biorą dwie drużyny: Łowcy i rekwizyty. Musisz być w stanie robić niektóre z tych samych rzeczy dla obu drużyn, aby gra działała. Na przykład:
-
dodawanie gracza do drużyny
-
usuwanie gracza z drużyny
-
wyświetlanie graczom informacji o ich drużynie
Aby stworzyć tę funkcjonalność dla obu drużyn bez powielania kodu, należy utworzyć klasę ze specyfikatorem <abstract>. Klasy ze specyfikatorem abstract są przeznaczone do posiadania częściowej funkcjonalności, którą ich podklasy dziedziczą i na której bazują. Najpierw należy utworzyć klasę abstrakcyjną o nazwie base_team i nadać jej funkcjonalność, którą będą współdzielić drużyny rekwizytów i łowców.
Ten dokument zawiera fragmenty Verse, które pokazują, jak wykonać mechanikę rozgrywki wymaganą w tej rozgrywce. Wykonaj poniższe instrukcje i skopiuj pełny skrypt w kroku 6 tego samouczka.
Utwórz nowy plik Verse w swoim projekcie o nazwie base_team.verse. Nie będzie to urządzenie Verse, więc można je utworzyć jako pusty plik Verse.
using { /Fortnite.com/Characters }
using { /Fortnite.com/Devices }
using { /Fortnite.com/UI }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /UnrealEngine.com/Temporary/UI }
using { /Verse.org/Colors }
using { /Verse.org/Simulation }
log_team := class(log_channel){}
# Ta klasa definiuje urządzenia potrzebne różnym drużynom podczas rozgrywki.
# Ta klasa jest abstrakcyjna, więc nie może być używana samodzielnie. Musi być dziedziczona przez inną klasę.
base_team := class<abstract>:
Logger:log = log{Channel:=log_team}
@editable # Używane do przypisania gracza do drużyny.
ClassSelector:class_and_team_selector_device = class_and_team_selector_device{}
@editable # Używane do przyznawania punktów agentom w drużynie.
ScoreManager:score_manager_device = score_manager_device{}
@editable # Używane do wyświetlania tytułu zadania drużyny.
TeamTitle:hud_message_device = hud_message_device{}
@editable # Używane do wyświetlania opisu zadania drużyny.
TeamDescription:hud_message_device = hud_message_device{}
@editable # Używane do subskrybowania zdarzeń likwidacji członków drużyny (drużyna rekwizytów) lub wrogów (drużyna łowców).
TeamManager:team_settings_and_inventory_device = team_settings_and_inventory_device{}
# Jest to tablica agentów w drużynie.
var TeamAgents<private>:[]agent = array{}
# To zdarzenie jest sygnalizowane, gdy tablica TeamAgents staje się pusta (sygnalizując koniec rundy).
TeamEmptyEvent:event() = event(){}
# Zwraca bieżącą tablicę TeamAgents.
# Jest to wymagane, ponieważ tablica TeamAgents jest prywatna, więc inne klasy nie mogą uzyskać do niej bezpośredniego dostępu.
GetAgents()<decides><transacts>:[]agent =
TeamAgents
# Zwraca rozmiar tablicy TeamAgents
# Wymaga to funkcji, ponieważ tablica TeamAgents jest prywatna, więc inne klasy nie mogą uzyskać do niej bezpośredniego dostępu.
Count()<transacts>:int =
TeamAgents.Length
# Zwraca indeks agenta w tablicy TeamAgents, w przeciwnym razie zawodzi.
FindOnTeam(Agent:agent)<decides><transacts>: int =
Index := TeamAgents.Find[Agent]
# Ustaw agenta w drużynie i powiadom o tym gracza.
InitializeAgent(Agent:agent):void =
AddAgentToTeam(Agent)
ClassSelector.ChangeTeamAndClass(Agent)
DisplayTeamInformation(Agent)
# Dodaj agenta do TeamAgents.
AddAgentToTeam(AgentToAdd:agent):void =
if (not FindOnTeam[AgentToAdd]):
Logger.Print("Dodawanie agenta do drużyny.")
set TeamAgents += array{AgentToAdd}
# Aktywuje urządzenia komunikatów w interfejsie, aby pokazać graczowi, w której drużynie się znajduje
DisplayTeamInformation(Agent:agent):void =
TeamTitle.Show(Agent)
TeamDescription.Show(Agent)
# Gdy agent opuści mecz, usuń go z tablicy TeamAgents i sprawdź, czy runda dobiegła końca.
EliminateAgent(Agent:agent)<suspends>:void =
Sleep(0.0) # Opóźnienie o 1 tyknięcie gry, aby upewnić się, że gracz respawnował się przed kontynuowaniem.
RemoveAgentFromTeam(Agent)
# Usuń agenta z TeamAgents.
# Jeśli usunięty agent był ostatnim, zasygnalizuj TeamEmptyEvent.
RemoveAgentFromTeam(AgentToRemove:agent):void =
set TeamAgents = TeamAgents.RemoveAllElements(AgentToRemove)
Logger.Print("Pozostała liczba agentów w drużynie: {Count()}.")
if (Count() < 1):
Logger.Print("Brak agentów w drużynie. Kończenie rundy.")
TeamEmptyEvent.Signal()
Teraz, gdy ta klasa jest już gotowa, można utworzyć klasy dla drużyny rekwizytów i drużyny łowców. Ponieważ każda z nich dziedziczy po base_team, ma to kilka zalet:
-
Kod do implementacji każdej drużyny jest znacznie krótszy, ponieważ mają one już swoje wspólne funkcje i dane zdefiniowane w
base_team. -
Łatwiej jest zrozumieć, który kod jest specyficzny dla drużyny rekwizytów i łowców, ponieważ znajdują się one w swoich własnych klasach, zamiast być wymieszane ze wspólnym kodem.
-
Dodanie większej liczby drużyn do trybu gry jest znacznie łatwiejsze. Każda nowa drużyna dziedziczy po
base_team, a kod, który sprawia, że nowa drużyna jest inna, znajduje się w jej własnej klasie.
Należy pamiętać, że nie można utworzyć instancji klasy ze specyfikatorem <abstract>. Należy utworzyć klasę dziedziczącą po klasie abstrakcyjnej i utworzyć jej instancję.
Drużyna łowców
Najpierw utwórz klasę dla drużyny łowców. W swoim projekcie utwórz nowy plik Verse o nazwie hunter_team.verse. Nie będzie to urządzenie Verse, więc można je utworzyć jako pusty plik Verse.
Zadeklaruj klasę o nazwie hunter_team. Powinna ona być <concrete> i dziedziczyć po base_team.
hunter_team := class<concrete>(base_team):
Utworzenie klasy <concrete> oznacza, że wszystkie pola tej klasy muszą mieć wartość domyślną. Patrz Specyfikatory i atrybuty, aby dowiedzieć się więcej.
Poniżej znajduje się pełny kod skryptu hunter_team.verse.
Klasa hunter_team posiada dwie funkcje o takich samych nazwach jak funkcje w klasie base_team. Jest to dozwolone, ponieważ obie mają specyfikator <override>. Oznacza to, że gdy te funkcje są wywoływane na instancji hunter_team, używana jest wersja z klasy hunter_team.
Na przykład, w poniższym kodzie użyta zostanie wersja InitializeAgent() zdefiniowana w hunter_team, ponieważ zastępuje ona funkcję o tej samej nazwie w base_team. Porównaj to z wywołaniem Count(), które użyje wersji zdefiniowanej w base_team, ponieważ nie ma funkcji nadpisującej.
HunterTeam:hunter_team = hunter_team{}
# Używa funkcji z hunter_team
HunterTeam.InitializeAgent(StartingHunterAgent)
# Używa funkcji z base_team
HunterTeam.Count()
Dwie nadpisane funkcje również używają (super:). Pozwala im to na wywołanie wersji funkcji zdefiniowanych w base_team, ponieważ base_team jest nadklasą hunter_team. W przypadku InitializeAgent() i EliminateAgent(), oba używają Logger.Print() by wydrukować coś w dzienniku. Następnie wywołują odpowiednie funkcje z base_team. Oznacza to, że funkcje działają dokładnie tak samo, jak wersje w base_team, z wyjątkiem wywołań Logger.Print().
Patrz podklasa, aby dowiedzieć się więcej o <override> i (super:)
Drużyna rekwizytów
Teraz należy utworzyć klasę dla drużyny rekwizytów. W projekcie utwórz nowy plik Verse o nazwie prop_team.verse. Nie będzie to urządzenie Verse, więc można je utworzyć jako pusty plik Verse.
Musisz zarządzać więcej dla członków drużyny rekwizytów. Mają efekty bicia serca, które muszą być uruchamiane i zatrzymywane w oparciu o licznik czasu i to, jak daleko się poruszają. Muszą również zostać przeniesieni do drużyny łowców, gdy zostaną zlikwidowani.
Aby zarządzać członkami drużyny rekwizytów, użyj metody RunPropGameLoop(). Metodę tę można traktować jako menadżera całej podróży rekwizytu przez grę. Od momentu spawnu do momentu likwidacji lub opuszczenia gry, metoda ta będzie działać dla każdego członka drużyny rekwizytów.
# Jeśli agent rekwizytów przestanie się poruszać, użyj wyrażenia race, aby sprawdzić, czy agent rekwizytów poruszy się poza MinimumMoveDistance, licznik czasu bicia serca zostanie zakończony lub agent rekwizytów zostanie zlikwidowany.
RunPropGameLoop(PropAgent:agent)<suspends>:void =
Logger.Print("Uruchamianie pętli gry agenta rekwizytów.")
# Wykonuj pętlę w nieskończoność przez zachowanie rekwizytów, aż agent rekwizytów zostanie zlikwidowany lub gracz opuści sesję.
race:
PropAgent.AwaitNoLongerAProp()
loop:
# Poczekaj, aż agent rekwizytów przemieści się na odległość mniejszą niż minimalna, a następnie przejdź dalej.
PropAgent.AwaitStopMoving(MinimumMoveDistance)
# Dopóki agent rekwizytów nie przesunie się poza minimalną odległość, odliczaj do bicia serca, a następnie odtwarzaj bicie serca w nieskończoność.
race:
PropAgent.AwaitStartMoving(MinimumMoveDistance)
block:
CountdownTimer(PropAgent)
PropAgent.StartHeartbeat()
Sleep(0.0) # Gdy wyścig dobiegnie końca (agent rekwizytów poruszy się), uruchom pętlę ponownie.
RunPropGameLoop() ma jeden parametr, PropAgent. Jest to stała reprezentująca gracza w drużynie rekwizytów. Posiada również specyfikator <suspends>, co oznacza, że ukończenie wymaga czasu. W tym przypadku nie zakończy się, dopóki przekazany PropAgent nie przestanie być w drużynie rekwizytów.
Cała funkcjonalność tej metody jest zawarta w wyrażeniu race. Oznacza to, że metoda nie zostanie ukończona, dopóki jedno z wyrażeń w ramach tego wyrażenia race nie zostanie ukończone. Te wyrażenia to:
-
PropAgent.AwaitNoLongerAProp() -
loop
Wyrażenie loop w tym wyrażeniu race nigdy się nie kończy. Celowo jest nieskończone. Oznacza to, że AwaitNoLongerAProp() jest metodą, która zawsze wygra wyścig i ukończy metodę. Używanie wyrażenia race w ten sposób jest jak mówienie programowi, aby uruchamiał określony zestaw kodu w kółko, aż coś się stanie. Patrz race, aby dowiedzieć się więcej o tym potężnym wyrażeniu.
Z tym kodem, AwaitNoLongerAProp() wygrywa wyścig.
# Wykonuj pętlę do momentu, gdy agent rekwizytów przestanie być częścią tablicy PropAgents. Usunięcie następuje, gdy agent rekwizytów zostanie zlikwidowany i zamieniony w łowcę lub gdy gracz opuści sesję.
(PropAgent:agent).AwaitNoLongerAProp()<suspends>:void =
loop:
if (not FindOnTeam[PropAgent]):
Logger.Print("Usuwanie zachowania agenta rekwizytów.")
break
Sleep(0.0) # Przejdź do następnego tyknięcia gry.
Ta metoda stale sprawdza, czy PropAgent jest w drużynie rekwizytów. Zaczyna się od pętli, która działa do momentu, aż not FindOnTeam[PropAgent] się powiedzie, a następnie przerywa, kończąc metodę. Zobacz Pętla i przerwa, aby dowiedzieć się więcej na ich temat.
FindOnTeam[] jest funkcją z możliwością niepowodzenia, która jest zadeklarowana w base_team. Zakończy się powodzeniem, jeśli PropAgent zostanie znaleziony w drużynie rekwizytów. Ale musisz użyć operatora not, ponieważ chcesz wyjść z pętli tylko wtedy, gdy PropAgent nie zostanie znaleziony w drużynie rekwizytów. Zobacz Operatory, aby dowiedzieć się więcej o operatorze not.
Ostatnim krokiem jest dodanie Sleep(0.0) na końcu pętli. Gwarantuje to, że pętla zostanie uruchomiona raz, a następnie przejdzie do następnej aktualizacji symulacji. Nie trzeba uruchamiać tego sprawdzenia częściej, więc dodano Sleep(0.0), aby zwiększyć wydajność. Więcej informacji można znaleźć na stronie przewodnika po interfejsie API Verse dla funkcji Sleep.
Teraz, gdy wiesz już jak działa AwaitNoLongerAProp(), możesz napisać nieskończoną pętlę, która ściga się z nią w RunPropGameLoop().