Gerando e Respawnando

*Este conteúdo é traduzido por IA (Beta) e pode conter erros. Para ver a página em inglês, clique aqui.

Gerar é o processo de criação de um objeto ou personagem em uma experiência, e respawnar é o processo de adicionar um objeto ou personagem de volta à uma experiência após atender uma condição de remoção, como a saúde de um personagem atingindo zero ou caindo do mapa. Ambos os processos são importantes porque garantem que os jogadores possam entrar na sua experiência e continuar jogando para melhorar suas habilidades.

Usando a experiência de laser de exemplo como referência, esta seção do tutorial ensina você a usar e personalizar os recursos incorporados do Roblox para lidar com o spawning e respawning, incluindo diretrizes de script em:

  • Configurando locais de spawn para que os jogadores só possam spawnar na zona de spawn de sua Equipe.
  • Adicionar novos jogadores e seus personagens à partida à medida que eles se juntam à experiência.
  • Personalizar campos de força que impedem danos à medida que os jogadores aparecem e respawnam.
  • Gerenciando o estado do cliente para que o jogo funcione corretamente no momento apropriado.
  • Respawning personagens depois que eles são marcados fora da rodada.
  • Realizar pequenas ações, miscelâneas, que são cruciais para definir parâmetros de jogo e personagens.

Esta seção inclui muito conteúdo de script, mas em vez de escrever tudo do zero ao criar uma experiência, ela encoraja você a usar componentes existentes, itera rapidamente e descobre quais sistemas precisam de uma implementação personalizada para corresponder à sua visão. Depois de completar esta seção, você aprenderá a implementar jogos baseados em rodadas que rastreiam pontos, monitoram o estado do jogador e exibem resultados de rodada.

Configurar Locais de Spawn

Se você testasse a experiência agora, todos os jogadores seriam aleatórios para aparecer na SpawnLocation objeto no zona de spawn do Equipeverde ou na zona de spawn do Equiperosa. Isso apresenta um problema de gameplay onde os jogadores podem rastrear uns aos outros dentro de cada zona de spawn tão logo o campo de força de seu oponente desaparece.

Para combater este problema, a experiência de laser de exemplo configura ambos os locais de spawn com um conjunto de propriedade Neutral para restrear os jogadores do Equipeoponente de spawn na zona de spawn errada e um conjunto de propriedade 1> Class.S

  • TeamASpawn – O local de spawn na zona de spawn verde com um conjunto de propriedades TeamColor definido para Mint .
  • TeamBSpawn – O local de spawn na zona de spawn da Equiperosa com um conjunto de propriedade TeamColor definido para Carnation Pink .
TeamASpawn
TeamBSpawn

Quando um jogador se juntar à experiência, ServerScriptService > Gameplay > Rounds > 1> Rounds1> > 4> spawntPlayersInMap4> verifica para ver quantos jogadores estão em cada Equipe, então retorna a equipe com a menor quantidade de jogadores.

gerarJogadoresNoMapa

local function getSmallestTeam(): Team
local teams = Teams:GetTeams()
-- Ordenar times em ordem crescente, do menor ao maior
table.sort(teams, function(teamA: Team, teamB: Team)
return #teamA:GetPlayers() < #teamB:GetPlayers()
end)
-- Retorne a Equipemais pequena
return teams[1]
end

Uma vez que ele saiba a equipe com a menor quantidade de jogadores, ele sorteia o jogador naquela Equipe, define sua propriedade Player.Neutral para falso para que o jogador só possa gerar e respawnar na localização de spawn da Equipe, então configura seu PlayerState para 1> SelectingBlaster1>, o que você aprender

gerarJogadoresNoMapa

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

Se você examinar Workspace > World > Map > 1> Spawns1> , você pode ver que há mais um local de spawn na experiência: 4>

Por exemplo, se a rodada estiver ativa, as propriedades Neutral são definidas para falso para que o spawnPlayersInMap</

Neutro

