Spawnen ist der Prozess, bei dem ein Objekt oder ein Charakter in einem Erlebnis erstellt wird, und Respawnen ist der Prozess, der ein Objekt oder einen Charakter in einem Erlebnis nach dem Erreichen einer Entfernungszone, wie z. B. der Gesundheit eines Charakters, wieder in ein Erlebnis fügt. Beide Prozesse sind wichtig, da sie sicherstellen, dass Spieler Ihrem Erlebnis beitreten können, und weiter sp
Dieser Abschnitt des Tutorials verwendet die Erfahrung mit der Laser-Tag-Technologie als Referenz, um dir zu zeigen, wie du die integrierten Funktionen von Roblox verwenden und anpassen kannst, um Spawns und Respawns zu behandeln, einschließlich Skript-Anleitung zu:
- Konfigurieren von Spawn-Standorten, damit Spieler nur in der Spawn-Zone ihres Teams spawnen können.
- Füge neue Spieler und ihre Charaktere zu der Runde hinzu, wenn sie sich dem Erlebnis anschließen.
- Benutzerdefinierte Kraftfelder, die verhindern, dass Spieler Schaden erleiden und respawnen.
- Steuerung des Client-Status, damit das Spiel im richtigen Zeitpunkt richtig funktioniert.
- Respawnen Sie Charaktere, nachdem sie aus der Runde ausgeworfen wurden.
- Durchführung kleiner, ungeschickter Aktionen, die für die Festlegung von Spiel- und Charakterparametern von grundlegender Bedeutung sind.
Dieser Abschnitt enthält eine Menge Skript-Inhalte, aber anstatt alles von Grund auf neu zu schreiben, wenn Sie ein Erlebnis erstellen, ermutigt Sie, bestehende Komponenten zu nutzen, schnell zu wiederholen und herauszufinden, welche Systeme eine benutzerdefinierte Lösung benötigen, um Ihren Vision zu entsprechen. Nachdem Sie diesen Abschnitt abgeschlossen haben, werden Sie lernen, wie Sie rundenbasierte Spielplay implementieren, die Punkte verfolgt, den Zustand des Spielers anzeigt und Runden-Ergeb
Spawn-Standorte konfigurieren
Wenn Sie die Erfahrung jetzt spielen würden, würden alle Spieler zufällig auf dem SpawnLocation -Objekt in der Spawn-Zone des grünen Teams oder dem SpawnLocation -Objekt in der Spawn-Zone des rosa Teams spawnen. Dies präsentiert ein Spielproblem, bei dem Spieler innerhalb jeder Spawn-Zone sofort nachdem das Kraftfeld ihres Gegners verschwindet taggen
Um dieses Problem zu bekämpfen, konfiguriert die Tutorialbeide Spawn-Orte mit einem Neutral-Eigenschaft, die auf false gesetzt ist, um die Spieler des gegnerischen Teams zu begrenzen
- TeamASpawn – Die Spawn-Location in der Spawn-Zone des grünen Teams mit einem TeamColor-Eigenschaftsset auf Mint .
- TeamBSpawn – Die Spawn-Location in der Spawn-Zone des rosa Teams mit einem TeamColor-Eigenschaft auf Carnation Pink eingestellt.
Wenn ein Spieler der Erlebnisbeitritt, ServerScriptService > Spielplay > Runden > 1> SpielerInMap1> prüft, wie viele Spieler bereits in jedem Team sind, und gibt dann das Team mit der minimalen Anzahl von Spielern zurück.
spawnSpielerInMap
local function getSmallestTeam(): Team
local teams = Teams:GetTeams()
-- Sortiere Teams in aufsteigender Reihenfolge von kleinstem bis größtem
table.sort(teams, function(teamA: Team, teamB: Team)
return #teamA:GetPlayers() < #teamB:GetPlayers()
end)
-- Rückgabe der kleinsten Team
return teams[1]
end
Sobald es die Team mit der minimalen Anzahl von Spielern kennt, sortiert das Team den Spieler in dieses Team, setzt seine Player.Neutral -Eigenschaft auf false , damit der Spieler nur an seinem Team spawnen und respawnen kann, und setzt seine PlayerState auf 1> SelectingBlaster1>, was Sie später im Tutorial erläern.
spawnSpielerInMap
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
Wenn Sie Workspace > World > Map > 1> Spawns1> , Sie können sehen, dass es eine weitere Spawn-Location auf der
Zum Beispiel, wenn die Runde aktiv ist, setzt die Neutral -Eigenschaft auf false, sodass spawnPlayersInMap
Um zu demonstrieren, wenn Sie ServerScriptService > Gameplay > Runden > 1> SpawnPlayersInLobby1> , der am Ende einer Runde ausgeführt wird, können Sie sehen, dass für jeden Spieler, der in die 4> players: Player 4> Tabelle passiert, das Skript, das. PL: die Skripts:
- Setzt ihre Player.Neutral-Eigenschaft auf true, um automatisch ihr Player.Team auf null zurückzusetzen, damit der Spieler in der Lobby wiederbelebt, wenn keine Runde aktiv ist, als der Spawn-Ort Neutral ist.
- Ändert ihre PlayerState zu InLobby, um den Blaster des Spieler:inund die First-Person-UI-Visuals zu entfernen.
For more information on the neutral spawn zone and its functionality for each round, see Runden hinzufügen in the next section of the Tutorial.
spawnSpielerInLobby
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
Neue Spieler verbinden
Luau-Code in Studio ist oft event-basiert, was bedeutet, dass Skripte auf Ereignisse aus einer Roblox-Dienstleistung hören und dann eine Funktion aufrufen, um darauf zu reagieren. Zum Beispiel, wenn Sie neue Spieler zu einer Multiplayer-Erlebnissen hinzufügen, muss ein Ereignis sein, das alles notwendige für die erfolgreiche Verbindung mit den Spielern handelt. In der Connectist dieses entsprechende Ereignis <
Players.PlayerAdded:Connect ist ein Teil mehrerer Skripte in der Erlebnis. Wenn Sie den Ctrl/cmd+Shift+F-Shortcut und die Suche nach Players.PlayerAdded:Connect verwenden und die Ergebnisse suchen, bieten die Ergebnisse einen guten Ausgangspunkt für das Verständnis des Erlebnis.
Um zu demonstrieren, öffnen Sie ServerScriptService > SetupHumanoid . Die Unterscheidung zwischen Player und 1> Class.Player.Character|Character1> ist der Schlüssel zu verstehen dieses Skript, das. PL: die Skripts:
- Spieler müssen einen Blaster auswählen und in die Bestenlisteaufgenommen werden. Charaktere müssen spawnen und einen Blaster erhalten.
SetupHumanoid sofort prüft, ob der Spieler einen Charakter (gerade beigetreten) oder nicht (wird respawned) hat. Nachdem es einen gefunden hat, ruft es onCharacterAdded()
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
Die wichtige Notiz mit diesem Skript ist, dass die Eigenschaften vollständig optional sind, was bedeutet, dass, wenn Sie die ersten sechs Zeilen der Funktion entfernen, die Erfahrung immer noch richtig funktioniert. Statt funktionaler Anforderungen kann jede Eigenschaft Ihnen Designentscheidungen ermöglichen, die Ihren Spielablaufzielen entsprechen. Zum Beispiel:
- Wenn Sie möchten, dass Charakternamen in größeren Entfernungen angezeigt werden, reduzieren Sie den Wert von Humanoid.NameDisplayDistance.
- Wenn Sie nur die Gesundheit eines Charakters anzeigen möchten, wenn sie unter 100% ist, setzen Sie Humanoid.HealthDisplayType auf Anzeigen bei Schaden .
- Wenn Sie möchten, dass die Charaktere zerbrechen, wenn ihre Gesundheit 0 erreicht, setzen Sie Humanoid.BreakJointsOnDeath auf Wahrheit .
Wenn Sie die Werte dieser Eigenschaften ändern, ist es wichtig, dass Sie das Spiel testen, damit Sie die Auswirkungen Ihrer neuen Einstellungen sehen können. Sie können das, was Spieler in einem mehrere Spieler-Umgebung erleben, im Clients and Servers -Abschnitt der Test -Registerkarte wiederherstellen, indem Sie mindestens zwei Zeichen aus der Clients and Servers-Sektion der 1>Test1>-Registerkarte auswählen.
Ein weiteres Beispiel des Players.PlayerAdded:Connect-Ereignisses finden Sie in ServerScriptService > PlayerStateHandler . Wie im vorherigen Beispiel prüft der Skript sofort nach einem Charakter.
Spielerzustands-Behandler
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)
Eine bestimmte Variable in PlayerStateHandler erfordert Diskussion: attributeChangedConnectionByPlayer . Diese Tabelle speichert alle Spieler und ihre Connections an den
Spielerzustands-Behandler
local attributeChangedConnectionByPlayer = {}
local function onPlayerAdded(player: Player)
-- Behandeln Sie alle zukünftigen Updates im Zustand des Spielers
attributeChangedConnectionByPlayer[player] = player
:GetAttributeChangedSignal(PlayerAttribute.playerState)
:Connect(function()
local newPlayerState = player:GetAttribute(PlayerAttribute.playerState)
onPlayerStateChanged(player, newPlayerState)
end)
end
-- Verbindung vom Spieler verlassen, wenn die zugeordnete Verbindung getrennt wird
local function onPlayerRemoving(player: Player)
if attributeChangedConnectionByPlayer[player] then
attributeChangedConnectionByPlayer[player]:Disconnect()
attributeChangedConnectionByPlayer[player] = nil
end
end
Sie können sehen, dass beide verbundene Funktionen in onPlayerAdded() aufrufen onPlayerStateChanged() . Während der ersten Einrichtung nach dem Zusammenführen eines Spielers in ein Team,
Spielerzustands-Behandler
local function onPlayerStateChanged(player: Player, newPlayerState: string)
-- Blaster-Status ist nur "Bereit", wenn der Spieler-Status "Spielt" ist
local newBlasterState = if newPlayerState == PlayerState.Playing then BlasterState.Ready else BlasterState.Disabled
-- Planen Sie die Zerstörungsfeldlogik, wenn der Spieler beginnt zu spielen
if newPlayerState == PlayerState.Playing then
scheduleDestroyForceField(player)
end
player:SetAttribute(PlayerAttribute.blasterStateServer, newBlasterState)
end
Wenn du print()-Statistiken hinzufügst oder
Kraftfelder anpassen
Statt benutzerdefinierte Lösungen zu verwenden, verwendet die Probe-Laser-Tag-Erlebnisse die integrierte ForceField -Klasse von Studio, um die Spieler daran zu hindern, Schaden zu erleiden, während sie mit ihrem Blaster auswählen
Ähnlich wie setupHumanoidAsync , die meisten Zeilen in ForceFieldClientVisuals sind optional. Zum Beispiel, wenn Sie die Inhalte der Funktion wie das folgende Skript auskommentieren, verwendet die Erfahrung das Standard-Feld anstelle des hexagonalen Skripts in StarterGui > 1>ForceFieldGui1>.
Kommentieren von Eigenschaften in ForceFieldClientVisuals
local function onCharacterAddedAsync(character: Model)
-- lokale Kraftfeld = Charakter:WaitForChild("ForceField", 3)
-- wenn nicht forceField dann
-- zurückgeben
-- beenden
-- forceField.Visible = falsch
-- localPlayer.PlayerGui:WaitForChild("ForceFieldGui").Enabled = wahr
-- forceField.Destroying:Warte()
-- localPlayer.PlayerGui.ForceFieldGui.Enabled = falsch
end
Da das benutzerdefinierte Kraftfeld ein GUI ist, nicht ein neues ParticleEmitter, betrifft das Skript ForceFieldClientVisuals nur die visuellen Effekte für jeden Spieler:in, nicht die visuellen Effekte für Dritte, wenn Spieler auf andere Spieler schauen. Die visuellen Effekte behalten die Aussehen. Weit
Kraftfelder sind nützlich, da sie den Spielern genügend Zeit bieten, um zwischen dem Spawnen und Respawnen zu warten, ohne sich um feindliche Spieler zu sorgen, aber letztendlich müssen sie für das Gameplaybeseitigt werden. Das Skript, das die Kraftfeldentfernung behandelt, befindet sich in ReplicatedStorage > scheduleDestroyForceField und prüft auf drei einzigartige Bedingungen:
- Nachdem Spieler einen Blaster ausgewählt haben, müssen Kraftfelder lange genug dauern, damit Spieler sich an ihre Umgebung anpassen können.
- Während dieser Ankündigungszeit können Kraftfelder kein Vorteil sein, daher müssen sie sofort nach dem Blast eines Spielers verschwinden.
- Force Felder müssen verschwinden wenn Spieler ihre Charaktere entweder vor dem Explosionszeitpunkt oder vor Ablauf der Zeit des Force Feldes zurücksetzen.
Jeder dieser Checks in der scheduleDestroyForceField Skriptanrufe endForceField() für diese Bedingungen.
ZeitpläneZerstörenKraftfeld
-- Ende Kraftfeld wenn Spieler schießt
local blasterStateAttribute = getBlasterStateAttribute()
attributeChangedConnection = player:GetAttributeChangedSignal(blasterStateAttribute):Connect(function()
local currentBlasterState = player:GetAttribute(blasterStateAttribute)
if currentBlasterState == BlasterState.Blasting then
endForceField()
end
end)
-- Ende Kraftfeld, wenn Spieler zurücksetzt
characterRespawnedConnection = player.CharacterRemoving:Connect(endForceField)
-- Ende des Kraftfelds nach 8 Sekunden
task.delay(MAX_FORCE_FIELD_TIME, endForceField)
endForceField() enthält eine scheinbar seltsame if Anweisung um den forceFieldEnded -Boolean. Weil die Prüfungen sequenziell laufen, kann das Skript die Funktion 0> endForceField0> zweimal oder sogar dreimal aufrufen. Die Funktion endForceField()3> garantiert, dass
ZeitpläneZerstörenKraftfeld
local function endForceField()
if forceFieldEnded then
return
end
forceFieldEnded = true
attributeChangedConnection:Disconnect()
characterRespawnedConnection:Disconnect()
destroyForceField(player)
end
Client-Status behandeln
Während die meisten dieser Abschnitte auf ServerScriptService > PlayerStateHandler konzentrieren, gibt es ein anderes Skript mit demselben Namen in ReplicatedStorage . Der Grund für die Aufteilung ist die Client-Server-Architektur:
Der Client muss Spieler-Status-Informationen verstehen, damit er im Echtzeit angemessen auf reagieren kann, z. B. indem er die richtigen Benutzeroberflächenelemente anzeigt oder die Bewegung und Explosion von Spielern aktiviert.
Der Server benötigt all diese gleichen Informationen, um Exploits zu verhindern. Zum Beispiel benötigt der Server auch den Spielerzustand, um Aktionen wie das Spawnen und Ausrüsten von Charaktern, das Deaktivieren von Kraftfeldern und das Anzeigen einer Bestenlistedurchzuführen. Deshalb befindet sich dieses Skript in ReplicatedStorage und nicht in einer rein kundenseitigen Position.
Um diese Kern-Logik zu sehen, überprüfen Sie das folgende Skript in ReplicatedStorage > PlayerStateHandler , das den aktuellen Zustand des Benutzers überprüft und dann die entsprechende Funktion aufruft, die die entsprechenden Aktionen für diesen Zustand ausführt.
Spielerzustands-Behandler
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
Alle Ereignisantworten werden in diesem Skript logisch zusammengeführt, da sie ähnliches Verhalten bei der Aktivierung oder Deaktivierung von Steuerung, der Kamera-Bewegung und der darstellbaren Benutzeroberfläche erfordert. Zum Beispiel müssen Spieler während der Blasterauswahl sowohl unverwundbar sein als auch nicht in der Lage sein, sich zu Verschiebungswerkzeug. Die
Spielerzustands-Behandler
local function onSelectingBlaster()
togglePlayerCamera(true)
togglePlayerMovement(false)
setGuiExclusivelyEnabled(playerGui.PickABlasterGui)
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end
Die onPlaying() Funktion ist ebenso einfach. Sie ermöglicht Bewegungen, Übergänge zum Haupt-Head-up-Anzeige (HUD), aktiviert den Blaster und ruft die gleiche Kraftfeldfunktion auf, wie die Server.
Spielerzustands-Behandler
local function onPlaying()
togglePlayerMovement(true)
setGuiExclusivelyEnabled(playerGui.HUDGui)
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Ready)
scheduleDestroyForceField()
end
Respawn-Charaktere
Die Beispiel-Laser-Tag-Erfahrung behandelt das Respawnen des Charakters zurück in einer Runde durch den onTaggedOut() -Zustand in ReplicatedStorage > PlayerStatusHandler . Wie der 2>onSelecting
Spielerzustands-Behandler
local function onTaggedOut()
-- Steuerelemente deaktivieren, während du mit dem Haken ausgängig bist
togglePlayerMovement(false)
togglePlayerCamera(false)
setGuiExclusivelyEnabled(playerGui.OutStateGui)
-- Blaster deaktivieren, während er mit einem Tag ausgelassen wird
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end
Wenn Sie dieses Verhalten testen möchten, können Sie Esc drücken, zu der Einstellungen -Registerkarte navigieren und dann auf die Schaltfläche Charakter zurücksetzen klicken. Beachten Sie, dass wenn Sie die Wiederbelebensschaltfläche auslösen, nicht Verschiebungswerkzeug, drehen Sie die Kamera oder schießen Sie Ihren Blaster können.
Es ist wichtig zu beachten, dass dieses Skript keine Charaktere tatsächlich respawnen, es stoppt sie nur dav
Wenn Spieler zurück in die Runde respawnen, respawnen sie an der Spawn-Ort ihres Teams gemäß der Eigenschaft SpawnLocation.TeamColor. Um die Respawn-Zeit anzupassen, können Sie die folgende Zeile zum Top von SetupHumanoid hinzufügen. Um mehr über diese Technik zu erfahren, sehen Sie Players.RespawnTime.
SetupHumanoid
local Players = game:GetService("Players")Players.RespawnTime = 10 -- new line, in seconds
Sonstige Einstellungen
Als Teil der ersten Einrichtung führt die Lasertag-Sammlung auch einige kleine, aber kritische Schritte aus:
Das Erlebnis enthält ein leeres Skript namens StarterPlayer > StarterCharacterScripts > Health , das die Standard-Roblox-Gesundheitsregeneration deaktiviert. Für eine Erklärung dieses Eigenschaftenverhaltens, siehe 1> Class.Humanoid.Health1> .
Die Erfahrung verwendet eine First-Person-Kamera, indem Sie die StarterPlayer.CameraMode.LockFirstPerson Eigenschafteneinstellt. Beachten Sie, dass, wenn Sie Benutzern ermöchten, zwischen First- und Third-Person-Kameras zu wechseln, müssen Sie das Eigenschaftsprogrammierungs-Programm ändern, anstatt es einmal in Studio zu setzen, und die Steuerelemente und die Benutzeroberfläche anpassen, um den Änderungsprozess in der Perspektive auszugleichen
Die Erfahrung verwendet die integrierte Roblox-Bestenliste mit der Einheit "Punkte", die Spieler jedes Mal verdienen, wenn sie einen anderen Spieler auslösen. Sie können die Konfiguration in ServerScriptService > Einstellungsleiste und In-Experience-Bestenlisten
Jetzt, da Spieler Spawnkönnen, wählen Sie einen Blaster und zielen Sie ihn aus einer Ansicht, die nächste Sektion erklärt Ihnen die Skripte hinter der Erstellung von rundenbasierten Gameplay.