W grach wieloosobowych drużyny graczy współzawodniczą lub współpracują, aby osiągnąć jakiś cel. Liczba graczy w każdej drużynie może mieć decydujący wpływ na rozgrywkę. Wielu twórców wybiera konkretny stosunek liczby graczy, aby przygoda z grą była bardziej wciągająca.
Równoważenie drużyn przydziela graczy do drużyn według zadanego stosunku. W większości gier wieloosobowych gracze są przydzielani po równo, aby żadna drużyna nie miała przewagi. W niektórych grach proporcje liczby graczy są celowo nierówne, np. wystawianie czwórki graczy przeciwko jednemu graczowi o znacznie większych mocach, z lepszym wyposażeniem itp. Niezależnie od konfiguracji, równowaga drużyny ma decydujące znaczenie przy tworzeniu lepszych, fascynujących przygód dla wieloosobowych drużyn.
Po ukończeniu tego samouczka dowiesz się, jak dynamicznie równoważyć drużyny graczy w trakcie gry oraz za każdym razem, gdy dołączy nowy gracz. Do celów odniesienia, na końcu tego przewodnika znajduje się kompletny skrypt.
Używane funkcje języka Verse
array: To urządzenie używa tablic do przechowywania odwołania do każdej drużyny.
option: To urządzenie używa opcji, aby określić, czy istnieje drużyna, w której jest mniej graczy niż w drużynie, w której jest aktualnie dany gracz.
for: Wyrażenie for umożliwia iterację po tablicach używanych przez urządzenie.
if: Wyrażenie if służy do sprawdzania, czy gracze powinni zostać przeniesieni do nowej drużyny na podstawie wielkości drużyn.
failure: Konteksty niepowodzenia wykorzystuje się w celu uzyskania dostępu do tablic oraz sterowania przepływem programu.
Używane interfejsy API Verse
Subskrybowalne: Będziesz subskrybować
PlayerAddedEvent(), aby dynamicznie zmieniać równowagę drużyn, gdy do trwającej gry dołączy nowy gracz.Drużyny: Klasa drużyn umożliwia dodawanie graczy do drużyn oraz ich usuwanie i pobieranie. W samouczku będziesz używać klasy drużyny, aby bezpośrednio manipulować graczami i ich przypisaniem do drużyny.
Przestrzeń gry: Przestrzeń gry pozwala śledzić zdarzenia, które można subskrybować, związane z dołączaniem graczy do gry oraz opuszczaniem gry przez graczy. Obsługuje też pobieranie list graczy i drużyn oraz znajdowanie drużyny dla danego gracza. W tym samouczku zasubskrybujesz wiele zdarzeń przestrzeni gry oraz pobierzesz graczy i drużyny przy użyciu metod przestrzeni gry, aby nimi bezpośrednio manipulować.
Ustawianie poziomu
W tym przykładzie wykorzystano następujące urządzenie.
4 x urządzenie Panelu startowego gracza: To urządzenie określa, w którym miejscu na początku gry spawnuje się gracz.
Postępuj zgodnie z poniższą instrukcją, aby skonfigurować swój poziom:
Dodaj do poziomu Panel startowy gracza.
W Outlinerze wybierz panel startowy, aby otworzyć dla niego panel Szczegóły.
W Opcjach użytkownika w panelu Szczegóły:
W pozycji Drużyna graczy wybierz opcję Indeks drużyny i ustaw dla niej wartość 1
Włącz Widoczność podczas gry
Kliknij obraz, aby go powiększyć.
Zduplikuj panel startowy i umieść go obok pierwszego panelu startowego.
Zduplikuj oba panele startowe i umieść je w dalszej odległości od pierwszej grupy paneli startowych. W tym miejscu będą się spawnowali gracze z Drużyny 2.
Wybierz zduplikowane panele startowe. W panelu Szczegóły, w Opcjach użytkownika zmień wartość Indeks drużyny na 2 dla obu paneli.
W Outlinerze wybierz urządzenie Ustawienia wyspy, aby otworzyć jego panel Szczegóły. W sekcji Opcje użytkownika – zasady gry:
W pozycji Drużyny wybierz opcję Indeks drużyny i ustaw dla niej wartość 2. W tym przykładzie używa się dwóch drużyn, ale możesz ich ustawić tyle, ile chcesz.
W pozycji Liczebność drużyn wybierz ustawienie Dynamiczna. Dzięki temu kod Verse może przejąć zadania równoważenia drużyn.
W pozycji Dołączanie w toku wybierz ustawienie Spawn, aby nowi gracze mogli dołączać do gry w trakcie jej trwania.
Kliknij obraz, aby go powiększyć.
Utwórz nowe urządzenie Verse o nazwie team_multiplayer_balancing za pomocą Eksploratora Verse i przeciągnij je do poziomu. (Aby dowiedzieć się, jak utworzyć nowe urządzenie w Verse, patrz: Tworzenie własnego urządzenia przy użyciu Verse).
Poziom powinien wyglądać mniej więcej następująco:
Rozdzielanie drużyn po równo
Równoważenie drużyn na początku gry
Ten krok pokazuje, jak rozdzielić graczy po równo na początku gry oraz gdy dołączy nowy gracz.
Otwórz Eksplorator Verse i kliknij dwukrotnie team_multiplayer_balancing.verse, aby otworzyć skrypt w Visual Studio Code.
W definicji klasy
team_multiplayer_balancingdodaj tablicę zmiennychteamo nazwieTeams, będzie ona przechowywała odwołania do każdej drużyny, w której są gracze.Verseteam_multiplayer_balance := class(creative_device): # Holds the teams found with GetTeams() var Teams : []team = array{}W funkcji
OnBegin()zaktualizuj tablicęDrużyn, aby pasowała do drużyn skonfigurowanych wcześniej w Ustawieniach wyspy. Wywołaj funkcjęGetTeams()z interfejsu APIfort_team_collection, aby pobrać wszystkie drużyny w przestrzeni gry.VerseOnBegin<override>()<suspends>:void= Print("Verse Device Started!") set Teams = Self.GetPlayspace().GetTeamCollection().GetTeams()Znajdź wszystkich graczy w grze, wywołując funkcję
GetPlayers(), i zapisz ich w tablicy graczy o nazwieAllPlayers.VerseOnBegin<override>()<suspends>:void= Print("Verse Device Started!") set Teams = Self.GetPlayspace().GetTeamCollection().GetTeams() AllPlayers := GetPlayspace().GetPlayers()Przeiteruj przez listę wszystkich graczy i utwórz drużyny o tej samej liczbie graczy. Drużynę, w której jest obecnie gracz, porównasz z innymi drużynami i określisz, czy najbardziej pasuje ona do danego gracza. W tym przypadku za pomocą
GetTeam[]możesz użyć drużyny, do której gracz na początku gry jest automatycznie przypisywany (ponieważ w grach z wieloma drużynami gracz musi należeć do jakiejś drużyny). Pamiętaj, żeGetTeam[]wymaga agenta typu jako parametru, ale gracz jest podklasą agenta, dlatego możesz przekazać gracza bez rzutowania typu.VerseAllPlayers := GetPlayspace().GetPlayers() for (TeamPlayer : AllPlayers, CurrentTeam := GetPlayspace().GetTeamCollection().GetTeam[TeamPlayer]): # Assign Players to a new team if teams are unbalancedDrużyna jest klasą wewnętrzną, dlatego nie można jej zainicjować. Można jej używać tylko jako odniesienia do istniejącego obiektu drużyny.
Chcesz przypisywać graczy do drużyny, w której jest najmniej graczy, aż wszystkie drużyny będą zrównoważone. W tym celu musisz sprawdzić każdego gracza, a potem każdą drużynę za pomocą pętli
for. Możesz użyć dwóch pętli, jednej do iterowania przez graczy, a drugiej do iterowania przez drużyny, ale w tym przykładzie wyodrębnisz drużynę, aby weszła do pętli własnej metody. Utwórz gracza dla pętli, uzyskując odwołanie do każdego gracza, a następnie odwołanie do każdej drużyny, w której są gracze, w stałej o nazwieCurrentTeam.Utwórz nową zmienną liczby całkowitej
TeamSizei zainicjuj ją z wartością0, następnie ustaw ją tak, aby była równa liczebności drużyny, do której aktualnie należy gracz. WyrażenieGetAgents[]może się zakończyć niepowodzeniem, więc musisz zamknąć to ustawienie w instrukcji if.Versefor (TeamPlayer : AllPlayers, CurrentTeam := GetPlayspace().GetTeamCollection().GetTeam[TeamPlayer]): # Assign Players to a new team if teams are unbalanced var TeamSize : int = 0 if(set TeamSize = GetPlayspace().GetTeamCollection().GetAgents[CurrentTeam].Length): Print("Size of this player's starting team is {TeamSize}")Utwórz metodę o nazwie
FindSmallestTeam(). Po przekazaniu jejTeamSizejako argumentu, zwróci ona opcjonalną drużynę (?team) i obsłuży znalezienie i zwrócenie drużyny, w której jest najmniej graczy. Zainicjuj nową opcję drużyny o nazwieSmallestTeamwewnątrzFindSmallestTeam(). W tym miejscu użyjesz opcji, ponieważ w momencie wywołaniaFindSmallestTeam()gracz może już należeć do najmniejszej drużyny.Domyślnie twoja opcja
SmallestTeamma wartość false i pozostaniefalse, jeśli nie zostanie znaleziona mniejsza drużyna. GdyFindSmallestTeam()zwrócifalse, wiesz na pewno, że gracz należy do najmniejszej drużyny. Musisz też zainicjować zmienną typu całkowitegoCurrentTeamSizena wartośćTeamSize.CurrentTeamSizemusi być zmienną, aby można ją było uaktualnić do liczebności innej znalezionej najmniejszej drużyny.VerseFindSmallestTeam(CurrentTeamSize : int) : ?team= var SmallestTeam : ?team = false var TeamSize : int = CurrentTeamSizePonieważ
TeamSiześledzi liczebnośćSmallestTeam, musisz ją porównać z liczebnością każdej drużyny. Przeiteruj przez każdą drużynę i pobierz jej liczebność do lokalnej zmiennej typu całkowitegoCandidateTeamSize. JeśliCandidateTeamSizejest mniejsza niżTeamSize, ustawSmallestTeamna tę drużynę, aTeamSizena liczebność tamtej drużyny.Warunek
TeamSize > CandidateTeamSizeto warunek filtra, ponieważ jest sprawdzany w nawiasach pętli for. Zastosowanie warunku filtra gwarantuje, że kod w pętli wykona się tylko, gdy warunek filtra zostanie spełniony. To gwarantuje, żeSmallestTeamzostanie ustawiona na drużynę, w której jest najmniej graczy, o ile taka drużyna zostanie znaleziona. Jeśli nie znajdzie się drużyna, w której jest mniej graczy,SmallestTeambędzie miała dalej wartość false.Na koniec zwróć wartość
SmallestTeampo sprawdzeniu wszystkich drużyn.Versefor(Team : Teams, CandidateTeamSize := GetPlayspace().GetTeamCollection().GetAgents[Team].Length, TeamSize > CandidateTeamSize): set SmallestTeam = option{Team} set TeamSize = CandidateTeamSize Print("Found a team with less players: {CandidateTeamSize}") return SmallestTeamW
OnBegin()utwórz nową opcję drużyny o nazwieSmallestTeamwewnątrz pętlifori zainicjuj ją wartościąFindSmallestTeam(), przekazującTeamSizejako argument.VerseSmallestTeam : ?team = FindSmallestTeam(TeamSize)Następnie spróbuj uzyskać dostęp do wartości w opcjonalnej zmiennej
SmallestTeam. Jeśli wartość to false, gracz jest już w najmniejszej drużynie i nie trzeba wykonywać przypisania. W przeciwnym razie przypisz gracza do nowej drużyny. Wiele metod nie pozwala nam na bezpośrednie przekazywanie opcji jako argumentu, dlatego musisz wyodrębnić wartość do lokalnej zmiennejTeamToAssign. Możesz spróbować przypisać gracza do tej drużyny przy użyciuAddToTeam[player, team]. Zwróć uwagę, że to przypisanie się nie uda, jeśli spróbujesz przypisać gracza do drużyny, do której już należy. Nie będzie to miało żadnych negatywnych konsekwencji, ponieważ pętlaforpo prostu przejdzie do kolejnego gracza, a pierwszego zostawi w oryginalnej drużynie.Verseif (TeamToAssign := SmallestTeam?, GetPlayspace().GetTeamCollection().AddToTeam[TeamPlayer, TeamToAssign]): Print("Attempting to assign player to a new team")
OnBegin()powinna wyglądać tak, jak poniższy blok kodu.VerseOnBegin<override>()<suspends> : void = Print("Verse Device Started!") set Teams = Self.GetPlayspace().GetTeamCollection().GetTeams() Print("Beginning to Assign Players") Playspace := GetPlayspace() AllPlayers := Playspace.GetPlayers() for (TeamPlayer : AllPlayers, CurrentTeam := Playspace.GetTeamCollection().GetTeam[TeamPlayer]): var TeamSize : int = 0 if(set TeamSize = Playspace.GetTeamCollection().GetAgents[CurrentTeam].Length): Print("Size of this player's starting team is {TeamSize}")
Postępowanie z graczem dołączającym w trakcie gry
Chcesz też automatycznie równoważyć drużyny podczas trwającej gry. Dlatego musisz zasubskrybować zdarzenie, które uruchamia się w chwili, gdy dołącza nowy gracz. Nie chcesz powtarzać całego dopiero co napisanego kodu, więc możesz go przepisać na wspólną metodę.
Utwórz metodę o nazwie
BalanceTeams()i przenieś cały kod od miejsca po ustawieniu zmiennejTeamsprzy użyciuGetTeams(). Jest to wywoływane w metodzieOnBegin(), dzięki czemu drużyny są zrównoważone w momencie rozpoczęcia gry. FunkcjaBalanceTeams()powinna wyglądać następująco.VerseBalanceTeams() : void = AllPlayers := GetPlayspace().GetPlayers() for (TeamPlayer : AllPlayers, CurrentTeam := GetPlayspace().GetTeamCollection().GetTeam[TeamPlayer]): var TeamSize : int = 0 if(set TeamSize = GetPlayspace().GetTeamCollection().GetAgents[CurrentTeam].Length): Print("Size of this player's starting team is {TeamSize}") SmallestTeam : ?team = FindSmallestTeam(TeamSize) if (TeamToAssign := SmallestTeam?, GetPlayspace().GetTeamCollection().AddToTeam[TeamPlayer, TeamToAssign]): Print("Attempting to assign player to a new team")Utwórz nową metodę o nazwie
OnPlayerAdded(), która zawiera wywołanieBalanceTeams(). Nie będziesz używać zmiennejplayer, ale definicja tej metody jej wymaga, ponieważ przy jej użyciu subskrybujeszPlayerAddedEvent(). Więcej szczegółów na temat zdarzeń, które można subskrybować, patrz Kodowanie interakcji z urządzeniem.VerseOnPlayerAdded(InPlayer : player) : void = Print("A new Player joined, assigning them to a team!") BalanceTeams()W metodzie
OnBeginsubskrybuj zdarzeniePlayerAddedEventprzestrzeni gry z użyciem metodyOnPlayerAdded. Od teraz, gdy do gry dołączy gracz,OnPlayerAddedwywołaBalanceTeams(), aby automatycznie zrównoważyć drużyny.VerseOnBegin<override>()<suspends> : void = GetPlayspace().PlayerAddedEvent().Subscribe(OnPlayerAdded) Print("Beginning to balance teams") BalanceTeams()Zapisz skrypt w Visual Studio Code i kliknij Skompiluj kod Verse, aby skompilować skrypt.
Na pasku narzędzi UEFN kliknij Uruchom sesję, aby przetestować poziom w grze.
W trakcie wykonywania testu gry poziomu, w dzienniku wyjściowym powinny być zapisane komunikaty o liczebności każdej drużyny i wszystkich mniejszych drużynach, które znalazł skrypt. Gracze powinni być po równo rozdzieleni po drużynach, a nowy gracz dołączający do gry powinien utrzymywać tę równowagę.
Kompletny skrypt
Poniższy kod to kompletny skrypt urządzenia, które automatycznie równoważy drużyny graczy.
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
team_multiplayer_balance := class(creative_device):
# Holds the teams found with GetTeams()
var Teams : []team = array{}
OnBegin<override>()<suspends> : void =
Print("Verse Device Started!")
Praca własna
Dzięki tej instrukcji wiesz, jak stworzyć w Verse urządzenie, które automatycznie równoważy drużyny graczy.
Wykorzystując zdobytą wiedzę, utwórz celowo niezrównoważone drużyny dla asymetrycznych trybów gry, takich jak jeden gracz kontra wielu graczy.