Spawnen und Respawnen

*Dieser Inhalt wurde mit KI (Beta) übersetzt und kann Fehler enthalten. Um diese Seite auf Englisch zu sehen, klicke hier.

Spawnen ist der Prozess, ein Objekt oder einen Charakter in einem Spiel zu erstellen, und Respawnen ist der Prozess, ein Objekt oder einen Charakter wieder in ein Spiel hinzuzufügen, nachdem sie eine Bedingung für die Entfernung erfüllt haben, wie zum Beispiel das Erreichen von null Lebenspunkten eines Charakters oder das Herunterfallen von der Karte. Beide Prozesse sind wichtig, da sie sicherstellen, dass Spieler deinem Spiel beitreten können und weiterhin spielen können, um ihre Fähigkeiten zu verbessern.

Anhand des Beispiel-Lasertag-Spiels lehrt dich dieser Abschnitt des Tutorials, wie du die integrierten Funktionen von Roblox zum Spawnen und Respawnen nutzen und anpassen kannst, einschließlich Skriptanleitungen zu:

  • Konfigurieren von Spawn-Standorten, damit Spieler nur in die Spawn-Zone ihres Teams spawnen können.
  • Hinzufügen neuer Spieler und ihrer Charaktere zur Runde, während sie dem Spiel beitreten.
  • Anpassen von Kraftfeldern, die Schaden verhindern, während Spieler spawnen und respawnen.
  • Verwalten des Client-Zustands, damit das Gameplay zur richtigen Zeit korrekt funktioniert.
  • Respawnen von Charakteren, nachdem sie aus der Runde getaggt wurden.
  • Ausführen kleiner, verschiedener Aktionen, die entscheidend für die Festlegung von Gameplay- und Charakterparametern sind.

Dieser Abschnitt enthält viele Skriptinhalte, aber anstatt alles von Grund auf neu zu schreiben, wenn du ein Spiel erstellst, ermutigt er dich, vorhandene Komponenten zu nutzen, schnell zu iterieren und herauszufinden, welche Systeme eine benutzerdefinierte Implementierung benötigen, um deiner Vision zu entsprechen. Nachdem du diesen Abschnitt abgeschlossen hast, wirst du lernen, wie man rundenbasiertes Gameplay implementiert, das Punkte verfolgt, den Spielerstatus überwacht und die Rundenergebnisse anzeigt.

Konfigurieren von Spawn-Standorten

Wenn du das Spiel jetzt testen würdest, würden alle Spieler zufällig entweder am SpawnLocation-Objekt in der Spawn-Zone des grünen Teams oder am SpawnLocation-Objekt in der Spawn-Zone des rosa Teams spawnen. Dies stellt ein Gameplay-Problem dar, bei dem Spieler sich innerhalb jeder Spawn-Zone taggen könnten, sobald das Kraftfeld des Gegners verschwindet.

Um dieses Problem zu bekämpfen, konfiguriert das Beispiel-Lasertag-Spiel beide Spawn-Standorte mit einer Neutral-Eigenschaft, die auf false gesetzt ist, um zu verhindern, dass die Spieler des gegnerischen Teams in der falschen Spawn-Zone spawnen, und einer TeamColor-Eigenschaft, die auf den entsprechenden Team.Color-Wert aus Teamfarben zuweisen im vorherigen Abschnitt des Tutorials gesetzt ist:

  • TeamASpawn – Der Spawn-Standort in der Spawn-Zone des grünen Teams mit einer TeamColor-Eigenschaft, die auf Mint gesetzt ist.
  • TeamBSpawn – Der Spawn-Standort in der Spawn-Zone des rosa Teams mit einer TeamColor-Eigenschaft, die auf Carnation Pink gesetzt ist.
TeamASpawn
TeamBSpawn

Wenn ein Spieler dem Spiel beitritt, überprüft ServerScriptServiceGameplayRoundsspawnPlayersInMap, wie viele Spieler bereits in jedem Team sind, und gibt dann das Team mit der geringsten Anzahl von Spielern zurück.

spawnPlayersInMap
local function getSmallestTeam(): Team
local teams = Teams:GetTeams()
-- Sortiere die Teams in aufsteigender Reihenfolge von klein nach groß
table.sort(teams, function(teamA: Team, teamB: Team)
return #teamA:GetPlayers() < #teamB:GetPlayers()
end)
-- Gib das kleinste Team zurück
return teams[1]
end

