Ajouter des rondes permet de structurer le gameplay en phases avec un point de départ et de fin clair, permettant aux joueurs de mesurer leur progression et d'avoir une opportunité périodique de jouer sur un terrain égal. Cela est particulièrement important pour le gameplay en équipe, car cela offre aux joueurs la chance de changer leur style de jeu en fonction de qui est dans leur équipe pendant cette ronde.
En utilisant l' expérience de laser tag échantillon comme référence, cette section du tutoriel vous enseigne comment utiliser et personnaliser les fonctionnalités intégrées de Roblox pour structurer chaque ronde, y compris des conseils de script sur :
- Commencer une ronde en réinitialisant les points individuels et d'équipe, puis en faisant apparaître les joueurs dans leurs zones de spawn d'équipe.
- Personnaliser les variables qui définissent l'objectif pour la ronde en haut de l'écran de chaque joueur.
- Suivre les contributions de points des joueurs pour le score de leur équipe.
- Déclencher des écrans UI uniques en fonction de si l'équipe du joueur a gagné ou perdu la ronde.
- Terminer une ronde en déconnectant les joueurs et en les faisant apparaître dans le hall neutre.
Après avoir complété cette section, vous apprendrez comment implémenter un comportement de blaster qui est à la fois précis et satisfaisant pour les joueurs.

Boucle de départ
ServerScriptService ⟩ Gameplay ⟩ Rounds gère la plupart de la logique pour implémenter des rondes, et commence par appeler la fonction startRoundLoopAsync() pour marquer le début d'une boucle de ronde. Pendant que les joueurs rejoignent le hall et attendent d'être répartis dans une équipe, startRoundLoopAsync() appelle la fonction resetScores() dans ServerScriptService ⟩ Gameplay ⟩ Scoring pour réinitialiser à la fois le tableau des scores et les points d'équipe.
Scoring
function Scoring.resetScores()
for _, player in Players:GetPlayers() do
player.leaderstats.Points.Value = 0
end
for _, team in Teams:GetTeams() do
team:SetAttribute(GuiAttribute.teamPoints, 0)
end
end
Maintenant que tout le monde commence avec zéro point, startRoundLoopAsync() définit ensuite la propriété Neutral de l'emplacement de spawn Neutre sur false afin que seuls les joueurs ayant la même propriété Team.Color que la propriété TeamColor de l'emplacement de spawn puissent y apparaître. Comme la propriété TeamColor de l'emplacement de spawn est définie sur blanc à la place des équipes mints ou rose carnation de l'échantillon, cette configuration empêche tous les joueurs d'apparaître ou de réapparaître là-bas pendant qu'une ronde est active.
Pour les joueurs qui sont actuellement dans le hall, startRoundLoopAsync() passe tous les joueurs actuellement dans l'expérience à la fonction spawnPlayersInMap dans ServerScriptService ⟩ Gameplay ⟩ Rounds ⟩ spawnPlayersInMap pour trier et équilibrer tout le monde dans une équipe avec environ le même nombre de joueurs.
Pour tout nouveau joueur qui rejoint l'expérience après que le groupe du hall a été trié en une équipe, startRoundLoopAsync() écoute l'événement Players.PlayerAdded:Connect, puis appelle à nouveau la fonction spawnPlayersInMap pour les ajouter à l'équipe avec le moins de joueurs. Pour plus d'informations sur ce processus, voir Configurer les emplacements de spawn dans la section précédente Apparitions et Réapparitions du tutoriel.
Rounds
-- Faire apparaître tous les joueurs sur la carte
neutralSpawn.Neutral = false
spawnPlayersInMap(Players:GetPlayers())
-- Faire apparaître de nouveaux joueurs sur la carte lorsqu'ils rejoignent
local playerAddedConnection = Players.PlayerAdded:Connect(function(player: Player)
spawnPlayersInMap({ player })
end)
Définir l'objectif
Maintenant que chaque joueur est dans l'arène avec ses coéquipiers, l'expérience doit fournir des instructions sur ce qu'il faut faire pour réussir dans la ronde. L'expérience de laser tag échantillon aborde cette exigence en fournissant une invite d'objectif en haut de l'écran de chaque joueur avec des directives claires sur ce que l'équipe doit faire pour gagner.

Bien que vous puissiez en apprendre davantage sur la façon de configurer et d'afficher le composant UI d'objectif dans le Curriculum UI, cette section se concentre sur la façon d'implémenter l'objectif alors que la ronde commence, en commençant par définir le montant de points que chaque équipe doit obtenir pour compléter la ronde.
Bien que l'invite d'objectif à l'exécution informe les joueurs qu'ils doivent marquer trois points pour gagner, si vous examinez l'invite dans StarterGui ⟩ HUDGui, vous pouvez voir qu'elle contient en fait une valeur configurable "%d" pour la valeur des points.

