Generando y reapareciendo

*Este contenido se traduce usando la IA (Beta) y puede contener errores. Para ver esta página en inglés, haz clic en aquí.

Spawning es el proceso de creación de un objeto o personaje en una experiencia, y respawning es el proceso de agregar un objeto o personaje de vuelta a una experiencia después de que cumplan una condición de eliminación, como la salud de un personaje alcanzando cero o cayendo fuera del mapa. Ambos procesos son importantes porque aseguran que los jugadores puedan unirse a tu experiencia y continuar jugando para mejorar sus habilidades.

Usando la experiencia de etiqueta láser ejemplo como referencia, esta sección del tutorial te enseña cómo usar y personalizar las características integradas de Roblox para manejar el generado y el reaparecimiento, incluyendo la orientación de código en:

  • Configurando lugares de aparición para que los jugadores solo puedan aparacer en la zona de aparición de su equipo.
  • Agregar nuevos jugadores y sus personajes a la ronda a medida que se unan a la experiencia.
  • Personalizar los campos de fuerza que impiden el daño a medida que los jugadores aparecen y reaparecen.
  • Manejar el estado del cliente para que el juego funcione correctamente en el momento adecuado.
  • Reaparecer los personajes después de que se les haya etiquetado fuera de la ronda.
  • Realizar pequeñas acciones misceláneas que son cruciales para establecer parámetros de juego y personaje.

Esta sección incluye mucho contenido de script, pero en lugar de escribir todo desde cero al crear una experiencia, te alienta a utilizar componentes existentes, a itener rápidamente y a averiguar qué sistemas necesitan una implementación personalizada para coincidir con su visión. Después de completar esta sección, aprenderás a implementar el juego en ronda basado en puntos, estado del jugador y mostrar los resultados de la ronda.

Configurar ubicaciones de spawn

Si jugaras la experiencia ahora mismo, todos los jugadores aparecerían aleatoriamente en el objeto SpawnLocation o el objeto SpawnLocation en la zona de spawn del equipo verde, o en el objeto Class.SpawnLocation en la zona de spawn del equipo rosa. Esto presenta un problema de juego en el que los jugadores podrían etiquetar uno al otro en cada zona de spawn tan pronto como el campo de fuerza del jugador desap

Para combatir este problema, la experiencia de etiqueta láser configura ambas ubicaciones de spawn con un conjunto de propiedades Neutral para restringir los jugadores del equipo contrario de spawn en la zona de spawn incorrecta y un conjunto de propiedades 1> Class.S

  • TeamASpawn – La ubicación de spawn en la zona de spawn del equipo verde con un conjunto de propiedades TeamColor ajustado a Menta .
  • TeamBSpawn – La ubicación de spawn en la zona de spawn del equipo rosa con un conjunto de propiedades TeamColor establecido a Carnation Pink .
TeamASpawn
TeamBSpawn

Cuando un jugador se une a la experiencia, ServerScriptService > Gameplay > Rounds > 1> spawnearJugadoresEnElMapa1> > cheques para ver cuántos jugadores están en cada equipo, luego devuelve el equipo con la menor cantidad de jugadores.

Generar Jugadores en el Mapa

local function getSmallestTeam(): Team
local teams = Teams:GetTeams()
-- Ordenar equipos en orden ascendente desde el más pequeño al más grande
table.sort(teams, function(teamA: Team, teamB: Team)
return #teamA:GetPlayers() < #teamB:GetPlayers()
end)
-- Devuelve el equipo más pequeño
return teams[1]
end

Una vez que conoce el equipo con la menor cantidad de jugadores, clasifica al jugador en ese equipo, establece su propiedad Player.Neutral a falso para que el jugador solo pueda generar y reaparecer en la ubicación de generación de su equipo, luego establece su PlayerState a 1> SelectingBlaster1>, lo cual aprenderás más tarde

Generar Jugadores en el Mapa

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 examinas Workspace > World > Map > 1> Spawns1> , puedes ver que hay una ubicación de spawn más en el experiencia: 4> Ne

Por ejemplo, si la ronda está activa, la propiedad Neutral establece a false para que PlayersInMap pueda sortear jug

Neutro

