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. 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żeniefor
umożliwia iterację po tablicach używanych przez urządzenie. -
if
: Wyrażenieif
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żyny dodaje graczy do drużyn oraz pobiera i usuwa z nich. W samouczku będziesz używać klasy drużyny, aby bezpośrednio manipulować graczami i ich przypisaniem do drużyny.
-
Przestrzeń gry: Przestrzeń gry śledzi subskrybowalne zdarzenia powiązane z graczami, którzy dołączają do gry i ją opuszczają. 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 Panel startowy 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.
-
Ustaw Liczebność drużyn na 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 przy użyciu 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 plik team_multiplayer_balancing.verse, aby otworzyć skrypt w Visual Studio Code.
-
W definicji klasy
team_multiplayer_balancing
dodaj tablicę zmiennychteam
o nazwieTeams
, będzie ona przechowywała odwołania do każdej drużyny, w której są gracze.team_multiplayer_balance := class(creative_device): # Przechowuje drużyny znalezione przy użyciu GetTeams() var Teams : []team = array{}
-
W funkcji
OnBegin()
uaktualnij tablicęTeams
, aby pasowała do drużyn ustawionych wcześniej w Ustawieniach wyspy. Wywołaj funkcjęGetTeams()
z APIfort_team_collection
, aby uzyskać wszystkie drużyny w przestrzeni gry.OnBegin<override>()<suspends>:void= Print("Uruchomiono urządzenie Verse!") set Teams = Self.GetPlayspace().GetTeamCollection().GetTeams()
-
Znajdź wszystkich graczy w grze, wywołując funkcję
GetPlayers()
, i zapisz ich w tablicy graczy o nazwieAllPlayers
.OnBegin<override>()<suspends>:void= Print("Uruchomiono urządzenie Verse!") 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.AllPlayers := GetPlayspace().GetPlayers() for (TeamPlayer : AllPlayers, CurrentTeam := GetPlayspace().GetTeamCollection().GetTeam[TeamPlayer]): # Przypisz graczy do nowej drużyny, jeśli drużyny są niezrównoważone
Druż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
TeamSize
i 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.for (TeamPlayer : AllPlayers, CurrentTeam := GetPlayspace().GetTeamCollection().GetTeam[TeamPlayer]): # Przypisz graczy do nowej drużyny, jeśli drużyny są niezrównoważone var TeamSize : int = 0 if(set TeamSize = GetPlayspace().GetTeamCollection().GetAgents[CurrentTeam].Length): Print("Liczebność drużyny początkowej tego gracza to {TeamSize}")
- Utwórz metodę o nazwie
FindSmallestTeam()
. Po przekazaniu jejTeamSize
jako 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 nazwieSmallestTeam
wewną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
SmallestTeam
ma 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łkowitegoCurrentTeamSize
na wartośćTeamSize
.CurrentTeamSize
musi być zmienną, aby można ją było uaktualnić do liczebności innej znalezionej najmniejszej drużyny.FindSmallestTeam(CurrentTeamSize : int) : ?team= var SmallestTeam : ?team = false var TeamSize : int = CurrentTeamSize
-
TeamSize
śledzi liczebnośćSmallestTeam
, dlatego 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śliCandidateTeamSize
jest mniejsza niżTeamSize
, ustawSmallestTeam
na tę drużynę, aTeamSize
na liczebność tamtej drużyny.Warunek
TeamSize > CandidateTeamSize
to 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, żeSmallestTeam
zostanie 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,SmallestTeam
będzie miała dalej wartość false.Na koniec zwróć wartość
SmallestTeam
po sprawdzeniu wszystkich drużyn.for(Team : Teams, CandidateTeamSize := GetPlayspace().GetTeamCollection().GetAgents[Team].Length, TeamSize > CandidateTeamSize): set SmallestTeam = option{Team} set TeamSize = CandidateTeamSize Print("Znaleziono drużynę z mniejszą liczbą graczy: {CandidateTeamSize}") return SmallestTeam
-
W
OnBegin()
utwórz nową opcję drużyny o nazwieSmallestTeam
wewnątrz pętlifor
i zainicjuj ją wartościąFindSmallestTeam()
, przekazującTeamSize
jako argument.SmallestTeam : ?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ętlafor
po prostu przejdzie do kolejnego gracza, a pierwszego zostawi w oryginalnej drużynie.if (TeamToAssign := SmallestTeam?, GetPlayspace().GetTeamCollection().AddToTeam[TeamPlayer, TeamToAssign]): Print("Próbuję przypisać gracza do nowej drużyny")
-
-
OnBegin()
powinna wyglądać tak, jak poniższy blok kodu.OnBegin<override>()<suspends> : void = Print("Uruchomiono urządzenie Verse!") set Teams = Self.GetPlayspace().GetTeamCollection().GetTeams() Print("Rozpoczęcie przypisywania graczy") 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("Liczebność drużyny początkowej tego gracza to {TeamSize}") SmallestTeam : ?team = FindSmallestTeam(TeamSize) if (TeamToAssign := SmallestTeam?, Playspace.GetTeamCollection().AddToTeam[TeamPlayer, TeamToAssign]): Print("Próbuję przypisać gracza do nowej drużyny")
Obsługa gracza dołączającego w toku 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 zmiennejTeams
przy 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.BalanceTeams() : 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("Liczebność drużyny początkowej tego gracza to {TeamSize}") SmallestTeam : ?team = FindSmallestTeam(TeamSize) if (TeamToAssign := SmallestTeam?, GetPlayspace().GetTeamCollection().AddToTeam[TeamPlayer, TeamToAssign]): Print("Próbuję przypisać gracza do nowej drużyny")
-
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.OnPlayerAdded(InPlayer : player) : void = Print("Dołączył nowy gracz, przypisuję go do drużyny!") BalanceTeams()
-
W
OnBegin()
zasubskrybujPlayerAddedEvent()
przy użyciuOnPlayerAdded
. Od teraz, gdy do gry dołączy gracz,OnPlayerAdded
wywołaBalanceTeams()
, aby automatycznie zrównoważyć drużyny.OnBegin<override>()<suspends> : void = GetPlayspace().PlayerAddedEvent().Subscribe(OnPlayerAdded) Print("Zaczynam równoważyć drużyny") BalanceTeams()
-
Zapisz skrypt w Visual Studio Code i kliknij Kompiluj skrypty 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):
# Przechowuje drużyny znalezione przy użyciu GetTeams()
var Teams : []team = array{}
OnBegin<override>()<suspends> : void =
Print("Uruchomiono urządzenie Verse!")
set Teams = Self.GetPlayspace().GetTeamCollection().GetTeams()
AllPlayers := GetPlayspace().GetPlayers()
#Zasubskrybuj PlayerAddedEvent, aby umożliwić ponowne zrównoważenie drużyny, gdy do gry dołączy nowy gracz
Self.GetPlayspace().PlayerAddedEvent().Subscribe(OnPlayerAdded)
Print("Zaczynam równoważyć drużyny")
BalanceTeams()
#Obsługuje nowego gracza dołączającego do gry
OnPlayerAdded(InPlayer : player) : void =
Print("Dołączył nowy gracz, przypisuję go do drużyny!")
BalanceTeams()
<#
Dla każdego gracza znajdź liczbę graczy w drużynie, do której należy. Przeiteruj przez
listę drużyn i przypisz gracza do drużyny, w której jest najmniej graczy, a jeśli liczebności są równe, przypisz go do jego
drużyny początkowej.
#>
BalanceTeams() : void =
AllPlayers := GetPlayspace().GetPlayers()
for (TeamPlayer : AllPlayers, CurrentTeam := GetPlayspace().GetTeamCollection().GetTeam[TeamPlayer]):
# Przypisz graczy do nowej drużyny, jeśli drużyny są niezrównoważone
var TeamSize:int = 0
if(set TeamSize = GetPlayspace().GetTeamCollection().GetAgents[CurrentTeam].Length):
Print("Liczebność drużyny początkowej tego gracza to {TeamSize}")
SmallestTeam : ?team = FindSmallestTeam(TeamSize)
if (TeamToAssign := SmallestTeam?, GetPlayspace().GetTeamCollection().AddToTeam[TeamPlayer, TeamToAssign]):
Print("Próbuję przypisać gracza do nowej drużyny")
FindSmallestTeam(CurrentTeamSize : int) : ?team =
var SmallestTeam : ?team = false
var TeamSize : int = CurrentTeamSize
<#
Dla każdej drużyny z Team uzyskaj liczbę graczy w tej drużynie. Jeśli jest w niej mniej graczy niż SmallestTeam,
ustaw SmallestTeam na Team i uaktualnij TeamSize do liczby graczy w nowej Team
#>
for(Team : Teams, CandidateTeamSize := GetPlayspace().GetTeamCollection().GetAgents[Team].Length, TeamSize > CandidateTeamSize):
set SmallestTeam = option{Team}
set TeamSize = CandidateTeamSize
Print("Znaleziono drużynę z mniejszą liczbą graczy: {CandidateTeamSize}")
return SmallestTeam
We własnym zakresie
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.