Partidas podem terminar em algumas condições, incluindo o tempo acabando ou um único jogador sendo deixado.
Gerenciar jogadores derrotados
No momento, jogadores derrotados respawnam na arena. Em vez disso, envie-os de volta ao lobby para esperar pela próxima conferir.
- No PlayerManager, crie uma função local chamada respawnPlayerInLobby(). Nessa função, faça o seguindo:
- Defina a propriedade RespawnLocation do jogador para o lobbySpawn.
- Recarregue o personagem com Player:LoadCharacter() . Lembre-se, LoadCharacter() recria o jogador em seu Gerar, removendo quaisquer ferramentas que eles tinham.
Usar funções anônimas
Funções anônimas são comumente usadas em scripts avançados sob situações específicas.Antes de definir eles, é importante entender uma situação que seu script pode encontrar.
Considere isso: Para teletransportar jogadores derrotados para o lobby, a função de respawn terá que ser conectada ao evento Died do jogador.Há um problema, porém.Se você conectar o evento como temos no passado, não há como obter o nome do jogador do evento Died.O script precisa desse nome para remover um jogador derrotado da tabela de rastreamento de jogadores ativos.
Para obter o nome do jogador que disparou o evento Died, use uma função anônima. Funções anônimas não têm nomes e podem ser criadas diretamente dentro de Connect() em vez de separadamente.
Uma função anônima de amostra está abaixo que mostra a síntese.
myPlayer.Died:Connect(function()
print(player)
end)
Codifique o evento de morte
Para essa função, sempre que o personagem de um jogador morre, ele ativará a função que o respawna.
Para obter acesso ao evento Died do jogador, no PlayerManager > preparePlayer(), adicione uma variável para o humanoide do jogador.
local function preparePlayer(player, whichSpawn)player.RespawnLocation = whichSpawnplayer:LoadCharacter()local character = player.Character or player.CharacterAdded:Wait()local sword = playerWeapon:Clone()sword.Parent = characterlocal humanoid = character:WaitForChild("Humanoid")endCrie uma função anônima que se conecte ao evento Died.Comece digitando humanoid.Died:Connect().Então, dentro de Connect() , digite function() , pressione Enter para preencher automaticamente end e exclua a vírgula extra.
local humanoid = character:WaitForChild("Humanoid")humanoid.Died:Connect(function()end)Na função anônima, chame respawnPlayerInLobby(). Passe em player, uma variável que armazena o jogador se preparando para entrar em uma conferir.
local humanoid = character:WaitForChild("Humanoid")humanoid.Died:Connect(function()respawnPlayerInLobby(player)end)Inicie um servidor e jogue uma conferir.Teste quando um jogador morre, ele respawna no lobby.Para derrotar os jogadores, caminhe até eles e use sua arma até confirmar que eles respawnaram no lobby.
Atacando o Jogador2 Jogador2 no Lobby depois de respawnar
Observe, também existem algumas maneiras diferentes de testar se desejado.
- Para matar um jogador, na janela Servidor > Saída > Barra de Comando, copie e cole: workspace.Player1.Humanoid.Health = 0 .Pressione Enter para executar o comando.Para remover outros jogadores, use Player2, Player3, etc.
- Definir GameSettings > para um tempo mais longo pode lhe dar mais tempo para encontrar e eliminar todos os jogadores.
- Para ter testes mais rápidos, altere GameSettings > minimumPlayers para um número menor, como 2.
Termine o jogo
Agora que os jogadores derrotados respawnaram, comece a trabalhar para terminar o jogo.Lembra de criar o evento MatchEnd? Ele será disparado quando o tempo acabar ou um vencedor for encontrado.
Para dizer a outros scripts qual condição terminou o jogo, crie uma tabela com variáveis para TimerUp e FoundWinner.Quando o evento de fim de partida é disparado, ele passará em uma variável para que outros scripts possam responder.
Em Configurações do Jogo, crie uma tabela de módulo vazia chamada endStates .
local GameSettings = {}-- Variáveis do jogoGameSettings.intermissionDuration = 5GameSettings.matchDuration = 10GameSettings.minimumPlayers = 2GameSettings.transitionTime = 5-- Maneiras possíveis que o jogo pode terminar/parar/sair.GameSettings.endStates = {}return GameSettingsCrie duas variáveis chamadas TimerUp e FoundWinner. Defina cada uma para uma string que corresponda ao seu nome. Essas strings serão usadas para testar o código.
GameSettings.endStates = {TimerUp = "TimerUp",FoundWinner = "FoundWinner"}
Termine com um temporizador
Quando o cronômetro termina, dispare o evento Fim de Partida e envie a variável de estado de fim correspondente.Dessa forma, outros scripts que estão ouvindo esse evento podem responder de acordo.Lembre-se que, enquanto eventos disparam sinais de fogo, também podem enviar dados que são recebidos por scripts de escuta, como TimerUp ou FoundWinner.
Em Gerenciador de Jogo , no while verdadeiro do loop, encontre a linha matchEnd.Event:Wait(). No início da linha, adicione local endState =.
while true dodisplayManager.updateStatus("Waiting for Players")repeattask.wait(gameSettings.intermissionDuration)until #Players:GetPlayers() >= gameSettings.minimumPlayersdisplayManager.updateStatus("Get ready!")task.wait(gameSettings.transitionTime)matchManager.prepareGame()local endState = matchEnd.Event:Wait()endPara confirmar que o estado correto foi recebido, adicione uma declaração de impressão incluindo endState.
while true dodisplayManager.updateStatus("Waiting for Players")repeattask.wait(gameSettings.intermissionDuration)until #Players:GetPlayers() >= gameSettings.minimumPlayersdisplayManager.updateStatus("Get ready!")task.wait(gameSettings.transitionTime)matchManager.prepareGame()local endState = matchEnd.Event:Wait()print("Game ended with: " .. endState)endNo MatchManager, encontre timeUp() e remova a declaração de impressão.Então, para disparar o evento de fim da partida, digite matchEnd:Fire() e passe em gameSettings.endStates.TimerUp.
-- Valoreslocal displayValues = ReplicatedStorage:WaitForChild("DisplayValues")local timeLeft = displayValues:WaitForChild("TimeLeft")-- Cria um novo objeto de cronômetro para ser usado para acompanhar o tempo da partida.local myTimer = timer.new()-- Funções Locaislocal function timeUp()matchEnd:Fire(gameSettings.endStates.TimerUp)endTeste uma conferir. Uma vez que o tempo acaba, verifique se a declaração de impressão inclui a string armazenada na variável TimerUp.
Dicas de solução de problemas
Neste ponto, a mensagem não foi exibida, tente uma das seguintes abaixo.
- Verifique que, onde quer que as variáveis de estado final sejam chamadas, elas sejam escritas exatamente, como aqui: gameSettings.endStates.TimerUp .
- Certifique-se de usar : (operador de coluna) com o em vez do operador de ponto, como em .
Codifique uma conferirvencedora
Em seguida, o script precisa identificar jogadores vencedores, remover jogadores perdedores e executar limpeza, como parar o cronômetro.Partidas também terminarão se um jogador for deixado.Para ver se a condição FoundWinner é atendida, você precisará de uma função que verifique o número deixado na tabela rastreando jogadores em uma conferir.
Verifique o número de jogadores
As partidas terminarão se restar apenas um jogador.Para verificar isso, o script precisa rastrear os jogadores em uma rodada.Uma vez que um jogador é deixado, um vencedor pode ser designado.
No PlayerManager, defina as seguintes variáveis:
- Pasta ModuleScripts
- Módulo GameSettings - Usado para acessar variáveis de estado final
- Pasta de eventos e o evento MatchEnd - Evento de incêndio
local PlayerManager = {}-- Serviçoslocal Players = game:GetService("Players")local ServerStorage = game:GetService("ServerStorage")local ReplicatedStorage = game:GetService("ReplicatedStorage")-- Móveislocal moduleScripts = ServerStorage:WaitForChild("ModuleScripts")local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))-- Eventoslocal events = ServerStorage:WaitForChild("Events")local matchEnd = events:WaitForChild("MatchEnd")Acima de respawnPlayerInLobby(), adicione uma nova função local chamada checkPlayerCount().
-- Variáveis do Jogadorlocal activePlayers = {}local playerWeapon = ServerStorage.Weaponlocal function checkPlayerCount()endlocal function respawnPlayerInLobby(player)Dentro dessa função, use uma declaração if então para verificar um vencedor. Nessa declaração:
- Verifique se o tamanho da tabela activePlayers é 1.
- Se assim for, dispare matchEnd e passe em gameSettings.endStates.FoundWinner.
local function checkPlayerCount()if #activePlayers == 1 thenmatchEnd:Fire(gameSettings.endStates.FoundWinner)endend
Remova um jogador
Uma contagem precisa não pode ser mantida a menos que os jogadores sejam removidos.Quando um jogador é derrotado, mantenha um contagem precisa de jogadores removendo-os da tabela de jogadores.Então, verifique o tamanho da tabela de jogadores ativos para ver se há um vencedor.
Abaixo de checkPlayerCount(), crie uma nova função local chamada removeActivePlayer() com um parâmetro chamado player .
local function checkPlayerCount()if #activePlayers == 1 thenmatchEnd:Fire(gameSettings.endStates.FoundWinner)endendlocal function removeActivePlayer(player)endPara encontrar o jogador na tabela activePlayers, itere através dela usando um for loop.Então, adicione uma declaração if que será executada se um jogador que corresponde ao nome for encontrado na função.
local function removeActivePlayer(player)for playerKey, whichPlayer in activePlayers doif whichPlayer == player thenendendendPara remover o jogador, na declaração if:
- Chame table.remove() . Dentro das vírgulas, passe em activePlayers , a tabela para olhar, e playerKey - o jogador para remover da tabela.
- Defina o valor do objeto playersLeft para #activePlayers.
- Verifique um jogador vencedor executando checkPlayerCount() .
local function removeActivePlayer(player)for playerKey, whichPlayer in activePlayers doif whichPlayer == player thentable.remove(activePlayers, playerKey)playersLeft.Value = #activePlayerscheckPlayerCount()endendend
Conectar eventos e testar
Para usar a função acabada de criar, chame-a a partir da função anônima conectada ao evento Died do jogador.
Encontre preparePlayer() . Na função anônima com a conexão do evento Died, chame removeActivePlayer() . Então, passe o jogador como parâmetro.
humanoid.Died:Connect(function()respawnPlayerInLobby(player)removeActivePlayer(player)end)Para ver se um jogador vencedor é encontrado, inicie um servidor de teste .Quando há apenas um jogador restante, você deve ver FoundWinner na janela de Saída.
Continue testando e deixe a partida terminar/parar/sair. Observe como uma nova partida começa, um erro aparece na janela de Saída:
Este erro ocorre porque o cronômetro não foi interrompido, o que será corrigido na próxima seção.
Pare o relógio
Sempre que uma partida termina com um jogador vencedor, o cronômetro deve parar também.Para interromper o cronômetro antes que o tempo acabe, faça com que o cronômetro pare sempre que o evento de fim de partida for disparado.Este é um dos benefícios de criar eventos.Eles podem ser reutilizados em várias situações para script causar e efeito relações.
No MatchManager, crie uma nova função local chamada stopTimer() . Dentro, digite myTimer:stop() para interromper o cronômetro.
-- Cria um novo objeto de cronômetro para ser usado para acompanhar o tempo da partida.local myTimer = timer.new()-- Funções Locaislocal function stopTimer()myTimer:stop()endlocal function timeUp()matchEnd:Fire(gameSettings.endStates.TimerUp)endPara interromper o cronômetro quando a partida terminar, conecte o evento matchEnd ao stopTimer().
-- Funções de Módulofunction MatchManager.prepareGame()playerManager.sendPlayersToMatch()matchStart:Fire()endmatchStart.Event:Connect(startTimer)matchEnd.Event:Connect(stopTimer)return MatchManagerTeste que o erro anterior não aparece mais ao iniciar um servidor .Elimine todos, exceto um jogador e então espere alguns segundos após o fim da partida.
Próximos passos
Enquanto as duas condições de vitória estão terminadas, ainda há algumas tarefas para terminar o ciclo do jogo.Por instância, o jogador vencedor nunca é teletransportado para o lobby.Na próxima lição, você mostrará como a partida terminou para os jogadores e redefinirá o jogo, finalizando, finalmente, todo o ciclo.
Scripts concluídos
Abaixo estão scripts concluídos para verificar duas vezes o seu trabalho.
scriptdo Gerenciador de Jogadores
local PlayerManager = {}
-- Serviços
local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Móveis
local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
-- Eventos
local events = ServerStorage:WaitForChild("Events")
local matchEnd = events:WaitForChild("MatchEnd")
-- Variáveis de Mapa
local lobbySpawn = workspace.Lobby.StartSpawn
local arenaMap = workspace.Arena
local spawnLocations = arenaMap.SpawnLocations
-- Valores
local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")
local playersLeft = displayValues:WaitForChild("PlayersLeft")
-- Variáveis do Jogador
local activePlayers = {}
local playerWeapon = ServerStorage.Weapon
-- Funções Locais
local function checkPlayerCount()
if #activePlayers == 1 then
matchEnd:Fire(gameSettings.endStates.FoundWinner)
end
end
local function removeActivePlayer(player)
for playerKey, whichPlayer in activePlayers do
if whichPlayer == player then
table.remove(activePlayers, playerKey)
playersLeft.Value = #activePlayers
checkPlayerCount()
end
end
end
local function respawnPlayerInLobby(player)
player.RespawnLocation = lobbySpawn
player:LoadCharacter()
end
local function onPlayerJoin(player)
player.RespawnLocation = lobbySpawn
end
local function preparePlayer(player, whichSpawn)
player.RespawnLocation = whichSpawn
player:LoadCharacter()
local character = player.Character or player.CharacterAdded:Wait()
local sword = playerWeapon:Clone()
sword.Parent = character
local humanoid = character:WaitForChild("Humanoid")
humanoid.Died:Connect(function()
respawnPlayerInLobby(player)
removeActivePlayer(player)
end)
end
-- Funções de Módulo
function PlayerManager.sendPlayersToMatch()
local arenaSpawns = spawnLocations:GetChildren()
for playerKey, whichPlayer in Players:GetPlayers() do
table.insert(activePlayers, whichPlayer)
local spawnLocation = table.remove(arenaSpawns, 1)
preparePlayer(whichPlayer, spawnLocation)
end
playersLeft.Value = #activePlayers
end
-- Eventos
Players.PlayerAdded:Connect(onPlayerJoin)
return PlayerManager
scriptde Configurações do Jogo
local GameSettings = {}-- Variáveis do jogoGameSettings.intermissionDuration = 5GameSettings.matchDuration = 10GameSettings.minimumPlayers = 2GameSettings.transitionTime = 5-- Maneiras possíveis que o jogo pode terminar/parar/sair.GameSettings.endStates = {TimerUp = "TimerUp",FoundWinner = "FoundWinner"}return GameSettings
scriptdo Gerenciador de Jogo
-- Serviçoslocal ServerStorage = game:GetService("ServerStorage")local Players = game:GetService("Players")-- Scripts de Módulolocal moduleScripts = ServerStorage:WaitForChild("ModuleScripts")local matchManager = require(moduleScripts:WaitForChild("MatchManager"))local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))local displayManager = require(moduleScripts:WaitForChild("DisplayManager"))-- Eventoslocal events = ServerStorage:WaitForChild("Events")local matchEnd = events:WaitForChild("MatchEnd")while true dodisplayManager.updateStatus("Waiting for Players")repeattask.wait(gameSettings.intermissionDuration)until #Players:GetPlayers() >= gameSettings.minimumPlayersdisplayManager.updateStatus("Get ready!")task.wait(gameSettings.transitionTime)matchManager.prepareGame()local endState = matchEnd.Event:Wait()print("Game ended with: " .. endState)end
scriptdo Gerenciador de Partida
local MatchManager = {}
-- Serviços
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Scripts de Módulo
local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
local playerManager = require(moduleScripts:WaitForChild("PlayerManager"))
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
local timer = require(moduleScripts:WaitForChild("Timer"))
-- Eventos
local events = ServerStorage:WaitForChild("Events")
local matchStart = events:WaitForChild("MatchStart")
local matchEnd = events:WaitForChild("MatchEnd")
-- Valores
local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")
local timeLeft = displayValues:WaitForChild("TimeLeft")
-- Cria um novo objeto de cronômetro para ser usado para acompanhar o tempo da partida.
local myTimer = timer.new()
-- Funções Locais
local function stopTimer()
myTimer:stop()
end
local function timeUp()
matchEnd:Fire(gameSettings.endStates.TimerUp)
end
local function startTimer()
print("Timer started")
myTimer:start(gameSettings.matchDuration)
myTimer.finished:Connect(timeUp)
while myTimer:isRunning() do
-- Adicionar +1 garante que a exibição do tempo termine em 1 ao invés de 0.
timeLeft.Value = (myTimer:getTimeLeft() + 1) // 1
-- Ao não definir o tempo para espera, oferece um looping mais preciso
task.wait()
end
end
-- Funções de Módulo
function MatchManager.prepareGame()
playerManager.sendPlayersToMatch()
matchStart:Fire()
end
matchStart.Event:Connect(startTimer)
matchEnd.Event:Connect(stopTimer)
return MatchManager