Sobald es das Team mit der geringsten Anzahl von Spielern kennt, sortiert es den Spieler in dieses Team, setzt die Player.Neutral-Eigenschaft auf false, damit der Spieler nur in die Spawn-Location seines Teams spawnen und respawnen kann, und setzt dann seinen PlayerState auf SelectingBlaster, was du später im Tutorial näher kennenlernen wirst.

spawnPlayersInMap
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 du WorkspaceWorldMapSpawns untersuchst, kannst du sehen, dass es einen weiteren Spawn-Standort auf der Karte gibt: NeutralSpawn. Dieser Spawn-Standort ist einzigartig im Vergleich zu den anderen, da er keine TeamColor-Eigenschaft hat, die auf eines der beiden Teams im Spiel gesetzt ist; stattdessen hat dieser Spawn-Standort eine Neutral-Eigenschaft, die sich ändert, je nachdem, ob eine Runde aktiv ist.

Wenn die Runde aktiv ist, wird die Neutral-Eigenschaft auf false gesetzt, damit spawnPlayersInMap die Spieler in Teams sortieren und sie in die Arena spawnen kann. Wenn die Runde jedoch nicht aktiv ist, wie zum Beispiel in der Zeit zwischen einer Runde und der nächsten, wird die Neutral-Eigenschaft auf true gesetzt, damit Spieler dort spawnen können, unabhängig von ihrem Teamstatus. Dieser Prozess macht den Neutral Spawn-Standort zu einer funktionalen Lobby.

Neutral

Um dies zu demonstrieren, wenn du ServerScriptServiceGameplayRoundsSpawnPlayersInLobby untersuchst, das am Ende einer Runde ausgeführt wird, kannst du sehen, dass für jeden Spieler, der in die players: { Player }-Tabelle übergeben wird, das Skript:

  • Setzt die Player.Neutral-Eigenschaft auf true, um automatisch die Player.Team auf nil zurückzusetzen, sodass der Spieler in der Lobby respawnen kann, wenn eine Runde nicht aktiv ist, da die Neutral-Eigenschaft des Spawn-Standorts ebenfalls auf true gesetzt ist.
  • Ändert seinen PlayerState auf InLobby, um den Blaster und die Benutzeroberflächenvisualisierungen im ersten Person-Modus zu entfernen.

Für weitere Informationen zur neutralen Spawn-Zone und ihrer Funktionalität für jede Runde siehe Runden hinzufügen im nächsten Abschnitt des Tutorials.

spawnPlayersInLobby
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 ereignisgesteuert, was bedeutet, dass Skripte auf Ereignisse von einem Roblox-Dienst hören und dann eine Funktion als Antwort aufrufen. Zum Beispiel muss es ein Ereignis geben, das alles Notwendige behandelt, damit Spieler erfolgreich zu einem Mehrspieler-Spiel verbunden werden. Im Beispiel-Lasertag-Spiel ist dieses entsprechende Ereignis Players.PlayerAdded:Connect.

Players.PlayerAdded:Connect ist Teil mehrerer Skripte im Spiel. Wenn du die Ctrl/Cmd+Shift+F-Tastenkombination verwendest und nach Players.PlayerAdded:Connect suchst, bieten die Ergebnisse einen guten Ausgangspunkt, um die anfängliche Einrichtung des Spiels zu verstehen.

Studios Find All-Fenster mit den hervorgehobenen Ergebnissen von Players.PlayerAdded.

Um dies zu demonstrieren, öffne ServerScriptServiceSetupHumanoid. Der Unterschied zwischen Player und Character ist entscheidend für das Verständnis dieses Skripts:

  • Ein Spieler ist ein verbundener Client, und ein Charakter ist ein Humanoid-Modell.
  • Spieler müssen einen Blaster auswählen und zur Bestenliste hinzugefügt werden. Charaktere müssen spawnen und einen Blaster erhalten.

SetupHumanoid überprüft sofort, ob der Spieler einen Charakter hat (gerade beigetreten) oder nicht (wird respawnt). Nachdem es einen gefunden hat, ruft es onCharacterAdded() auf, erhält das Humanoid-Modell vom Charakter und übergibt es an ServerScriptServiceSetupHumanoidsetupHumanoidAsync zur Anpassung. Nachdem diese Werte gesetzt sind, wartet das Skript darauf, dass die Lebenspunkte des Charakters null erreichen. Du wirst später in diesem Abschnitt des Tutorials mehr über das Respawnen erfahren.

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

