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.
- 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.
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 = 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 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)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)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.
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.
In GameSettings, create an empty module table named endStates .
local GameSettings = {}-- Variáveis do JogoGameSettings.intermissionDuration = 5GameSettings.matchDuration = 10GameSettings.minimumPlayers = 2GameSettings.transitionTime = 5-- Possíveis maneiras que o jogo pode terminar/parar/sair.GameSettings.endStates = {}return GameSettingsCrie 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.
Em GameManager , na while true do loop, find the line matchEnd.Event:Wait() . No começo da linha, adicionar 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)endIn 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> .
-- Valoreslocal 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 Locaislocal function timeUp()matchEnd:Fire(gameSettings.endStates.TimerUp)endTeste 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.
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çoslocal Players = game:GetService("Players")local ServerStorage = game:GetService("ServerStorage")local ReplicatedStorage = game:GetService("ReplicatedStorage")-- Móduloslocal 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 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 thenmatchEnd:Fire(gameSettings.endStates.FoundWinner)endend
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.
Sob 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 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 doif whichPlayer == player thenendendendPara 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 doif whichPlayer == player thentable.remove(activePlayers, playerKey)playersLeft.Value = #activePlayerscheckPlayerCount()endendend
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.
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)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.
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.
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 Locaislocal function stopTimer()myTimer:stop()endlocal function timeUp()matchEnd:Fire(gameSettings.endStates.TimerUp)endPara interromper o timer quando a partida terminar, conecte o evento matchEnd ao stopTimer() .
-- Funções de Modulofunction 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 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 JogoGameSettings.intermissionDuration = 5GameSettings.matchDuration = 10GameSettings.minimumPlayers = 2GameSettings.transitionTime = 5-- Possíveis maneiras que o jogo pode terminar/parar/sair.GameSettings.endStates = {TimerUp = "TimerUp",FoundWinner = "FoundWinner"}return GameSettings
Script do GameManager
-- 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
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