Para demonstrar, se você examinar ServerScriptService > Gameplay > Rounds > 1> SpawnPlayersInLobby1>, que é executado no final de uma rodada, você pode ver que para cada jogador que é passado na tabela 4>players: player4>, o script:

  • Define sua propriedade Player.Neutral para verdadeiro para redefinir automaticamente seu Player.Team para nil, permitindo que o jogador respawne no lobby quando uma rodada não está ativa, como a propriedade Neutral da localização de spawn também é definida como 1>verdadeiro1>.
  • Altera seu PlayerState para InLobby para remover os visuais de UI do jogador e os visuais de primeira pessoa.

Para mais informações sobre a zona de spawn neutral e sua funcionalidade para cada rodada, see Adicionando Rodadas na próxima seção do Tutorial.

gerarJogadoresNoLobby

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 Novos Jogadores

O código Luau no Studio geralmente é baseado em eventos, o que significa que scripts ouvem eventos de um serviço Roblox e, em seguida, chamam uma função em resposta. Por exemplo, ao adicionar novos jogadores a uma experiência multijogador, deve haver um evento que lidar com tudo o que é necessário para os jogadores se conectarem com sucesso. Na experiência de laser de exemplo, este evento correspondente é Players.PlayerAdded:Connect.

Players.PlayerAdded:Connect é uma parte de vários scripts na experiência. Se você usar o atalho de teclado Ctrl/cmd+Shift+f e pesquisar por Players.PlayerAdded:Connect, os resultados fornecem um bom ponto de partida para entender a configuração inicial da experiência.

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

Para demonstrar, abra ServerScriptService > SetupHumanoid . A distinção entre Player e 1> Class.Player.Character|Character1> é a chave para entender este script:

  • Um player é um cliente conectado, e um carakter é um modelo Humanoid.
  • Os jogadores precisam escolher um blaster e serem adicionados à tabela de classificação. Os personagens precisam ser gerados e receber um blaster.

SetupHumanoid imediatamente verifica se o jogador tem um personagem (acabou de entrar) ou não (está respawnando). Depois de encontrar um, chama onCharacterAdded(), obtém

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

A nota importante com este script é que as propriedades são completamente opcionais, o que significa que, se você remover as seis primeiras linhas da função, a experiência ainda funciona normalmente. Em vez de ser requisitos funcionais, cada propriedade permite que você tome decisões de design que atendem aos seus objetivos de jogo. Por exemplo:

  • Se você quiser que os nomes dos personagens sejam exibidos em distâncias mais próximas, reduza o valor de Humanoid.NameDisplayDistance.
  • Se você só quiser a saúde de um personagem para exibir se estiver abaixo de 100%, set Humanoid.HealthDisplayType para Exibir quando danificado .
  • Se você quiser que os personagens se desfaçam quando a saúde deles atinge 0, configure Humanoid.BreakJointsOnDeath para Verdadeiro .

Se você alterar os valores dessas propriedades, é importante testar o jogo para que você possa ver o impacto de suas novas configurações. Você pode recriar o que os jogadores experimentam em um ambiente multijogador selecionando pelo menos dois personagens na seção Clientes e Servidores da aba Teste da aba Testes.

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.

Outro exemplo do evento Players.PlayerAdded:Connect em ServerScriptService > PlayerStateHandler é imediatamente verificado por um característica. Se o jogador não estiver no lobby, o script configura um atributo

Gerenciador de estado do jogador

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)

Uma variável particular em PlayerStateHandler requer discussão: attributeChangedConnectionByPlayer. Esta tabela armazena todos os jogadores e suas Connections ao 1>

Gerenciador de estado do jogador

local attributeChangedConnectionByPlayer = {}
local function onPlayerAdded(player: Player)
-- Gerencie todas as atualizações futuras para o estado do jogador
attributeChangedConnectionByPlayer[player] = player
:GetAttributeChangedSignal(PlayerAttribute.playerState)
:Connect(function()
local newPlayerState = player:GetAttribute(PlayerAttribute.playerState)
onPlayerStateChanged(player, newPlayerState)
end)
end
-- Desconecte da conexão atribuída quando o jogador sair
local function onPlayerRemoving(player: Player)
if attributeChangedConnectionByPlayer[player] then
attributeChangedConnectionByPlayer[player]:Disconnect()
attributeChangedConnectionByPlayer[player] = nil
end
end

Você pode ver que ambas as funções conectadas em onPlayerAdded() chamam onPlayerStateChanged() . Durante a configuração inicial após um jogador classificar em uma Equipe, on

