Encerrando Partidas

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

Partidas podem terminar em alguns condições, incluindo relógios acabando ou um único jogador sendo deixado.

Gerenciando Jogadores Derrotados

Agora, os jogadores derrotados reaparecem na arena. Em vez disso, envie-os de volta ao lobby para aguardar a próxima conferir.

  1. No PlayerManager, crie uma função local chamada respawnPlayerInLobby() . Nesta 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.

Usando Funções Anônimas

Funções anônimas são comumente usadas em scripts avançados sob situações específicas. Antes de definí-las, é importante entender uma situação que seu script pode encontrar.

Considere isso: Para teletransportar jogadores derrotados para o lobby, a função de respawn precisará estar conectada ao evento Died do jogador. Há um problema, porém. Se você conectar o evento como fazemos no passado, não há maneira de obter o nome do jogador do evento Died. O script precisa desse nome para remover um jogador derrotado da mesa de rastreamento de jogadores ativos.

Para obter o nome do jogador que desencadeou 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 exemplo está abaixo que mostra a sintaxe.


myPlayer.Died:Connect(function()
print(player)
end)

Código do Evento Morto

Para essa função, sempre que um personagem de um jogador morre, eles gatilharão a função que os ressuscita.

  1. Para obter acesso ao evento Died do jogador, em PlayerManager > preparePlayer(), adicione uma variável para o humanóide do jogador.


    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")
    end
  2. Crie uma função anônima que se conecta ao evento Died. Comece digitando humanoid.Died:Connect() . Em seguida, dentro Connect() , digite 1> function()1> e pressione 4> Enter4> para autocompletar 7> terminar/parar/sair7> e excluir a paisagem extra.


    local humanoid = character:WaitForChild("Humanoid")
    humanoid.Died:Connect(function()
    end)
  3. Na função anônima, chame respawnPlayerInLobby() . Passe em player, uma variável armazenando o jogador se preparando para entrar em uma conferir.


    local humanoid = character:WaitForChild("Humanoid")
    humanoid.Died:Connect(function()
    respawnPlayerInLobby(player)
    end)
  4. Inicie um servidor e jogue uma conferir. Teste que quando um jogador morre, eles reaparecem no lobby. Para derrotar os jogadores, chegue perto deles e use sua arma até você confirmar que eles reapareceram no lobby.

    Ataque o Jogador2
    Jogador2 no Lobby após o ressurgimento

Nota, também existem alguns métodos de teste diferentes, se desejar.

  • Para matar um jogador, na Janela de Saída do Servidor > Barra de Comandos, copie e cole: workspace.Player1.Humanoid.Health = 0 . Pressione Enter para executar o comando. Para remover outros jogadores, use o Player2, Player3, etc.
  • Configurar GameSettings > matchDuration para um tempo mais longo pode lhe dar mais tempo para encontrar e eliminar todos os jogadores.
  • Para testes mais rápidos, altere GameSettings > minimumPlayers para um número menor, como 2.

Terminando o Jogo

Agora que jogadores derrotados respawnam, comece a trabalhar no fim do jogo. Lembre-se de criar o evento MatchEnd? Ele será disparado quando o tempo acabar ou um vencedor for encontrado.

Para dizer a outros scripts que condição terminou o jogo, crie uma tabela com variáveis para TimerUp e FoundWinner. Quando o evento de fim da partida é disparado, ele passará em uma variável para que outros scripts possam responder.

  1. In GameSettings, create an empty module table named endStates .


    local GameSettings = {}
    -- Variáveis do Jogo
    GameSettings.intermissionDuration = 5
    GameSettings.matchDuration = 10
    GameSettings.minimumPlayers = 2
    GameSettings.transitionTime = 5
    -- Possíveis maneiras que o jogo pode terminar/parar/sair.
    GameSettings.endStates = {
    }
    return GameSettings
  2. Crie duas variáveis chamadas TimerUp e FoundWinner. Defina cada uma delas para uma string correspondendo ao seu nome. Essas strings serão usadas para testar o código.


GameSettings.endStates = {
TimerUp = "TimerUp",
FoundWinner = "FoundWinner"
}

Terminando com um Temporizador