Der wichtige Hinweis zu diesem Skript ist, dass die Eigenschaften völlig optional sind, was bedeutet, dass das Spiel auch dann ordnungsgemäß funktioniert, wenn du die ersten sechs Zeilen der Funktion entfernst. Anstatt funktionale Anforderungen zu sein, ermöglichen dir die Eigenschaften, Designentscheidungen zu treffen, die deinen Gameplay-Zielen entsprechen. Zum Beispiel:

  • Wenn du möchtest, dass die Namen der Charaktere in kürzeren Abständen angezeigt werden, reduziere den Wert von Humanoid.NameDisplayDistance.
  • Wenn du möchtest, dass die Lebenspunkte eines Charakters nur angezeigt werden, wenn sie unter 100 % liegen, setze Humanoid.HealthDisplayType auf DisplayWhenDamaged.
  • Wenn du möchtest, dass Charaktere auseinanderbrechen, wenn ihre Lebenspunkte null erreichen, setze Humanoid.BreakJointsOnDeath auf True.

Wenn du die Werte dieser Eigenschaften änderst, ist es wichtig, das Spiel zu testen, damit du die Auswirkungen deiner neuen Einstellungen sehen kannst. Du kannst das, was Spieler in einer Multi-Client-Simulation erleben, nachstellen, indem du mindestens zwei Charaktere in einem Server & Clients-Playtest aus der Mezzanine auswählst.

Server & Clients-Option im Dropdown-Menü der Testmodi der Mezzanine von Studio.

Ein weiteres Beispiel für das Players.PlayerAdded:Connect-Ereignis befindet sich in ServerScriptServicePlayerStateHandler. Genau wie im vorherigen Beispiel überprüft PlayerStateHandler sofort, ob ein Charakter vorhanden ist. Wenn der Spieler sich nicht in der Lobby befindet, setzt das Skript ein Spielerattribut auf den Zustand SelectingBlaster, den Anfangszustand für eine Runde, in der Spieler nach dem Spawnen in die Arena aus zwei verschiedenen Blastertypen auswählen können. Dieser Zustand umfasst auch ein Kraftfeld, das verhindert, dass Spieler Schaden nehmen, während sie ihre Auswahl treffen.

PlayerStateHandler
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 verdient eine Diskussion: attributeChangedConnectionByPlayer. Diese Tabelle speichert alle Spieler und ihre Connections zum GetAttributeChangedSignal. Der Grund, warum diese Verbindung in einer Tabelle gespeichert wird, ist, dass PlayerStateHandler sie trennen kann, wenn der Spieler das Spiel verlässt. Dieser Prozess dient als eine Art Speicherverwaltung, um zu verhindern, dass die Anzahl der Verbindungen im Laufe der Zeit immer größer wird.

PlayerStateHandler
local attributeChangedConnectionByPlayer = {}
local function onPlayerAdded(player: Player)
-- Behandle alle zukünftigen Updates zum Spielerstatus
attributeChangedConnectionByPlayer[player] = player
:GetAttributeChangedSignal(PlayerAttribute.playerState)
:Connect(function()
local newPlayerState = player:GetAttribute(PlayerAttribute.playerState)
onPlayerStateChanged(player, newPlayerState)
end)
end
-- Trenne die Verbindung zum Attribut, wenn der Spieler das Spiel verlässt
local function onPlayerRemoving(player: Player)
if attributeChangedConnectionByPlayer[player] then
attributeChangedConnectionByPlayer[player]:Disconnect()
attributeChangedConnectionByPlayer[player] = nil
end
end

Du kannst sehen, dass beide verbundenen Funktionen in onPlayerAdded() onPlayerStateChanged() aufrufen. Während der anfänglichen Einrichtung, nachdem ein Spieler in ein Team sortiert wurde, setzt onPlayerAdded() den PlayerState auf SelectingBlaster, sodass die erste if-Anweisung falsch ausgewertet wird und der BlasterState deaktiviert wird. Im späteren Abschnitt Blaster implementieren des Tutorials wirst du mehr Details über diesen Prozess erfahren.

PlayerStateHandler
local function onPlayerStateChanged(player: Player, newPlayerState: string)
-- Blaster-Zustand ist 'Bereit', wenn der Spielerstatus 'Spielen' ist
local newBlasterState = if newPlayerState == PlayerState.Playing then BlasterState.Ready else BlasterState.Disabled
-- Plane die Logik zum Zerstören des Kraftfeldes, wenn der Spieler mit dem Spielen beginnt
if newPlayerState == PlayerState.Playing then
scheduleDestroyForceField(player)
end
player:SetAttribute(PlayerAttribute.blasterStateServer, newBlasterState)
end