Gerenciador de estado do jogador

local function onPlayerStateChanged(player: Player, newPlayerState: string)
-- O estado do Blaster é 'Ready' apenas se o estado do jogador é 'Playing'
local newBlasterState = if newPlayerState == PlayerState.Playing then BlasterState.Ready else BlasterState.Disabled
-- Agende a lógica de campo de força de destruição quando o jogador começar a jogar
if newPlayerState == PlayerState.Playing then
scheduleDestroyForceField(player)
end
player:SetAttribute(PlayerAttribute.blasterStateServer, newBlasterState)
end

Se você adicionar pontos de interrupção ou até mesmo uma declaração <

Personalizar Campos de Força

Em vez de usar uma implementação personalizada, a experiência de laser de exemplo usa a classe integrada ForceField do Studio para impedir que os jogadores levem dano enquanto eles estão selecionando seu blaster. Isso garante que a única exigência para os jogadores

Semelhante a setupHumanoidAsync , a maioria das linhas em ForceFieldClientVisuals são opcionais. Por exemplo, se você comentar os conteúdos da função, como o seguinte script, a experiência usa o campo de força padrão em vez do campo de força hexagonal em StarterGui > 2>ForceFieldGui2>.

Comentando Propriedades em ForceFieldClientVisuals

local function onCharacterAddedAsync(character: Model)
-- campo de força local = personagem: WaitForChild("ForceField", 3)
-- a menos que forceField então
-- retornar
-- terminar/parar/sair
-- forceField.Visible = falso
-- localPlayer.PlayerGui:WaitForChild("ForceFieldGui").Enabled = verdadeiro
-- forceField.Destroying:Wait()
-- localPlayer.PlayerGui.ForceFieldGui.Enabled = falso
end

Como o campo de força personalizado é um GUI, em vez de um novo ParticleEmitter, o script ForceFieldClientVisuals só afeta os visuais de primeira pessoa para cada jogador, não os visuais de terceira pessoa quando os jogadores olham para outros jogadores. Os visuais de terceira pessoa mantêm a ap

First-person force field visuals include a futuristic hexagonal grid on the perimeter of the screen.
Visuais de campo de força em primeira pessoa
Third-person force field visuals include a blue sparkling orb around the player spawning into the experience.
Visões de campo de força de terceiros

Campos de força são úteis porque fornecem tempo suficiente para os jogadores entre o spawn e o respawn sem precisar se preocupar com jogadores inimigos, mas eventualmente eles precisam desaparecer para o principal jogabilidadede laser tag. O script que lida com a remoção de campo de força é em ReplicatedStorage > scheduleDestroyForceField e verifica três condições únicas:

  • Depois que os jogadores selecionam um blaster, os campos de força precisam durar o suficiente para permitir que os jogadores se aclimatem ao seu ambiente.
  • Durante este tempo de aceleração, campos de força não podem ser uma vantagem, então eles precisam desaparecer no momento em que um jogador explodir seu blaster.
  • Campos de força precisam desaparecer quando os jogadores redefinem seus personagens, antes de explodir ou antes que o campo de força expire.

Cada um desses cheques no scheduleDestroyForceField script call endForceField() para essas condições.

campo de força de destruição

-- Terminar campo de força se o jogador explodir
local blasterStateAttribute = getBlasterStateAttribute()
attributeChangedConnection = player:GetAttributeChangedSignal(blasterStateAttribute):Connect(function()
local currentBlasterState = player:GetAttribute(blasterStateAttribute)
if currentBlasterState == BlasterState.Blasting then
endForceField()
end
end)
-- Terminar campo de força se o jogador redefinir
characterRespawnedConnection = player.CharacterRemoving:Connect(endForceField)
-- Campo de força finalizado após 8 segundos
task.delay(MAX_FORCE_FIELD_TIME, endForceField)

endForceField() inclui uma declaração de if que parece estranha ao redor do forceFieldEnded botão. Como os cheques são executados em série, o script pode chamar a função 0> endForceField0> duas ou até mesmo três vezes. A função endForceField()3> garante que a função apenas destrua um campo

campo de força de destruição

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

Manipular o estado do cliente