Para demostrar, si examinas ServerScriptService > Gameplay > Rounds > 1> SpawnPlayersInLobby1>, que se ejecuta al final de una ronda, puedes ver que para cada jugador que es pasado a la mesa, el script:

  • Establece su propiedad Player.Neutral a true para restablecer automáticamente su Player.Team a nil, permitiendo que el jugador reaparezca en el lobby cuando no hay una ronda activa, ya que la propiedad Neutral de su lugar de spawn también está configurada como 1> true1> .
  • Cambia su PlayerState a InLobby para eliminar los visuales de UI del jugador y la primera persona.

Para obtener más información sobre la zona de spawn neutral y su funcionalidad para cada ronda, see Agregar rondas en la siguiente sección del tutorial.

Generar jugadores en el lobby

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

Conectar Nuevos Jugadores

El código Luau en Studio a menudo se basa en eventos, lo que significa que los scripts escuchan eventos de un servicio de Roblox, luego llaman a una función en respuesta. Por ejemplo, al agregar nuevos jugadores a una experiencia multijugador, debe haber un evento que maneje todo lo necesario para que los jugadores se conecten con éxito. En la experiencia de etiqueta láser, este evento correspondiente es Players.PlayerAdded:Connect .

Players.PlayerAdded:Connect es una parte de varios scripts en la experiencia. Si usa el atajo de teclas Ctrl/Command+Shift+F y busca por Players.PlayerAdded:Connect, los resultados proporcionan un buen punto de partida para entender la configuración inicial de la experiencia.

Studio's Find All window with the Players.PlayerAdded results highlighted.

Para demostrar, abra Servicio de Script del Servidor > ConfiguraciónHumanoide . La distinción entre Player y 1> Class.Player.Character|Character1> es clave para entender este script:

  • Un jugador es un cliente conectado, y un carácter es un aplicación de modeladoHumanoid.
  • Los jugadores deben elegir un blaster y ser agregados a la tabla de clasificación. Los personajes deben generar y recibir un blaster.

SetupHumanoid inmediatamente comprueba si el jugador tiene un personaje (solo se unió) o no (respawning). Después de que encuentre uno, llamará a onCharacterAdded(), tutorial

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

La nota importante con este script es que las propiedades son completamente opcionales, lo que significa que si eliminas las seis primeras líneas de la función, la experiencia todavía funciona correctamente. En lugar de ser requisitos funcionales, cada propiedad te permite tomar decisiones de diseño que cumplen con tus objetivos de juego. Por ejemplo:

Si cambia los valores de estas propiedades, es importante jugar para ver el impacto de sus nuevos ajustes. Puede recrear lo que los jugadores experimentan en un entorno multijugador seleccionando al menos dos personajes en la sección Clients y Servidores de la pestaña Prueba de la pestaña Test.

Studio's Test tab with the the players dropdown highlighted. This setting needs to be at least two players to see the impact of your new settings.

Otro ejemplo del evento Players.PlayerAdded:Connect es en ServerScriptService > PlayerStateHandler . Justo como en el ejemplo anterior, 1> PlayerStateHandler1> inmediatamente verifica

Manipulador de estado del jugador

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)

Una particular variable en PlayerStateHandler requiere discusión: attributeChangedConnectionByPlayer . Esta tabla almacena todos los jugadores y sus Connections a la 1>

Manipulador de estado del jugador

local attributeChangedConnectionByPlayer = {}
local function onPlayerAdded(player: Player)
-- Manipula todas las actualizaciones futuras del estado del jugador
attributeChangedConnectionByPlayer[player] = player
:GetAttributeChangedSignal(PlayerAttribute.playerState)
:Connect(function()
local newPlayerState = player:GetAttribute(PlayerAttribute.playerState)
onPlayerStateChanged(player, newPlayerState)
end)
end
-- Desconectarse de la conexión cambiada atributo cuando el jugador se va
local function onPlayerRemoving(player: Player)
if attributeChangedConnectionByPlayer[player] then
attributeChangedConnectionByPlayer[player]:Disconnect()
attributeChangedConnectionByPlayer[player] = nil
end
end

Puedes ver que ambas funciones conectadas en onPlayerAdded() llaman onPlayerStateChanged() . Durante la configuración inicial después de que un jugador se ordene en un equipo, onPlayerAdded()</

Manipulador de estado del jugador

