Spawning est le processus de création d'un objet ou d'un personnage dans une expérience, et respawning est le processus d'ajout d'un objet ou d'un personnage dans une expérience après qu'un joueur atteigne une condition de suppression, telle qu'une santé de personnage atteignant zéro ou tombant de la carte. Les deux processus sont importants car ils garantissent que les joueurs peuvent rejoindre votre expérience et continuer à jouer
En utilisant l'expérience de laser de test de génération comme référence, cette section du tutoriel vous apprend à utiliser et à personnaliser les fonctionnalités intégrées de Roblox pour gérer la génération et la réapparition, y compris les conseils de script sur :
- Configurer des lieux d'apparition afin que les joueurs ne puissent apparaître que dans la zone d'apparition de leur équipe.
- Ajouter de nouveaux joueurs et de leur personnage à la manche à mesure qu'ils rejoignent l'expérience.
- Personnalisation des champs de force qui empêche les joueurs de générer et de réapparaître des dommages.
- Gestion du client pour que le jeu fonctionne correctement au bon moment.
- Réapparition des personnages après qu'ils aient été marqués à l'extérieur de la manche.
- Exécuter de petites actions mineures qui sont cruciales pour définir les paramètres du jeu et du personnage.
Cette section inclut beaucoup de contenu de script, mais au lieu d'écrire tout à partir de zéro lors de la création d'une expérience, il vous encourage à utiliser les composants existants, à itérer rapidement et à déterminer les systèmes qui nécessitent une implémentation personnalisée pour correspondre à votre vision. Après avoir terminé cette section, vous apprendrez à implémenter un jeu basé sur des manches qui suit les points, surveille l'état du joueur et affiche les résultats des manches.
Configurer les lieux d'apparition
Si vous testiez l'expérience en ce moment, tous les joueurs apparaîtraient au hasard dans l'un des objets suivants dans la zone de génération de l'équipe verte ou dans l'un des objets suivants dans la zone de génération de l'équipe rose. Cela présente un problème de gameplay où les joueurs pourraient taguer les uns les autres dans chaque zone de génération tant que le champ de force de l'adversaire disparaît.
Pour combattre ce problème, l'expérience de marquage laser utilise les deux emplacements d'apparition avec un Neutral propriété de set à false pour restreindre les joueurs de l'équipe adverse à apparaître dans la tutoriel
- TeamASpawn – Le lieu d'apparition dans la zone d'apparition de l'équipe verte avec un ensemble de propriété TeamColor défini sur Mint .
- ÉquipeBSpawn – Le lieu d'apparition dans la zone d'apparition de l'équipe rose avec une propriété TeamColor définie sur Carnation Pink .
Lorsqu'un joueur rejoint l'expérience, ServerScriptService > Gameplay > Rounds > 1> Rounds1> > 4> spawnePlayersInMap4> vérifie le nombre de joueurs dans chaque équipe, puis renvoie l'équipe avec le moins de joueurs.
spawnJoueurs dans la carte
local function getSmallestTeam(): Team
local teams = Teams:GetTeams()
-- Trier les équipes de plus en plus petites à plus en plus grandes
table.sort(teams, function(teamA: Team, teamB: Team)
return #teamA:GetPlayers() < #teamB:GetPlayers()
end)
-- Renvoiez l'équipe la plus petite
return teams[1]
end
Une fois qu'il sait l'équipe avec le moins de joueurs, il trie le joueur dans cette équipe, définit leur propriété Player.Neutral sur false afin que le joueur ne puisse que générer et réapparaître à leur lieu d'apparition, puis définit leur PlayerState sur 1> SelectingBlaster1>, que vous apprendrez plus tard
spawnJoueurs dans la carte
local function spawnPlayersInMap(players: { Player })
for _, player in players do
player.Team = getSmallestTeam()
player.Neutral = false
player:SetAttribute(PlayerAttribute.playerState, PlayerState.SelectingBlaster)
task.spawn(function()
player:LoadCharacter()
end)
end
end
Si vous examinez Workspace > World > Map > 1> Spawns1>, vous pouvez voir qu'il y a un autre lieu d'apparition
Par exemple, si la manche est active, la propriété Neutral définie sur faux afin que spawnPlayersInMap puisse trier
Pour démontrer, si vous examinez ServerScriptService > Gameplay > Rounds > 1> SpawnPlayersInLobby1>, qui s'exécute à la fin d'un tour, vous pouvez voir que pour chaque joueur qui est passé dans la table 4> players: Player4>, le script :
- Définit leur propriété Player.Neutral sur vrai pour réinitialiser automatiquement leur Player.Team à zéro, ce qui permet au joueur de réapparaître dans le lobby lorsqu'une manche n'est pas active, car la propriété Neutral de leur lieu de production est également réglée sur 1>vrai1>.
- Change leur PlayerState en InLobby pour supprimer les visuels de l'interface joueurdu blaster et de la première personne.
Pour plus d'informations sur la zone de neutralité et sa fonctionnalité pour chaque tour, voir Ajouter des tours dans la prochaine section du tutoriel.
spawnJoueursDansLobby
local function spawnPlayersInLobby(players: { Player })
for _, player in players do
player.Neutral = true
player:SetAttribute(PlayerAttribute.playerState, PlayerState.InLobby)
task.spawn(function()
player:LoadCharacter()
end)
end
end
Connectez de nouveaux joueurs
Le code Luau dans Studio est souvent basé sur des événements, ce qui signifie que les scripts écoutent des événements à partir d'un service Roblox, puis appellent une fonction en réponse. Par exemple, lors de l'ajout de nouveaux joueurs à une expérience multijoueur, il doit y avoir un événement qui gère tout ce dont les joueurs doivent se connecter avec succès. Dans l'exemple de la balise laser, cet événement correspondant est Players.PlayerAdded:Connect .
Players.PlayerAdded:Connect fait partie de plusieurs scripts dans l'expérience. Si vous utilisez le raccourci de Ctrl/Commande+Shift+F et recherchez après Players.PlayerAdded:Connect, les résultats fournissent un bon point de départ pour comprendre le paramètre initial de l'expérience.
Pour démontrer, ouvrez ServerScriptService > SetupHumanoid . La distinction entre Player et 2> Class.Player.Character|Character2> est la clé de la compréhension de ce script :
- Les joueurs doivent choisir un blaster et être ajoutés au classements. Les personnages doivent apparaître et recevoir un blaster.
SetupHumanoid vérifie immédiatement si le joueur a un personnage (vient de rejoindre) ou non (est en train de renaître). Après qu'il ait trouvé un, il appelle onCharacter
setupHumanoidAsync
local function setupHumanoidAsync(player: Player, humanoid: Humanoid)
humanoid.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.Subject
humanoid.NameDisplayDistance = 1000
humanoid.HealthDisplayDistance = 1000
humanoid.NameOcclusion = Enum.NameOcclusion.OccludeAll
humanoid.HealthDisplayType = Enum.HumanoidHealthDisplayType.AlwaysOn
humanoid.BreakJointsOnDeath = false
humanoid.Died:Wait()
onHumanoidDied(player, humanoid)
end
L'important note avec ce script est que les propriétés sont complètement optionnelles, ce qui signifie que si vous supprimez les six premières lignes de la fonction, l'expérience fonctionne toujours correctement. Au lieu d'être des exigences fonctionnelles, chaque propriété vous permet de prendre des décisions de conception qui répondent à vos objectifs de jeu. Par exemple :
- Si vous souhaitez que les noms de personnages s'affichent à des distances plus rapprochées, réduisez la valeur de Humanoid.NameDisplayDistance .
- Si vous souhaitez seulement la santé d'un personnage à afficher si elle est inférieure à 100 %%, définissez Humanoid.HealthDisplayType à afficher quand elle est endommagée .
- Si vous voulez que les personnages se brisent lorsque leur santé atteint 0, définissez Humanoid.BreakJointsOnDeath à Vrai .
Si vous changez les valeurs de ces propriétés, il est important de tester le jeu pour que vous puissiez voir l'impact de vos nouvelles paramètres. Vous pouvez recréer ce que les joueurs expérimentent dans un environnement multijoueur en sélectionnant au moins deux personnages dans la section Clients et serveurs de l'onglet Test .
Un autre exemple de l'événement Players.PlayerAdded:Connect est dans ServerScriptService > PlayerStateHandler . Comme dans l'exemple précédent, 1> PlayerStateHandler1> vérifie
Gestionnaire de l'état des joueurs
local function onPlayerAdded(player: Player)
player.CharacterAdded:Connect(function()
if not player.Neutral then
player:SetAttribute(PlayerAttribute.playerState, PlayerState.SelectingBlaster)
onPlayerStateChanged(player, PlayerState.SelectingBlaster)
end
end)
Une variable spécifique dans PlayerStateHandler nécessite une discussion: attributeChangedConnectionByPlayer. Ce tableau stocke tous les joueurs et leurs Connections à l'aide de laquelle
Gestionnaire de l'état des joueurs
local attributeChangedConnectionByPlayer = {}
local function onPlayerAdded(player: Player)
-- Gérez toutes les futures mises à jour sur l'état du joueur
attributeChangedConnectionByPlayer[player] = player
:GetAttributeChangedSignal(PlayerAttribute.playerState)
:Connect(function()
local newPlayerState = player:GetAttribute(PlayerAttribute.playerState)
onPlayerStateChanged(player, newPlayerState)
end)
end
-- Déconnectez-vous de la connexion modifiée lorsque le joueur quitte
local function onPlayerRemoving(player: Player)
if attributeChangedConnectionByPlayer[player] then
attributeChangedConnectionByPlayer[player]:Disconnect()
attributeChangedConnectionByPlayer[player] = nil
end
end
Vous pouvez voir que les deux fonctions connectées dans onPlayerAdded() appellent onPlayerStateChanged() . Lors de l'initialisation après qu'un joueur trie dans une équipe, onPlayerAdded()
Gestionnaire de l'état des joueurs
local function onPlayerStateChanged(player: Player, newPlayerState: string)
-- L'état du laser est « Prêt » seulement si l'état du joueur est « Jouer »
local newBlasterState = if newPlayerState == PlayerState.Playing then BlasterState.Ready else BlasterState.Disabled
-- Planifiez la logique de champ de force de destruction lorsque le joueur commence à jouer
if newPlayerState == PlayerState.Playing then
scheduleDestroyForceField(player)
end
player:SetAttribute(PlayerAttribute.blasterStateServer, newBlasterState)
end
Si vous ajoutez des points d'arrêt ou même une simple déclaration print()</
Personnaliser les champs de force
Au lieu d'utiliser une implémentation personnalisée, l'expérience de laser de classe personnalisé utilise la classe ForceField intégrée de Studio pour empêcher les joueurs de subir des dommages pendant qu'ils sélectionnent leur laser. Cela garantit que le seul
Semblable à setupHumanoidAsync , la plupart des lignes dans ForceFieldClientVisuals sont optionnelles. Par exemple, si vous commentez le contenu de la fonction comme le script suivant, l'expérience utilise le champ de force par défaut au lieu du champ de force hexagonal dans StarterGui > 1> ForceFieldGui1>.
Commentaires sur les propriétés dans ForceFieldClientVisuals
local function onCharacterAddedAsync(character: Model)
-- forceField local = personnage : WaitForChild("ForceField", 3)
-- si ce n'est pas forceField alors
-- renvoyer
-- terminer
-- forceField.Visible = faux
-- localPlayer.PlayerGui:WaitForChild("ForceFieldGui").Enabled = vrai
-- forceField.Destroying:Wait()
-- localPlayer.PlayerGui.ForceFieldGui.Enabled = faux
end
Puisque le champ de force personnalisé n'est pas un nouvel ParticleEmitter , le script ForceFieldClientVisuals ne modifie que les visuels de première personne pour chaque joueur, pas les visuels de troisième personne lorsque les joueurs regardent les autres joueurs. Les visuels de troisième personne conservent l'apparence par défaut de Roblox.
Les champs de force sont utiles parce qu'ils fournissent aux joueurs le temps qu'ils entrent et se respawnent sans avoir à se soucier des joueurs ennemis, mais ils finissent par disparaître pour le partieprincipal de laser tag. Le script qui gère la suppression des champs de force est dans ReplicatedStorage > scheduleDestroyForceField , et il vérifie trois conditions uniques :
- Après que les joueurs aient choisi un blaster, les champs de force doivent durer assez longtemps pour permettre aux joueurs d'acclimater à leur environnement.
- Pendant cette période d'acclimat, les champs de force ne peuvent pas être un avantage, donc ils doivent disparaître au moment où un joueur lance son blaster.
- Les champs de force doivent disparaître lorsque les joueurs réinitialisent leurs personnages, soit avant l'explosion, soit avant la fin du temps de vie du champ de force.
Chacun de ces vérifications dans le scheduleDestroyForceField script call endForceField() pour ces conditions.
scheduleForceFieldDestruction
-- Terminez le champ de force si le joueur fait exploser
local blasterStateAttribute = getBlasterStateAttribute()
attributeChangedConnection = player:GetAttributeChangedSignal(blasterStateAttribute):Connect(function()
local currentBlasterState = player:GetAttribute(blasterStateAttribute)
if currentBlasterState == BlasterState.Blasting then
endForceField()
end
end)
-- Forcer le champ de force si le joueur se réinitialise
characterRespawnedConnection = player.CharacterRemoving:Connect(endForceField)
-- Forcer le champ de force après 8 secondes
task.delay(MAX_FORCE_FIELD_TIME, endForceField)
endForceField() inclut une déclaration if étrange autour du forceFieldEnded boîtier. Étant donné que les vérifications s'exécuteront de manière séquentielle, le script peut appeler la fonction 0> endForceField0> deux ou même trois fois. La fonction endForceField()3> garantit que la fonction ne dé
scheduleForceFieldDestruction
local function endForceField()
if forceFieldEnded then
return
end
forceFieldEnded = true
attributeChangedConnection:Disconnect()
characterRespawnedConnection:Disconnect()
destroyForceField(player)
end
Gérer l'état du client
Bien que la plupart de cette section se concentre sur ServerScriptService > PlayerStateHandler , il y a un autre script du même nom dans ReplicatedStorage . La raison du split est l'architecture client-serveur :
Le client doit comprendre l'information sur l'état du joueur afin qu'il puisse répondre appropriatement en temps réel, comme afficher les éléments d'interface utilisateur corrects ou permettre aux joueurs de se déplacer et d'exploser.
Le serveur a besoin de toutes ces mêmes informations pour pouvoir empêcher les exploits. Par exemple, le serveur a également besoin d'un état de joueur pour exécuter des actions comme générer et équiper des personnages, désactiver les champs de force et afficher un classements. C'est pourquoi ce script est dans ReplicatedStorage et non un lieu côté client.
Pour voir cette logique de coeur, réparez le script suivant dans ReplicatedStorage > PlayerStateHandler qui vérifie l'état actuel de l'utilisateur, puis appelle la fonction appropriée qui gère les actions correspondantes pour cet état.
Gestionnaire de l'état des joueurs
local function onPlayerStateChanged(newPlayerState: string)
if newPlayerState == PlayerState.SelectingBlaster then
onSelectingBlaster()
elseif newPlayerState == PlayerState.Playing then
onPlaying()
elseif newPlayerState == PlayerState.TaggedOut then
onTaggedOut()
elseif newPlayerState == PlayerState.InLobby then
onInLobby()
else
warn(`Invalid player state ({newPlayerState})`)
end
end
Toutes les réponses d'événements sont logiquement groupées ensemble dans ce script parce qu'elles nécessitent un comportement similaire pour activer ou désactiver les contrôles des joueurs, le mouvement de la caméra et quelle couche d'interface utilisateur est visible. Par exemple, pendant la sélection du blaster, les joueurs doivent être à la fois invulnérables et incapables de se déplacer. Pour démontrer, si vous v
Gestionnaire de l'état des joueurs
local function onSelectingBlaster()
togglePlayerCamera(true)
togglePlayerMovement(false)
setGuiExclusivelyEnabled(playerGui.PickABlasterGui)
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end
La fonction onPlaying() est similaire. Elle permet le mouvement, les transition à l'afficheur principal (HUD), l'activation du blaster et l'appel de la même fonction de champ de force que le serveur.
Gestionnaire de l'état des joueurs
local function onPlaying()
togglePlayerMovement(true)
setGuiExclusivelyEnabled(playerGui.HUDGui)
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Ready)
scheduleDestroyForceField()
end
Réapparition des personnages
L'expérience de laser tag de génération de caractères renvoie le personnage dans une boucle à travers l'état onTaggedOut() dans ReplicatedStorage > PlayerStateHandler . Comme l'expérience de laser tag de
Gestionnaire de l'état des joueurs
local function onTaggedOut()
-- Désactiver les contrôles lorsqu'il est démarqué
togglePlayerMovement(false)
togglePlayerCamera(false)
setGuiExclusivelyEnabled(playerGui.OutStateGui)
-- Désactivez le blaster pendant que vous êtes désactivé
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end
Si vous voulez tester ce comportement, vous pouvez appuyer sur Esc, naviguer dans l'onglet paramètres, puis cliquer sur le bouton Réinitialiser le personnage. Remarquez que lorsque vous activez l'écran de réapparition, vous ne pouvez pas mouvement, faire pivoter la caméra ou exploser votre blaster.
Il est important de noter que ce script ne réapparaît pas vraiment les personnages, il les arrête simplement d'ag
Lorsque les joueurs réapparaissent dans la manche, ils réapparaissent à leur lieu d'apparition d'équipe selon la propriété SpawnLocation.TeamColor. Pour personnaliser le temps de réapparition, vous pouvez ajouter la ligne suivante au sommet de SetupHumanoid. Pour en savoir plus sur cette technologie, voir Players.RespawnTime.
SetupHumanoid
local Players = game:GetService("Players")Players.RespawnTime = 10 -- new line, in seconds
Diverses modifications
Dans le cadre de l'initialisation, l'expérience de marquage laser de l'échantillon effectue également quelques étapes petites, mais cruciales :
L'expérience inclut un script vide nommé StarterPlayer > StarterCharacterScripts > Health qui désactive la régénération de santé par défaut de Roblox. Pour une explication de ce comportement de la propriété, voir 1> Class.Humanoid.Health1> .
L'expérience utilise une caméra à première personne en définissant la propriété StarterPlayer.CameraMode.LockFirstPerson. Remarquez que si vous souhaitez permettre aux utilisateurs de changer entre les caméras à première et à troisième personne, vous devez modifier le programme de propriété plutôt que de simplement le définir une fois dans Studio, et de modifier les contrôles et l'interface utilisateur pour compenser le changement de perspective.
L'expérience utilise le classement Roblox intégré avec l'unité de «points», que les joueurs gagnent chaque fois qu'ils taguent un autre joueur. Vous pouvez voir la configuration dans ServerScriptService > SetupLeaderboard , mais In-Experience Leaderboards offre
Maintenant que les joueurs peuvent régénération, apparition, choisissez un blaster et visez-le d'un point de voirà la première personne, la prochaine section vous apprend les scripts derrière la création d'un partiede manches.