Enquanto a maioria desta seção se concentra em ServerScriptService > PlayerStateHandler, há outro script do mesmo nome em ReplicatedStorage. A razão para a divisão é a arquitetura cliente-servidor:

  • O cliente precisa entender informações sobre o estado do jogador para que ele possa responder adequadamente em tempo real, como exibir os elementos da interface do usuário certos ou habilitar os jogadores a se mover e explodir.

  • O servidor precisa de toda essa mesma informação para que ele possa prevenir exploits. Por exemplo, o servidor também precisa de estado de jogador para executar ações como o spawning e equipando personagens, desabilitando campos de força e exibindo uma classificação. É por isso que este script está em Armazenamento Replicado e não é um local puramente do lado do cliente.

Para ver essa lógica do núcleo, revise o seguinte script em ReplicatedStorage > PlayerStateHandler que verifica o estado atual do usuário, então chama a função apropriada que lida com as ações correspondentes para esse estado.

Gerenciador de estado do jogador

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 as respostas de eventos são lógica grupos juntos neste script porque eles requerem comportamento semelhante de habilitar ou desativar controles do jogador, movimento da câmera e qual camada de UI é visível. Por exemplo, durante a seleção de um blaster, os jogadores precisam ser ambos invencíveis e incapazes de se mover. O servidor já lida com o campo de

Gerenciador de estado do jogador

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

A função onPlaying() é semelhante. Ela habilita movimento, transições para a tela principal (HUD), habilita o blaster e chama a mesma função de campo de força que o servidor.

Gerenciador de estado do jogador

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

Gerar Personagens

A experiência de laser de ressurgimento de personagens é tratada com o retorno de um personagem de volta em uma rodada através do estado onTaggedOut() em Armazenamento Replicado > Jogador状態Handler

Gerenciador de estado do jogador

local function onTaggedOut()
-- Desabilitar controles enquanto estiver fora
togglePlayerMovement(false)
togglePlayerCamera(false)
setGuiExclusivelyEnabled(playerGui.OutStateGui)
-- Desabilitar o blaster enquanto estiver fora
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end

Se você quiser testar esse comportamento, você pode pressionar Esc, navegar até a Configurações aba, então clique no botão Reset Character . Observe que quando você ativar a tela de ressurgimento, você não pode se movimento, girar a Câmeraou explodir seu blaster.

Roblox's settings menu with the Reset Character button highlighted.
Botão de Redefinição de Personagem
The respawn screen displays as a player respawns back into the round.
Tela de Respawnar

É importante notar que este script não é realmente respawnar personagens, ele apenas os impede de agir e fornece

Quando os jogadores reaparecem na ronda, eles reaparecem na localização de spawn de sua Equipede acordo com a propriedade SpawnLocation.TeamColor. Para personalizar o tempo de reaparecimento, você pode adicionar a seguinte linha na parte superior de SetupHumanoid. Para aprender mais sobre esta técnica, veja Players.RespawnTime.

ConfigurarHumanoid

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

Configurações Diversas

Como parte do setup inicial, a experiência de laser de exemplo também executa alguns pequenos, mas críticos passos:

  • A experiência inclui um script vazio chamado StarterPlayer > StarterCharacterScripts > Health que desativa a regeneração de saúde padrão do Roblox. Para uma explicação sobre o comportamento desta propriedade, veja 1> Class.Humanoid.Health1> .

  • A experiência usa uma câmera de primeira pessoa ao configurar a propriedade StarterPlayer.CameraMode.LockFirstPerson. Observe que se você quiser permitir que os usuários alterne entre câmeras de primeira e terceira pessoa, você deve alterar o programa de propriedade de forma programática, em vez de apenas definir uma vez no Studio, e modificar os controles e UI para compensar a mudança de perspectiva.

  • A experiência usa o placar de classificação integrado do Roblox com a unidade de "pontos", que os jogadores ganham cada vez que marcam outro jogador fora. Você pode ver a configuração em ServerScriptService > SetupLeaderboard , mas In-Experience Leaderboards

Agora que os jogadores podem Gerar, escolha um blaster e aponta-o a partir de uma primeira pessoa, a próxima seção ensina você sobre os scripts por trás da criação de uma jogabilidade baseada em rodadas.