Quando o temporizador terminar, fire o evento Match End e envie a variável de estado de fim correspondente. Desta forma, outros scripts que ouvem para este evento podem responder de acordo. Lembre-se de que, enquanto os sinais de evento são disparados, isso também pode enviar dados que são recebidos ao ouvir scripts, como TimerUp ou FoundWinner.

  1. Em GameManager , na while true do loop, find the line matchEnd.Event:Wait() . No começo da linha, adicionar local endState = .


    while true do
    displayManager.updateStatus("Waiting for Players")
    repeat
    task.wait(gameSettings.intermissionDuration)
    until #Players:GetPlayers() >= gameSettings.minimumPlayers
    displayManager.updateStatus("Get ready!")
    task.wait(gameSettings.transitionTime)
    matchManager.prepareGame()
    local endState = matchEnd.Event:Wait()
    end
  2. Para confirmar que o estado correto foi recebido, adicione uma declaração de impressão incluindo endState .


    while true do
    displayManager.updateStatus("Waiting for Players")
    repeat
    task.wait(gameSettings.intermissionDuration)
    until #Players:GetPlayers() >= gameSettings.minimumPlayers
    displayManager.updateStatus("Get ready!")
    task.wait(gameSettings.transitionTime)
    matchManager.prepareGame()
    local endState = matchEnd.Event:Wait()
    print("Game ended with: " .. endState)
    end
  3. In MatchManager, find timeUp() e remover a declaração de impressão. Em seguida, para disparar o evento de fim de match, digite matchEnd:Fire() e passe em 1> gameSettings.endSettings.TimerUp1> .


    -- Valores
    local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")
    local timeLeft = displayValues:WaitForChild("TimeLeft")
    -- Cria um novo objeto de relógio para ser usado para rastrear o tempo da partida.
    local myTimer = timer.new()
    -- Funções Locais
    local function timeUp()
    matchEnd:Fire(gameSettings.endStates.TimerUp)
    end
  4. Teste uma conferir. Uma vez que o tempo acabar, 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 onde quer que as variáveis de estado final sejam chamadas, que elas sejam escritas exatamente, como aqui: gameSettings.endStates.TimerUp.
  • Certifique-se de usar : (operador de ponto) com o Fire() em vez do operador de ponto, como em matchEnd:Fire .

Codificando uma Partida Ganhadora

Em seguida, o script precisa identificar jogadores vencedores, remover jogadores perdendo e executar limpeza, como parar o timer. Partidas também terminam se um jogador for deixado. Para ver se a condição FoundWinner é atendida, você precisará de uma função que verifica o número restante na tabela rastreando jogadores em uma conferir.

Verificando a Contagem de Jogadores

As partidas terminarão se houver apenas um jogador restante. Para verificar isso, o script precisa rastrear os jogadores em uma rodada. Uma vez que um jogador é restante, um vencedor pode ser designado.

  1. In PlayerManager, defina as seguintes variáveis:

    • Pasta ModuleScripts
    • GameSettings módulo - Usado para acessar variáveis de estado do fim
    • Evento Folders e o Evento MatchEnd - Fires evento

    local PlayerManager = {}
    -- Serviços
    local Players = game:GetService("Players")
    local ServerStorage = game:GetService("ServerStorage")
    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    -- Módulos
    local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
    local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
    -- Eventos
    local events = ServerStorage:WaitForChild("Events")
    local matchEnd = events:WaitForChild("MatchEnd")
  2. Acima de respawnPlayerInLobby() , adicione uma nova função local chamada checkPlayerCount() .


    -- Variáveis do Jogador
    local activePlayers = {}
    local playerWeapon = ServerStorage.Weapon
    local function checkPlayerCount()
    end
    local function respawnPlayerInLobby(player)
  3. Dentro dessa função, use uma declaração if para verificar se há um vencedor. Na declaração:

    • Verifique se o tamanho da tabela activePlayers é 1.
    • Se sim, fire matchEnd e passe em gameSettings.endStates.FoundWinner .

    local function checkPlayerCount()
    if #activePlayers == 1 then
    matchEnd:Fire(gameSettings.endStates.FoundWinner)
    end
    end

Removendo um Jogador

Um contador preciso não pode ser mantido a menos que os jogadores sejam removidos. Quando um jogador for derrotado, mantenha um contador de jogadores preciso removendo-o da tabela de jogadores. Em seguida, verifique o tamanho da tabela de jogadores ativa para ver se há um vencedor.

  1. Sob checkPlayerCount(), crie uma nova função local chamada removeActivePlayer() com um parâmetro chamado player.


    local function checkPlayerCount()
    if #activePlayers == 1 then
    matchEnd:Fire(gameSettings.endStates.FoundWinner)
    end
    end
    local function removeActivePlayer(player)
    end
  2. Para encontrar o jogador na tabela activePlayers, itere através dela usando um loop for. Em seguida, adicione uma declaração if que será executada se um jogador correspondendo ao nome for encontrado na função.


    local function removeActivePlayer(player)
    for playerKey, whichPlayer in activePlayers do
    if whichPlayer == player then
    end
    end
    end
  3. Para remover o jogador, na declaração if:

    • Chame table.remove() . Dentro dos paises, passe em activePlayers , a tabela para olhar para dentro e playerKey - o jogador para remover da tabela.
    • Defina o valor do objeto playersLeft para #activePlayers.
    • Verifique se um jogador vencedor está executando checkPlayerCount() .

    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