local function onPlayerStateChanged(player: Player, newPlayerState: string)
-- El estado del bloqueador solo es "Listo" si el estado del jugador es "Jugando"
local newBlasterState = if newPlayerState == PlayerState.Playing then BlasterState.Ready else BlasterState.Disabled
-- Programa la lógica del campo de fuerza de destrucción cuando el jugador comienza a jugar
if newPlayerState == PlayerState.Playing then
scheduleDestroyForceField(player)
end
player:SetAttribute(PlayerAttribute.blasterStateServer, newBlasterState)
end

Si agrega puntos de interrupción o incluso solo una declaración de print

Personalizar Campos de Fuerza

En lugar de usar una implementación personalizada, la experiencia de etiqueta láser personalizada de Studio usa la clase de clase ForceField para evitar que los jugadores reciban daño mientras seleccionan su láser. Esto garantiza que la única exigencia para los jugadores

Al igual que setupHumanoidAsync , la mayoría de las líneas en ForceFieldClientVisuals son opcionales. Por ejemplo, si comenta los contenidos de la función como el siguiente script, la experiencia usa el campo de fuerza estándar en lugar del campo de fuerza hexagonal en StarterGui > 1>ForceFieldGui1> .

Comentando propiedades en ForceFieldClientVisuals

local function onCharacterAddedAsync(character: Model)
-- campo de fuerza local = personaje: Espera por hijo ("ForceField", 3)
-- si no forceField entonces
-- devolver
-- finalizar
-- forceField.Visible = falso
-- localPlayer.PlayerGui:WaitForChild("ForceFieldGui").Enabled = true
-- forceField.Destroying:Espera()
-- localPlayer.PlayerGui.ForceFieldGui.Enabled = falso
end

Dado que el campo de fuerza personalizado es un GUI en lugar de un nuevo ParticleEmitter , el script ForceFieldClientVisuals solo afecta los visuales de primera persona para cada jugador, no los visuales de tercer persona cuando los jugadores miran a otros jugadores. Los visuales de tercer persona conserven la aspecto, lookpredeterminada de Roblox. Para obtener más

First-person force field visuals include a futuristic hexagonal grid on the perimeter of the screen.
Primera visualización de campo de fuerza en primera persona
Third-person force field visuals include a blue sparkling orb around the player spawning into the experience.
Visuales de campo de fuerza de terceras personas

Los campos de fuerza son útiles porque proporcionan a los jugadores suficiente tiempo para entre generar y reaparecer sin tener que preocuparse por los jugadores enemigos, pero eventualmente necesitan desaparecer para el juego principal de etiqueta láser. El script que maneja la eliminación de campo de fuerza está en ReplicatedStorage > scheduleDestroyForceField , y verifica tres condiciones únicas:

  • Las fuerzas de campo deben durar lo suficiente para permitir que los jugadores se acostumbren a su entorno.
  • Durante este tiempo de aceleración, los campos de fuerza no pueden ser una ventaja, por lo que necesitan desaparecer al momento en que un jugador dispare su bláster.
  • Los campos de fuerza necesitan desaparecer cuando los jugadores reinician sus personajes antes de que se acabe el tiempo de espera del campo de fuerza o antes de que se acabe el tiempo de vida del campo de fuerza.

Cada uno de estos cheques en el scheduleDestroyForceField script call endForceField() para estas condiciones.

Planificar Destrucción de Campo de Fuerza

-- Detener el campo de fuerza si el jugador hace explosiones
local blasterStateAttribute = getBlasterStateAttribute()
attributeChangedConnection = player:GetAttributeChangedSignal(blasterStateAttribute):Connect(function()
local currentBlasterState = player:GetAttribute(blasterStateAttribute)
if currentBlasterState == BlasterState.Blasting then
endForceField()
end
end)
-- Eliminar campo de fuerza si el jugador se reinicia
characterRespawnedConnection = player.CharacterRemoving:Connect(endForceField)
-- Campo de fuerza final después de 8 segundos
task.delay(MAX_FORCE_FIELD_TIME, endForceField)

endForceField() incluye una declaración de if que parece extraño alrededor del forceFieldEndedBooleano. Debido a que los cheques se ejecutan secuencialmente, el script puede llamar la función 0> endForceField0> dos veces o incluso tres veces. La función endForceField()3> garantiza que la función solo dest

Planificar Destrucción de Campo de Fuerza

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

Manipular estado del cliente