"%d" est une chaîne d'espace réservée que vous pouvez augmenter ou diminuer à tout moment pour répondre à vos propres exigences de gameplay en mettant à jour la variable TEAM_SCORE_LIMIT dans ReplicatedStorage ⟩ TEAM_SCORE_LIMIT. Par exemple, si vous deviez définir ce nombre sur un 200 excessivement élevé, l'invite et le compteur de points d'équipe se mettraient à jour en conséquence.
TEAM_SCORE_LIMITlocal TEAM_SCORE_LIMIT = 200 -- ligne mise à jour, assurez-vous de revenir en arrièrereturn TEAM_SCORE_LIMIT

Cette simple mise à jour de variable fonctionne à l'exécution car, lorsque la ronde commence, ReplicatedStorage ⟩ HUDGuiSetup ⟩ SetObjective requiert le script de module TEAM_SCORE_LIMIT afin de pouvoir échanger la chaîne d'espace réservée dans l'objet TextLabel de l'objectif UI.
TEAM_SCORE_LIMIT
local TEAM_SCORE_LIMIT = require(ReplicatedStorage.TEAM_SCORE_LIMIT)
local function setObjective(gui: ScreenGui)
local bodyTextLabel = gui.Objective.ObjectiveDisplay.Body.BodyTextLabel
bodyTextLabel.Text = bodyTextLabel.Text:format(TEAM_SCORE_LIMIT)
end
Suivre les points
Maintenant que les joueurs ont un objectif pour la ronde, l'expérience doit suivre les points de chaque équipe jusqu'à ce qu'ils atteignent leur objectif. Alors que le comportement par défaut du service Teams regroupe automatiquement chaque joueur sous leur équipe et additionne les contributions de chaque joueur à leur score d'équipe, il est important de stocker et de surveiller les points dans un emplacement séparé pour le gameplay basé sur des rondes, car si un joueur marque, puis quitte avant la fin de la ronde, sa contribution est déduite du tableau des scores dès qu'il se déconnecte de l'expérience.
Pour garantir que cela ne se produise pas et que chaque contribution au but de l'équipe soit préservée, ReplicatedStorage ⟩ HUDGuiSetup ⟩ StartSyncingTeamPoints stocke tous les points séparément sous l'attribut teamPoints dans le service Teams. À mesure que teamPoints s'incrémente, ce script de module appelle la fonction startSyncingTeamPoints pour trouver le compteur d'équipe Class.GuiObjects au sein du composant UI d'Objectif.
Lorsque cela localise TeamACounter et TeamBCounter, il obtient leur attribut teamColor, qui correspond aux zones de spawn d'équipe : TeamACounter affiche les points de l'équipe verte, et TeamBCounter suit les points de l'équipe rose.
StartSyncingTeamPoints
local function startSyncingTeamPoints(gui: ScreenGui)
for _, teamPointCounter in gui.Objective.TeamPointCounter:GetChildren() do
if not teamPointCounter:IsA("GuiObject") then
continue
end
local iconTeamColor = teamPointCounter:GetAttribute(GuiAttribute.teamColor)
Le script de module appelle ensuite sa fonction getTeamFromTeamColor pour vérifier que l'attribut teamColor mint du TeamACounter et l'attribut teamColor carnation pink du TeamBCounter correspondent tous les deux aux propriétés Team.Color correspondantes sous le service Teams. Si oui, il retourne les deux équipes.
StartSyncingTeamPoints
local function getTeamFromTeamColor(teamColor: Color3): Team?
for _, team in Teams:GetTeams() do
if team.TeamColor == teamColor then
return team
end
end
return nil
end
Lorsque cela se produit, startSyncingTeamPoints définit les objets TextLabel des deux compteurs d'équipe sur leurs valeurs correspondantes de teamPoints, et continue de les mettre à jour chaque fois qu'un joueur marque un point en éliminant un autre joueur de l'équipe adverse.
StartSyncingTeamPoints
teamPointCounter.TextLabel.Text = team:GetAttribute(GuiAttribute.teamPoints)
team:GetAttributeChangedSignal(GuiAttribute.teamPoints):Connect(function()
teamPointCounter.TextLabel.Text = team:GetAttribute(GuiAttribute.teamPoints)
Tout ce qui a été abordé dans cette section jusqu'à présent s'est concentré sur la façon de suivre les points à l'écran du joueur, mais il est important de revoir la logique qui gère le suivi des points sur le serveur afin qu'il sache quand une équipe atteint l'objectif et gagne la ronde. Si vous revenez à ServerScriptService ⟩ Gameplay ⟩ Scoring, vous pouvez voir que le script de module commence par créer un événement liaison, qui sera déclenché chaque fois qu'un joueur marque un point.
Scoringlocal teamScoreChangedBindable = Instance.new("BindableEvent")local Scoring = {teamScoreChanged = teamScoreChangedBindable.Event,}
Il appelle ensuite la fonction incrementScore, qui effectue les actions suivantes :
- Récupère le score individuel du joueur sur le tableau des scores, et ajoute un point.
- Déclenche l'événement liaison précédemment mentionné avec à la fois l'équipe du joueur et leur score.
Ce processus permet de garder le client et le serveur synchronisés concernant les scores individuels des joueurs et les scores d'équipe.
Scoring
function Scoring.incrementScore(player: Player, amount: number)
local team = player.Team
assert(team, `Le joueur {player.Name} doit être dans une équipe pour marquer un point, mais n'a pas d'équipe`)
local teamPoints = team:GetAttribute(GuiAttribute.teamPoints)
teamPoints += amount
team:SetAttribute(GuiAttribute.teamPoints, teamPoints)
local leaderstat = player.leaderstats.Points
leaderstat.Value += amount
teamScoreChangedBindable:Fire(team, teamPoints)
end
Afficher les résultats
Alors que les joueurs s'éliminent et marquent des points pour leur équipe, ServerScriptService ⟩ Gameplay ⟩ Rounds vérifie si l'équipe qui a marqué a atteint l'objectif de la ronde. Si le score de leur équipe est inférieur à la variable TEAM_SCORE_LIMIT dans ReplicatedStorage ⟩ TEAM_SCORE_LIMIT, le serveur continue d'attendre jusqu'à ce qu'une des équipes marque à nouveau.
Cependant, une fois que le score d'une équipe atteint la variable TEAM_SCORE_LIMIT, le script déclenche une instance d'événement roundWinnerRemote avec le nom du joueur et leur équipe.
Rounds-- Vérifiez si la ronde est terminée après chaque scorelocal team: Teamlocal score: number = 0while score < TEAM_SCORE_LIMIT doteam, score = Scoring.teamScoreChanged:Wait()end-- Afficher l'équipe gagnantefor _, player in Players:GetPlayers() do-- Envoi de l'équipe à laquelle le joueur appartient à la fin de la ronde-- parce que l'équipe du joueur est sur le point d'être retirée, donc le client-- ne pourra pas vérifier sa propre équiperoundWinnerRemote:FireClient(player, team, player.Team)end
Le script ReplicatedStorage ⟩ RoundResultsGuiSetup sur chaque client écoute cette instance d'événement roundWinnerRemote afin de pouvoir :
- Afficher un écran UI unique StarterGui ⟩ RoundResultsGui qui annonce les résultats de la ronde et si le joueur était dans l'équipe gagnante.
- Jouer un clip audio de victoire ou de défaite.
Par exemple, si un joueur est dans l'équipe qui a marqué le point gagnant, il reçoit plusieurs formes de retour d'informations sur les résultats de la ronde sous la forme d'un écran UI affichant un texte de victoire et un clip audio jouant un son joyeux. En revanche, si un joueur n'est pas dans l'équipe qui a marqué le point gagnant, il reçoit un écran UI affichant un texte de défaite et un clip audio jouant un son sinistre.
RoundResultsGuiSetup
local function onRoundWinner(winner: Team, localTeam: Team?)
local victoryDefeatText = "La ronde est terminée !"
if localTeam then
-- Si notre équipe a gagné, nous afficherons Victoire ! Sinon afficher Défaite...
local isVictory = winner == localTeam
if isVictory then
victorySound:Play()
victoryDefeatText = VICTORY_TEXT
else
defeatSound:Play()
victoryDefeatText = DEFEAT_TEXT
end
end
Réinitialiser les équipes
Au même moment, ServerScriptService ⟩ Gameplay ⟩ Rounds vérifie qu'une équipe a atteint l'objectif de la ronde et déclenche l'affichage UI approprié pour chaque joueur, il transporte également tous les joueurs de l'arène vers le hall en les déconnectant de la ronde. Cela commence le processus de fin formelle de la ronde et de réinitialisation des deux équipes.
En utilisant la même logique dans Configurer les emplacements de spawn, Rounds définit ensuite la propriété Neutral de l'emplacement de spawn Neutre sur true afin que les joueurs puissent y réapparaître indépendamment de leur statut d'équipe. Cela signifie que le hall devient le seul emplacement où les joueurs peuvent apparaître après avoir été déconnectés de la ronde.
Rounds-- Envoyer tout le monde au hallplayerAddedConnection:Disconnect()neutralSpawn.Neutral = truespawnPlayersInLobby(Players:GetPlayers())
Après avoir attendu dix secondes pour une intermission, le script serveur Rounds recommence ensuite la boucle en réinitialisant les scores de tout le monde et en les triant en nouvelles équipes. L'échantillon répète ce processus cyclique de ronde jusqu'à ce qu'il n'y ait plus de joueurs sur le serveur.
Maintenant que les joueurs peuvent apparaître dans la carte avec leur propre équipe et jouer une ronde complète, la prochaine section vous enseignera les scripts derrière le comportement de chaque blaster.