Conectando Eventos e Testes

Para usar a função acabada de criar, chame-a a partir do evento anônimo conectado ao evento Died do jogador.

  1. Encontre preparePlayer() . Na função anônima com a conexão de evento Died, chame removeActivePlayer() . Então, passe no jogador como parâmetro.


    humanoid.Died:Connect(function()
    respawnPlayerInLobby(player)
    removeActivePlayer(player)
    end)
  2. Para ver se um jogador vencedor está encontrado, inicie um servidor de teste . Quando houver apenas um jogador restante, você deve ver o Ganhador encontrado na janela de saída.

  3. Continue testando e deixe o jogo terminar/parar/sair. Observe como uma nova partida começa, um erro aparece na janela de saída:

Este erro ocorre porque o timer não foi parado, o que será corrigido na próxima seção.

Parando o Temporizador

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, tenha o cronômetro parar sempre que o evento de partida terminar. Este é um dos benefícios de criar eventos. Eles podem ser reutilizados em várias situações para causar e efeito relacionados.

  1. No MatchManager, crie uma nova função local chamada stopTimer() . Dentro, digite myTimer:stop() para interromper o timer.


    -- Cria um novo objeto de relógio para ser usado para rastrear 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
  2. Para interromper o timer quando a partida terminar, conecte o evento matchEnd ao stopTimer() .


    -- Funções de Modulo
    function MatchManager.prepareGame()
    playerManager.sendPlayersToMatch()
    matchStart:Fire()
    end
    matchStart.Event:Connect(startTimer)
    matchEnd.Event:Connect(stopTimer)
    return MatchManager
  3. Teste que o erro anterior não aparece mais ao iniciar um servidor . Elimine todos, exceto um jogador e depois espere alguns segundos depois que a partida terminar.

Próximos passos

Enquanto as duas condições de vitória estiverem terminadas, ainda há algumas tarefas a serem concluídas para terminar o loop de jogo. Por instância, o jogador vencedor nunca é teletransportado para o lobby. Na próxima aula, você exibirá como a partida terminou para os jogadores e redefinirá o jogo, finalmente terminando todo o loop.

Scripts Concluídos

Abaixo estão scripts concluídos para verificar duas vezes seu trabalho.

Script do PlayerManager


local PlayerManager = {}
-- Serviços
local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Módulos
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 Modulo
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

Script das Configurações do Jogo


local GameSettings = {}
-- Variáveis do Jogo
GameSettings.intermissionDuration = 5
GameSettings.matchDuration = 10
GameSettings.minimumPlayers = 2
GameSettings.transitionTime = 5
-- Possíveis maneiras que o jogo pode terminar/parar/sair.
GameSettings.endStates = {
TimerUp = "TimerUp",
FoundWinner = "FoundWinner"
}
return GameSettings

Script do GameManager


-- Serviços
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
-- Scripts de Módulo
local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
local matchManager = require(moduleScripts:WaitForChild("MatchManager"))
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
local displayManager = require(moduleScripts:WaitForChild("DisplayManager"))
-- Eventos
local events = ServerStorage:WaitForChild("Events")
local matchEnd = events:WaitForChild("MatchEnd")
while true do
displayManager.updateStatus("Waiting for Players")
repeat
task.wait(gameSettings.intermissionDuration)
until #Players:GetPlayers() >= gameSettings.minimumPlayers
displayManager.updateStatus("Get ready!")
task.wait(gameSettings.transitionTime)
matchManager.prepareGame()
local endState = matchEnd.Event:Wait()
print("Game ended with: " .. endState)
end

Script do MatchManager


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 relógio para ser usado para rastrear 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 o display do timer termine em 1 em vez de 0.
timeLeft.Value = (math.floor(myTimer:getTimeLeft() + 1))
-- Ao não definir o tempo para esperar, ele oferece mais precisão de looping
task.wait()
end
end
-- Funções de Modulo
function MatchManager.prepareGame()
playerManager.sendPlayersToMatch()
matchStart:Fire()
end
matchStart.Event:Connect(startTimer)
matchEnd.Event:Connect(stopTimer)
return MatchManager