Wenn du Haltepunkte hinzufügst oder sogar nur eine print()-Anweisung verwendest, kannst du sehen, dass onPlayerStateChanged() häufig im Spiel aufgerufen wird: zum Beispiel während der anfänglichen Einrichtung einer Runde, um sich auf den Hauptcodepfad zu setzen, nachdem der Spieler einen Blaster ausgewählt hat und wenn der Spieler in die Lobby oder den Neutral Spawn-Standort zurückkehrt. Darüber hinaus setzt ServerScriptServiceBlasterSelectedHandler den PlayerState auf Playing, und PlayerStateHandler kann schließlich das Kraftfeld entfernen, indem es scheduleDestroyForceField() aufruft.

Kraftfelder anpassen

Anstatt eine benutzerdefinierte Implementierung zu verwenden, nutzt das Beispiel-Lasertag-Spiel die integrierte ForceField-Klasse von Studio, um zu verhindern, dass Spieler Schaden nehmen, während sie ihren Blaster auswählen. Dies stellt sicher, dass die einzige Voraussetzung für Spieler, mit einem Kraftfeld zu spawnen, darin besteht, Spawn-Standorte mit einer SpawnLocation.Duration-Eigenschaft zu haben, die größer als 0 ist. Das Beispiel verwendet einen willkürlichen Wert von 9.999, um Kraftfelder zu aktivieren, und behandelt die tatsächliche Dauer programmatisch in ReplicatedStorageForceFieldClientVisuals.

Ähnlich wie setupHumanoidAsync sind die meisten Zeilen in ForceFieldClientVisuals optional. Wenn du beispielsweise den Inhalt der Funktion wie im folgenden Skript auskommentierst, verwendet das Spiel das standardmäßige funkelnde Kraftfeld anstelle des hexagonalen Skripts in StarterGuiForceFieldGui.

Commenting Out Properties in ForceFieldClientVisuals
local function onCharacterAddedAsync(character: Model)
-- local forceField = character:WaitForChild("ForceField", 3)
-- if not forceField then
-- return
-- end
-- forceField.Visible = false
-- localPlayer.PlayerGui:WaitForChild("ForceFieldGui").Enabled = true
-- forceField.Destroying:Wait()
-- localPlayer.PlayerGui.ForceFieldGui.Enabled = false
end

Da das benutzerdefinierte Kraftfeld eine GUI und kein neuer ParticleEmitter ist, beeinflusst das Skript ForceFieldClientVisuals nur die Visualisierungen im ersten Person-Modus für jeden Spieler, nicht die Visualisierungen im dritten Person-Modus, wenn Spieler andere Spieler ansehen. Die Visualisierungen im dritten Person-Modus behalten das standardmäßige Roblox-Aussehen. Für weitere Informationen zur Modifizierung von Kraftfeldern siehe ForceField.Visible.

Die Visualisierungen des Kraftfeldes im ersten Person-Modus umfassen ein futuristisches hexagonales Gitter am Rand des Bildschirms.
Visualisierungen des Kraftfeldes im ersten Person-Modus
Die Visualisierungen des Kraftfeldes im dritten Person-Modus umfassen eine blaue funkelnde Kugel um den Spieler, der ins Spiel spawnt.
Visualisierungen des Kraftfeldes im dritten Person-Modus

Kraftfelder sind nützlich, da sie den Spielern genügend Zeit zwischen dem Spawnen und Respawnen geben, ohne sich um feindliche Spieler sorgen zu müssen, aber schließlich müssen sie für das Haupt-Lasertag-Gameplay verschwinden. Das Skript, das die Entfernung des Kraftfeldes behandelt, befindet sich in ReplicatedStoragescheduleDestroyForceField, und es überprüft drei einzigartige Bedingungen:

  • Nachdem die Spieler einen Blaster ausgewählt haben, müssen die Kraftfelder lange genug bestehen, damit die Spieler sich an ihre Umgebung gewöhnen können.
  • Während dieser Akklimatisierungszeit dürfen Kraftfelder keinen Vorteil bieten, daher müssen sie im Moment verschwinden, in dem ein Spieler seinen Blaster abfeuert.
  • Kraftfelder müssen verschwinden, wenn Spieler ihre Charaktere zurücksetzen, entweder bevor sie abfeuern oder bevor das Kraftfeld abläuft.