Mientras que la mayoría de esta sección se enfoca en ServerScriptService > PlayerStateHandler , hay otro script del mismo nombre en ReplicatedStorage . La razón del dividendo es la arquitectura cliente-servidor:

  • El cliente necesita entender información del estado del jugador para que pueda responder adecuadamente en tiempo real, como mostrar los elementos de la interfaz de usuario correctos o habilitar a los jugadores para mover y explotar.

  • El servidor necesita toda esta misma información para que pueda prevenir los exploits. Por ejemplo, el servidor también necesita el estado del jugador para realizar acciones como generar y equipar personajes, desactivar campos de fuerza y mostrar una tabla de clasificación. Por esta razón, este script está en Almacenamiento Replicado y no es una ubicación puramente del lado del cliente.

Para ver esta lógica del núcleo, revisa el siguiente script en ReplicatedStorage > PlayerStateHandler que verifica el estado actual del usuario, luego llama la función apropiada que maneja las acciones correspondientes para ese estado.

Manipulador de estado del jugador

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

Todas las respuestas de eventos se agrupan lógicamente juntos en este script porque requieren un comportamiento similar para habilitar o deshabilitar controles del jugador, el movimiento de la cámara y qué capa de UI es visible. Por ejemplo, durante la selección de un bláster, los jugadores deben ser tanto invulnerables como incapaces de herramienta de movimiento. El servidor ya maneja el campo de fuerza, pero el cliente

Manipulador de estado del jugador

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

La función onPlaying() es similarmente sencilla. Habilita movimiento, transiciones a la pantalla principal (HUD), habilita el blaster y llama la misma función de campo de fuerza que el servidor.

Manipulador de estado del jugador

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

Restablecer Personajes

La experiencia de etiqueta láser que reaparece maneja a los personajes de vuelta en una ronda a través del estado de onTaggedOut() en Almacenamiento Replicado > PlayerStateHandler . Como el estado

Manipulador de estado del jugador

local function onTaggedOut()
-- Desactivar controles mientras está etiquetado
togglePlayerMovement(false)
togglePlayerCamera(false)
setGuiExclusivelyEnabled(playerGui.OutStateGui)
-- Desactivar el blaster mientras está etiquetado
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end

Si desea probar este comportamiento, puede presionar Esc, encontrar la pestaña Configuración y luego hacer clic en el botón Restablecer el personaje . Observe que cuando usted activa la pantalla de respawn, no puede herramienta de movimiento, girar la cámara o explotar su blaster.

Roblox's settings menu with the Reset Character button highlighted.
Botón de reinicio de personaje
The respawn screen displays as a player respawns back into the round.
Reutilizar pantalla

Es importante tener en cuenta que este script no realmente reaparece personajes, solo los detiene de actuar y proporc

Cuando los jugadores reaparecen en la ronda, reaparecen en la ubicación de generación de su equipo según la propiedad SpawnLocation.TeamColor. Para personalizar el tiempo de reaparición, puede agregar la siguiente línea a la parte superior de SetupHumanoid . Para aprender más sobre esta técnica, consulte Players.RespawnTime .

Configuración de humanoides

local Players = game:GetService("Players")
Players.RespawnTime = 10 -- new line, in seconds

Configuración Miscelánea

Como parte del proceso de inicialización, la experiencia de etiqueta láser también realiza algunos pasos pequeños pero críticos:

  • La experiencia incluye un script vacío llamado StarterPlayer > StarterCharacterScripts > Health que desactiva la regeneración de salud predeterminada de Roblox. Para una explicación de este propiedad, véase 1> Class.Humanoid.Health1> .

  • La experiencia usa una cámara de primera persona al configurar la propiedad StarterPlayer.CameraMode.LockFirstPerson . Nota que si desea permitir que los usuarios cambien entre cámaras de primera y tercera persona, debe cambiar el programa de propiedad de forma programática en lugar de simplemente establecerlo una vez en Studio, y modificar los controles y la interfaz de usuario para compensar el cambio en la perspectiva.

  • La experiencia usa la tabla de clasificación de Roblox integrada con la unidad de "puntos", que los jugadores ganan cada vez que etiquetan a otro jugador fuera. Puedes ver la configuración en Servicio de Script del Servidor > IniciarTabla de Clasificación , pero

Ahora que los jugadores pueden generar, elegir un blaster y apuntarlo desde un punto de vista de primera persona, la siguiente sección te enseña sobre los scripts detrás de crear una juegobasada en rondas.