Ajouter des rounds vous permet de structurer le gameplay en phases avec un point de départ et de fin clair afin que les joueurs puissent mesurer leurs progrès et avoir une opportunité périodique d'un terrain de jeu égal. Cela est particulièrement important pour le gameplay en équipe car cela offre aux joueurs la possibilité de changer leur style de jeu en fonction de qui est dans leur équipe pendant ce round.
En utilisant le jeu de laser tag exemple comme référence, cette section du tutoriel vous apprend à utiliser et à personnaliser les fonctionnalités intégrées de Roblox pour structurer chaque round, y compris des conseils de script sur :
- Commencer un round 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 le round 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 le round.
- Terminer un round en déconnectant les joueurs et en les faisant apparaître dans le hall neutre.
Après avoir terminé cette section, vous apprendrez à implémenter un comportement de blaster qui est à la fois précis et satisfaisant pour les joueurs.

Démarrer la boucle
ServerScriptService ⟩ Gameplay ⟩ Rounds gère la plupart de la logique pour implémenter des rounds, et cela commence par appeler la fonction startRoundLoopAsync() pour marquer le début d'une boucle de round. Pendant que les joueurs rejoignent le hall et attendent d'être triés 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.
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
endMaintenant 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 au lieu des équipes menthe ou rose carnation de l'exemple, cette configuration empêche tous les joueurs d'apparaître ou de réapparaître là-bas pendant qu'un round est actif.
Pour les joueurs qui sont actuellement dans le hall, startRoundLoopAsync() passe tous les joueurs actuellement dans le jeu à la fonction spawnPlayersInMap dans ServerScriptService ⟩ Gameplay ⟩ Rounds ⟩ spawnPlayersInMap pour trier et équilibrer tout le monde dans une équipe avec un nombre approximatif de joueurs.
Pour les nouveaux joueurs qui rejoignent le jeu après que le groupe du hall a été trié dans 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 Apparition et Réapparition du tutoriel.
-- Faire apparaître tous les joueurs dans la carte
neutralSpawn.Neutral = false
spawnPlayersInMap(Players:GetPlayers())
-- Faire apparaître de nouveaux joueurs dans 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, le jeu doit fournir des instructions sur ce qu'il faut faire pour réussir dans le round. Le jeu de laser tag exemple répond à cette exigence en fournissant une invite d'objectif en haut de l'écran de chaque joueur avec des indications 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 au début du round, en commençant par la façon de définir le nombre de points que chaque équipe doit atteindre pour compléter le round.
Même si 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 plutôt un "%d" configurable pour la valeur des points.

"%d" est une chaîne de remplacement 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.
local TEAM_SCORE_LIMIT = 200 -- ligne mise à jour, assurez-vous de revenir en arrière
return TEAM_SCORE_LIMIT
Cette simple mise à jour de variable fonctionne à l'exécution car au début du round, ReplicatedStorage ⟩ HUDGuiSetup ⟩ SetObjective nécessite le script de module TEAM_SCORE_LIMIT afin de pouvoir échanger la chaîne de remplacement dans l'objet TextLabel de l'UI d'objectif.
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)
endSuivre les points
Maintenant que les joueurs ont un objectif pour le round, le jeu doit garder une trace des points de chaque équipe jusqu'à ce qu'ils atteignent leur objectif. Bien que le comportement par défaut du service Teams regroupe automatiquement chaque joueur sous son é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 rounds car si un joueur marque puis quitte avant la fin du round, sa contribution est déduite du tableau des scores dès qu'il se déconnecte du jeu.
Pour s'assurer que cela ne se produise pas et que chaque contribution vers l'objectif 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 dans le composant UI d'objectif.
Lorsqu'il 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.
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 valider que l'attribut teamColor menthe de TeamACounter et l'attribut teamColor rose carnation de TeamBCounter correspondent tous deux aux propriétés Team.Color correspondantes sous le service Teams. Si c'est le cas, il retourne les deux équipes.
local function getTeamFromTeamColor(teamColor: Color3): Team?
for _, team in Teams:GetTeams() do
if team.TeamColor == teamColor then
return team
end
end
return nil
endLorsque cela se produit, startSyncingTeamPoints définit les objets TextLabel des deux compteurs d'équipe sur leurs valeurs teamPoints correspondantes, et continue de les mettre à jour chaque fois qu'un joueur marque un point en éliminant un autre joueur de l'équipe adverse.
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é jusqu'à présent dans cette section s'est concentré sur la façon de suivre les points sur 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 le round. Si vous revenez à ServerScriptService ⟩ Gameplay ⟩ Scoring, vous pouvez voir que le script de module commence par créer un événement liant, qui sera déclenché chaque fois qu'un joueur marque un point.
local 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.
- Déclenche l'événement liant mentionné précédemment avec à la fois l'équipe du joueur et son score.
Ce processus maintient efficacement à la fois le client et le serveur alignés concernant les scores individuels des joueurs et leurs scores d'équipe.
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)
endAfficher les résultats
Alors que les joueurs s'éliminent mutuellement et marquent des points pour leur équipe, ServerScriptService ⟩ Gameplay ⟩ Rounds vérifie si l'équipe qui a marqué a atteint l'objectif du round. 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 son équipe.
-- Vérifier si le round est terminé après chaque score
local team: Team
local score: number = 0
while score < TEAM_SCORE_LIMIT do
team, score = Scoring.teamScoreChanged:Wait()
end
-- Afficher l'équipe gagnante
for _, player in Players:GetPlayers() do
-- Envoyer à quel équipe le joueur appartient à la fin du round
-- car l'équipe du joueur est sur le point d'être supprimée, donc le client
-- ne pourra pas vérifier sa propre équipe
roundWinnerRemote:FireClient(player, team, player.Team)
endLe 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 du round 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 sur les résultats du round sous la forme d'un écran UI qui affiche un texte de victoire, et un clip audio qui joue un son joyeux. À l'inverse, si un joueur n'est pas dans l'équipe qui a marqué le point gagnant, il reçoit un écran UI qui affiche un texte de défaite, et un clip audio qui joue un son sinistre.
local function onRoundWinner(winner: Team, localTeam: Team?)
local victoryDefeatText = "Round terminé !"
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
endRéinitialiser les équipes
En même temps que ServerScriptService ⟩ Gameplay ⟩ Rounds vérifie qu'une équipe a atteint l'objectif du round 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 du round. Cela commence le processus de fin formelle du round 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 apparaître indépendamment de leur statut d'équipe. Cela signifie que le hall devient le seul endroit où les joueurs peuvent apparaître après avoir été déconnectés du round.
-- Envoyer tout le monde au hall
playerAddedConnection:Disconnect()
neutralSpawn.Neutral = true
spawnPlayersInLobby(Players:GetPlayers())Après avoir attendu dix secondes pour une intermission, le script serveur Rounds recommence la boucle en réinitialisant les scores de tout le monde et en les triant dans de nouvelles équipes. L'exemple répète ce processus cyclique de round jusqu'à ce qu'il n'y ait plus de joueurs dans le serveur.
Maintenant que les joueurs peuvent apparaître dans la carte avec leur propre équipe et jouer un round complet, la prochaine section vous apprend les scripts derrière le comportement de chaque blaster.