Jede dieser Überprüfungen im scheduleDestroyForceField-Skript ruft endForceField() für diese Bedingungen auf.

scheduleDestroyForceField
-- Beende das Kraftfeld, wenn der Spieler abfeuert
local blasterStateAttribute = getBlasterStateAttribute()
attributeChangedConnection = player:GetAttributeChangedSignal(blasterStateAttribute):Connect(function()
local currentBlasterState = player:GetAttribute(blasterStateAttribute)
if currentBlasterState == BlasterState.Blasting then
endForceField()
end
end)
-- Beende das Kraftfeld, wenn der Spieler zurücksetzt
characterRespawnedConnection = player.CharacterRemoving:Connect(endForceField)
-- Beende das Kraftfeld nach 8 Sekunden
task.delay(MAX_FORCE_FIELD_TIME, endForceField)

endForceField() enthält eine scheinbar seltsame if-Anweisung um die forceFieldEnded-Boolean. Da die Überprüfungen sequenziell ausgeführt werden, kann das Skript die Funktion endForceField() zwei- oder sogar dreimal aufrufen. Die forceFieldEnded-Boolean stellt sicher, dass die Funktion nur versucht, ein Kraftfeld einmal zu zerstören.

scheduleDestroyForceField
local function endForceField()
if forceFieldEnded then
return
end
forceFieldEnded = true
attributeChangedConnection:Disconnect()
characterRespawnedConnection:Disconnect()
destroyForceField(player)
end

Client-Zustand verwalten

Während sich der Großteil dieses Abschnitts auf ServerScriptServicePlayerStateHandler konzentriert, gibt es ein weiteres Skript mit demselben Namen in ReplicatedStorage. Der Grund für die Trennung ist die Client-Server-Architektur:

  • Der Client muss die Informationen zum Spielerstatus verstehen, damit er in Echtzeit angemessen reagieren kann, z. B. um die richtigen Benutzeroberflächenelemente anzuzeigen oder es den Spielern zu ermöglichen, sich zu bewegen und zu feuern.

  • Der Server benötigt all diese Informationen, um Exploits zu verhindern. Zum Beispiel benötigt der Server auch den Spielerstatus, um Aktionen wie das Spawnen und Ausrüsten von Charakteren, das Deaktivieren von Kraftfeldern und das Anzeigen einer Bestenliste durchzuführen. Aus diesem Grund befindet sich dieses Skript in ReplicatedStorage und nicht an einem rein clientseitigen Ort.

Um diese Kernlogik zu sehen, überprüfe das folgende Skript in ReplicatedStoragePlayerStateHandler, das den aktuellen Zustand des Benutzers überprüft und dann die entsprechende Funktion aufruft, die die entsprechenden Aktionen für diesen Zustand behandelt.

PlayerStateHandler
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(`Ungültiger Spielerstatus ({newPlayerState})`)
end
end

Alle Ereignisantworten sind in diesem Skript logisch gruppiert, da sie ein ähnliches Verhalten erfordern, um die Spielersteuerung, die Kamerabewegung und die sichtbare UI-Ebene zu aktivieren oder zu deaktivieren. Zum Beispiel müssen Spieler während der Blasterauswahl sowohl unverwundbar als auch bewegungsunfähig sein. Der Server behandelt bereits das Kraftfeld, aber der Client behandelt die Bewegung. Um dies zu demonstrieren, wenn du die Logik für die Funktion onSelectingBlaster() überprüfst, kannst du sehen, dass der Client die Spielerbewegung deaktiviert, während sie einen Blaster auswählen.

PlayerStateHandler
local function onSelectingBlaster()
togglePlayerCamera(true)
togglePlayerMovement(false)
setGuiExclusivelyEnabled(playerGui.PickABlasterGui)
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end

Die Funktion onPlaying() ist ebenfalls recht unkompliziert. Sie aktiviert die Bewegung, wechselt zur Hauptanzeige (HUD), aktiviert den Blaster und ruft dieselbe Kraftfeldfunktion wie der Server auf.

PlayerStateHandler
local function onPlaying()
togglePlayerMovement(true)
setGuiExclusivelyEnabled(playerGui.HUDGui)
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Ready)
scheduleDestroyForceField()
end

Charaktere respawnen

