In Multiplayer-Spielen treten Teams von Spielern gegeneinander an oder arbeiten zusammen, um ein bestimmtes Ziel zu erreichen. Die Anzahl der Spieler in jedem Team kann radikale Auswirkungen auf das Gameplay haben, und viele Entwickler wählen ein bestimmtes Verhältnis von Spielern, um ein angenehmes Erlebnis zu schaffen.
Beim Team-Balancing werden die Spieler in Teams aufgeteilt, die einem bestimmten Verhältnis folgen. Bei den meisten Multiplayer-Spielen sind die Teams gleichmäßig aufgeteilt, so dass kein Team einen Vorteil hat. Manche Spiele schaffen absichtlich unausgewogene Szenarien, indem sie beispielsweise vier Spieler gegen einen übermächtigen Spieler antreten lassen. Unabhängig von der Art des Spiels ist die Ausgewogenheit der Teams entscheidend für die Schaffung interessanter Erlebnisse für mehrere Spielerteams.
In diesem Leitfaden erfährst du, wie du Teams von Spielern zur Laufzeit dynamisch ausbalancieren kannst, und immer dann, wenn ein neuer Spieler dem Spiel beitritt. Das vollständige Script ist am Ende dieses Leitfadens als Referenz enthalten.
Verwendete Sprachfunktionen in Verse
array: Dieses Gerät verwendet Arrays, um einen Verweis auf jedes Team zu speichern.
option: Dieses Gerät verwendet Optionen, um festzustellen, ob es ein Team mit weniger Spielern gibt als das Team, in dem ein Spieler gerade spielt.
for: Mit dem Ausdruck „for“ kannst du über die Arrays iterieren, die das Gerät verwendet.
if: Der if-Ausdruck wird verwendet, um zu prüfen, ob Spieler aufgrund der Teamgrößen in ein neues Team wechseln sollten.
failure: Fehlerkontexte werden verwendet, um auf Arrays zuzugreifen und den Programmablauf zu steuern.
Verwendete APIs in Verse
Abonnierbar: Du abonnierst
PlayerAddedEvent(),um die Teams dynamisch neu zusammenzustellen, wenn ein neuer Spieler einem laufenden Spiel beitritt.Teams: Die Team-Klasse fügt Spieler hinzu, entfernt sie und ruft sie aus Teams ab. In diesem Tutorial wirst du die Teamklasse verwenden, um Spieler und ihre Teamzuordnungen direkt zu bearbeiten.
Spielbereich: Der Spielbereich verfolgt abonnierbare Events im Zusammenhang mit Spielern, die das Spiel betreten und verlassen. Außerdem kannst du Listen von Spielern und Teams abrufen und die Mannschaft eines bestimmten Spielers finden. In diesem Tutorial wirst du mehrere Spielbereich-Events abonnieren und Spieler und Teams mit Spielbereich-Methoden abrufen, damit du sie direkt bearbeiten kannst.
Level einrichten
In diesem Beispiel wird das folgende Gerät verwendet.
4 x Spieler-Spawnflächen-Gerät: Dieses Gerät legt fest, wo der Spieler zu Beginn des Spiels spawnen wird.
Befolge diese Schritte, um dein Level einzurichten:
Füge dem Level eine Spieler-Spawnfläche hinzu.
Wähle die Spawnfläche im Outliner aus, um ihr Details-Panel zu öffnen.
Im Details-Panel, unter Nutzeroptionen:
Setze Spieler-Team auf Team-Index mit einem Wert von 1
Aktiviere Im Spiel sichtbar
Klicke auf das Bild, um es zu vergrößern.
Dupliziere die Spawnfläche und platziere sie neben der ersten Spawnfläche.
Dupliziere beide Spawnflächen und platziere sie weiter entfernt von der ersten Gruppe von Spawnflächen. Hier werden die Spieler von Team 2 spawnen.
Wähle die doppelten Spawnflächen aus und ändere im Details-Panel unter Benutzeroptionen den Wert von Team-Index für beide auf 2.
Wähle im Outliner das Gerät Insel-Einstellungen aus, um dessen Details-Panel zu öffnen. Unter Benutzeroptionen – Spielregeln:
Setze Teams auf Team-Index mit einem Wert von 2. In diesem Beispiel werden zwei Teams verwendet, aber du kannst eine beliebige Anzahl von Teams haben.
Setze Teamgröße auf Dynamisch. Das bedeutet, dass dein Verse-Code das Team-Balancing übernehmen kann.
Setze Bei laufendem Spiel beitreten auf Spawnen, damit neue Spieler dem Spiel beitreten können, während es läuft.
Klicke auf das Bild, um es zu vergrößern.
Erstelle mit Verse Explorer ein neues Verse-Gerät mit dem Namen team_multiplayer_balancing und ziehe das Gerät in das Level. (Wie du ein neues Gerät in Verse erstellen kannst, erfährst du unter Erstelle dein eigenes Gerät mit Verse.)
Dein Level sollte so ähnlich aussehen wie diese Konfiguration:
Gleichmäßige Aufteilung der Teams
Balance der Teams zu Beginn des Spiels
In diesem Schritt wird gezeigt, wie die Spieler zu Beginn eines Spiels und bei Beitritt eines neuen Spielers gleichmäßig in Teams aufgeteilt werden.
Öffne Verse-Explorer und doppelklicke auf team_multiplayer_balancing.verse, um das Script in Visual Studio Code zu öffnen.
In der Klassendefinition von
team_multiplayer_balancingfüge ein variablesTeam-Array mit dem NamenTeamshinzu, das Verweise auf jedes Team speichert, dem die Spieler angehören.Verseteam_multiplayer_balance := class(creative_device): # Holds the teams found with GetTeams() var Teams : []team = array{}Aktualisiere in der
OnBegin()- Funktion das ArrayTeams, um die Teams zuzuordnen, die du zuvor in den Inseleinstellungen eingerichtet hast. Rufe die FunktionGetTeams()aus der APIfort_team_collectionauf, um alle Teams im Spielbereich zu erhalten.VerseOnBegin<override>()<suspends>:void= Print("Verse Device Started!") set Teams = Self.GetPlayspace().GetTeamCollection().GetTeams()Finde alle Spieler im Spiel, indem du die Funktion
GetPlayers()aufrufst, und speichere sie in einem Spieler-Array namensAllPlayers.VerseOnBegin<override>()<suspends>:void= Print("Verse Device Started!") set Teams = Self.GetPlayspace().GetTeamCollection().GetTeams() AllPlayers := GetPlayspace().GetPlayers()Gehe die Liste aller Spieler durch und bilde Teams mit der gleichen Anzahl von Spielern. Du vergleichst das Team, in dem ein Spieler derzeit spielt, mit allen anderen Teams und stellst fest, ob es am besten zu diesem Spieler passt. In diesem Fall kannst du das Team verwenden, dem ein Spieler automatisch zugewiesen wird, wenn das Spiel beginnt, indem du
GetTeam[]verwendest (da Spieler in Spielmodi mit mehreren Teams einem Team angehören müssen). Beachte, dassGetTeam[]einen Parameter vom Typ „agent“ benötigt, aber da „player“ eine Subklasse von „agent“ ist, kannst du einen „player“ ohne Typ-Casting übergeben.VerseAllPlayers := GetPlayspace().GetPlayers() for (TeamPlayer : AllPlayers, CurrentTeam := GetPlayspace().GetTeamCollection().GetTeam[TeamPlayer]): # Assign Players to a new team if teams are unbalancedDa `team` eine interne Klasse ist, kann sie nicht initialisiert werden und nur als Verweis auf ein bestehendes `team`-Objekt verwendet werden.
Du solltest die Spieler dem Team mit den wenigsten Spielern zuweisen, bis alle Teams ausgeglichen sind. Dazu musst du jeden Spieler und dann jedes Team mit einer
for- Schleife überprüfen. Du könntest zwei for-Schleifen verwenden, eine für die Iteration durch Spieler und eine für die Iteration durch Teams, aber in diesem Beispiel wirst du die for-Schleife für das Team in eine eigene Methode extrahieren. Richte die Spieler-Schleife ein, indem du eine Referenz auf jeden Spieler und dann eine Referenz auf jedes Team, in dem sie sind, in einer Konstante namensCurrentTeamabrufst.Erstelle eine neue Ganzzahl-Variable
TeamSize, initialisiere sie auf0und setze sie dann gleich der Größe des Teams, in dem sich der Spieler gerade befindet. DaGetAgents[]ein fehlbarer Ausdruck ist, musst du diesen Satz in eine if-Anweisung einschließen.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}")Erstelle eine Methode namens
FindSmallestTeam(). Dies gibt ein optionales Team (?team) zurück, wennTeamSizeals Argument übergeben wird, und handhabt das Suchen und die Rückgabe des Teams mit den wenigsten Spielern. Initialisiere eine neue Team-Option mit dem NamenSmallestTeaminnerhalb vonFindSmallestTeam(). Du verwendest hier eine Option, weil ein Spieler bereits im kleinsten Team sein kann, wenn duFindSmallestTeam()aufrufst.Da deine Option
SmallestTeamstandardmäßig auf false gesetzt ist, bleibt siefalse, wenn kein kleineres Team gefunden wird. WennFindSmallestTeam()den Wertfalsezurückgibt, weißt du definitiv, dass der angegebene Spieler bereits in dem kleinsten Team war. Außerdem musst du eine Variable intCurrentTeamSizemit dem Wert vonTeamSizeinitialisieren. Du musstCurrentTeamSizevariabel gestalten, damit du es auf die Größe jedes anderen Teams aktualisieren kannst, das du mit weniger Spielern findest.VerseFindSmallestTeam(CurrentTeamSize : int) : ?team= var SmallestTeam : ?team = false var TeamSize : int = CurrentTeamSizeDa
TeamSizedie Größe vonSmallestTeamverfolgt, musst du sie mit der Größe jedes Teams vergleichen. Iteriere durch jedes Team und rufe ihre Größe in einer lokalen intCandidateTeamSizeab. WennCandidateTeamSizekleiner ist alsTeamSize, wirdSmallestTeamauf dieses Team undTeamSizeauf die Größe dieses Teams gesetzt.Die Bedingung
TeamSize > CandidateTeamSizeist eine Filterbedingung, da sie innerhalb der Klammern der for-Schleife geprüft wird. Die Verwendung einer Filterbedingung garantiert, dass der Code in deiner Schleife nur dann ausgeführt wird, wenn die Filterbedingung erfolgreich ist. Dies garantiert, dassSmallestTeamauf das Team mit den wenigsten Spielern gesetzt wird, wenn eines gefunden wird. Wenn kein Team mit weniger Spielern gefunden wird, bleibtSmallestTeamFalse.Schließlich wird
SmallestTeamzurückgegeben, wenn alle Teams überprüft worden sind.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 SmallestTeamErstelle in
OnBegin()eine neue Team-Option namensSmallestTeaminnerhalb derfor-Schleife und initialisiere sie mit dem Wert vonFindSmallestTeam(), wennTeamSizeals Argument übergeben wird.VerseSmallestTeam : ?team = FindSmallestTeam(TeamSize)Versuche als Nächstes, auf den Wert in der optionalen Variable
SmallestTeamzuzugreifen. Wenn der Wert false ist, war der Spieler bereits im kleinsten Team, und es ist keine Zuordnung erforderlich. Andernfalls musst du den Spieler seinem neuen Team zuordnen. Da viele Methoden es nicht erlauben, eine Option direkt als Argument zu übergeben, musst du den Wert in eine lokale VariableTeamToAssignextrahieren. Du kannst versuchen, einen Spieler mitAddToTeam[player, team]diesem Team zuzuweisen. Beachte, dass diese Zuweisung fehlschlägt, wenn du versuchst, einen Spieler einem Team zuzuweisen, zu dem er bereits gehört. Dies hat jedoch keine negativen Effekte, da diefor-Schleife einfach zum nächsten Spieler iterieren wird und den ersten Spieler in seinem ursprünglichen Team belässt.Verseif (TeamToAssign := SmallestTeam?, GetPlayspace().GetTeamCollection().AddToTeam[TeamPlayer, TeamToAssign]): Print("Attempting to assign player to a new team")
OnBegin()sollte wie der folgende Code-Block aussehen.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}")
Umgang mit einem Spieler, der einem laufenden Spiel beitritt
Da du auch in der Lage sein willst, Teams für ein laufendes Spiel automatisch auszugleichen, musst du das Event abonnieren, das ausgelöst wird, wenn ein neuer Spieler beitritt. Da du den gesamten Code, den du gerade geschrieben hast, nicht wiederholen willst, kannst du ihn in eine gemeinsame Methode umstrukturieren.
Erstelle eine Methode namens
BalanceTeams()und verschiebe den gesamten Code hinter die Stelle, an der du die VariableTeamsmitGetTeams()gesetzt hast. Dies wird in der MethodeOnBegin()aufgerufen, damit die Teams ausgeglichen sind, wenn das Spiel beginnt.BalanceTeams()sollte ungefähr so aussehen.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")Erstelle eine weitere Methode namens
OnPlayerAdded(), die einen Aufruf vonBalanceTeams()enthält. Obwohl du dieplayer-Variable nicht verwendest, ist sie in der Methodendefinition erforderlich, da du dich mit dieser Methode beiPlayerAddedEvent()anmeldest. Weitere Einzelheiten zu abonnierbaren Events findest du auf der Seite Geräteinteraktionen programmieren.VerseOnPlayerAdded(InPlayer : player) : void = Print("A new Player joined, assigning them to a team!") BalanceTeams()Abonniere in
OnBegin()dasPlayerAddedEvent()mitOnPlayerAdded. Wenn nun ein Spieler dem Spiel beitritt, ruftOnPlayerAddedBalanceTeams()auf, um die Teams automatisch auszugleichen.VerseOnBegin<override>()<suspends> : void = GetPlayspace().PlayerAddedEvent().Subscribe(OnPlayerAdded) Print("Beginning to balance teams") BalanceTeams()Speichere das Script in Visual Studio Code und klicke auf Verse Code erstellen, um dein Script zu kompilieren.
Klicke auf Sitzung starten in der UEFN-Symbolleiste, um den Level einen Spieltest durchzuführen.
Wenn du dein Level testest, solltest du die Größe der einzelnen Teams sowie alle kleineren Teams, die das Script findet, im Output-Log sehen. Die Spieler sollten gleichmäßig auf die Teams verteilt sein, und wenn ein neuer Spieler dem Spiel beitritt, sollte diese Ausgewogenheit beibehalten werden.
Vollständiges Script
Der folgende Code ist das vollständige Script für ein Gerät, das automatisch Teams von Spielern ausbalanciert.
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!")
Du bist am Zug
Wenn du diese Anleitung abgeschlossen hast, hast du gelernt, wie du mit Verse ein Gerät erstellst, das automatisch Teams von Spielern ausbalanciert.
Versuche, mit dem Gelernten absichtlich unausgewogene Teams für asymmetrische Spielmodi zu bilden, z. B. ein Spieler gegen vier Spieler.