Das Beispiel-Lasertag-Spiel behandelt das Respawnen von Charakteren zurück in eine Runde durch den Zustand onTaggedOut() in ReplicatedStoragePlayerStateHandler. Ähnlich wie die Zustände onSelectingBlaster() und onPlaying() löst onTaggedOut() ein einzigartiges Verhalten aus, das den Änderungen des playerState-Attributs entspricht. Insbesondere deaktiviert es die Spielerbewegung, zeigt die Respawn-UI an und deaktiviert den Blaster.

PlayerStateHandler
local function onTaggedOut()
-- Deaktiviere die Steuerung, während du getaggt bist
togglePlayerMovement(false)
togglePlayerCamera(false)
setGuiExclusivelyEnabled(playerGui.OutStateGui)
-- Deaktiviere den Blaster, während du getaggt bist
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end

Wenn du dieses Verhalten testen möchtest, kannst du Esc drücken, zum Tab Einstellungen navigieren und dann auf die Schaltfläche Charakter zurücksetzen klicken. Beachte, dass du, wenn du den Respawn-Bildschirm auslöst, dich nicht bewegen, die Kamera nicht drehen oder deinen Blaster abfeuern kannst.

Roblox's Einstellungen-Menü mit der hervorgehobenen Schaltfläche Charakter zurücksetzen.
Schaltfläche Charakter zurücksetzen
Der Respawn-Bildschirm wird angezeigt, während ein Spieler wieder in die Runde respawnt.
Respawn-Bildschirm

Es ist wichtig zu beachten, dass dieses Skript tatsächlich keine Charaktere respawnt, sondern sie nur daran hindert, zu handeln, und den Spielern visuelles Feedback gibt, dass der Server ihre Charaktere respawnt. Um dies zu demonstrieren, wenn du ServerScriptServiceSetupHumanoidsetupHumanoidAsynconHumanoidDied untersuchst, setzt das Skript den PlayerState auf TaggedOut (was im Wesentlichen ReplicatedStoragePlayerStateHandler benachrichtigt) und fügt einige visuelle Indikatoren hinzu. Die tatsächliche Logik des Respawnens ist ein integriertes Roblox-Verhalten.

Wenn Spieler wieder in die Runde respawnen, respawnen sie an ihrem Team-Spawn-Standort gemäß der SpawnLocation.TeamColor-Eigenschaft. Um die Respawn-Zeit anzupassen, kannst du die folgende Zeile an den Anfang von SetupHumanoid hinzufügen. Um mehr über diese Technik zu erfahren, siehe Players.RespawnTime.

SetupHumanoid
local Players = game:GetService("Players")
Players.RespawnTime = 10 -- neue Zeile, in Sekunden

Verschiedene Einstellungen

Im Rahmen der anfänglichen Einrichtung führt das Beispiel-Lasertag-Spiel auch einige kleine, aber entscheidende Schritte durch:

  • Das Spiel enthält ein leeres Skript namens StarterPlayerStarterCharacterScriptsHealth, das die standardmäßige Roblox-Gesundheitsregeneration deaktiviert. Für eine Erklärung des Verhaltens dieser Eigenschaft siehe Humanoid.Health.

  • Das Spiel verwendet eine Kamera im ersten Person-Modus, indem es die StarterPlayer.CameraMode.LockFirstPerson-Eigenschaft festlegt. Beachte, dass du, wenn du den Benutzern erlauben möchtest, zwischen der ersten und der dritten Person zu wechseln, die Eigenschaft programmatisch ändern musst, anstatt sie nur einmal in Studio festzulegen, und die Steuerungen und die Benutzeroberfläche anpassen musst, um den Wechsel der Perspektive zu berücksichtigen.

  • Das Spiel verwendet die integrierte Roblox-Bestenliste mit der Einheit "Punkte", die Spieler jedes Mal verdienen, wenn sie einen anderen Spieler taggen. Du kannst die Konfiguration in ServerScriptServiceSetupLeaderboard sehen, aber In-Game-Bestenlisten bietet einen vollständigen Überblick. Beachte, dass onPlayerTagged Punkte zur Bestenliste hinzufügt, was du in Runden hinzufügen und Treffer erkennen lernen wirst.

Jetzt, da Spieler spawnen, einen Blaster auswählen und ihn aus einer Perspektive im ersten Person-Modus zielen können, lehrt dich der nächste Abschnitt die Skripte hinter der Erstellung von rundenbasiertem Gameplay.

©2026 Roblox Corporation. Roblox, das Roblox-Logo und "Powering Imagination" gehören zu unseren eingetragenen und nicht eingetragenen Markenzeichen in den USA und anderen Ländern.