Mecze mogą zakończyć się w kilku warunkach, w tym wygaśnięciem czasomierzy lub pozostawieniem pojedynczego gracza.
Zarządzaj pokonanymi graczami
W tej chwili pokonani gracze odrodzić się na arenie. Zamiast tego wyślij ich z powrotem do lobby, aby czekali na następny dopasowywać.
- W PlayerManager, utwórz lokalną funkcję o nazwie respawnPlayerInLobby(). W tej funkcji wykonaj obserwujeczynności:
- Ustaw właściwość RespawnLocation gracza na lobbySpawn.
- Przeładuj postać za pomocą Player:LoadCharacter() . Pamiętaj, że LoadCharacter() odtwarza gracza na ich spawnie, usuwając wszelkie narzędzia, które miał.
Użyj anonimowych funkcji
Funkcje anonimowe są powszechnie używane w zaawansowanych skryptach w konkretnych sytuacjach.Zanim zdefiniujesz je, ważne jest zrozumienie sytuacji, z jaką twój skrypt może się spotkać.
Weź to pod uwagę: Aby teleportować pokonanych graczy do lobby, funkcja odrodzenia musi być połączona z wydarzeniem Śmierć gracza.Jest jednak problem.Jeśli połączysz wydarzenie tak, jak miało to miejsce w przeszłości, nie ma możliwości uzyskania nazwy gracza z wydarzenia Died.Skrypt potrzebuje tej nazwy, aby usunąć pokonanego gracza z tabeli śledzenia aktywnych graczy.
Aby uzyskać nazwę gracza, który uruchomił wydarzenie Śmierć, użyj funkcji anonimowej. Funkcje anonimowe nie mają nazw i mogą być tworzone bezpośrednio w Connect() zamiast oddzielnie.
Próbna funkcja anonimowa jest poniżej, która pokazuje sytaks.
myPlayer.Died:Connect(function()
print(player)
end)
Zakoduj wydarzenie umierające
Dla tej funkcji, za każdym razem, gdy postać gracza umiera, uruchamia się funkcja, która je odrodzi.
Aby uzyskać dostęp do wydarzenia Śmierć gracza, w PlayerManager > preparePlayer(), dodaj zmienną dla ludzkiego gracza.
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")endStwórz anonimową funkcję, która łączy się z wydarzeniem Died.Zacznij od wpisania humanoid.Died:Connect().Następnie, wewnątrz Connect() , wpisz function() , naciśnij Enter , aby uzupełnić automatycznie end i usuń dodatkową spójnik.
local humanoid = character:WaitForChild("Humanoid")humanoid.Died:Connect(function()end)W funkcji anonimowej wezwij respawnPlayerInLobby(). Przekaż player, zmienną przechowującą gracza, który przygotowuje się do wejścia w dopasowywać.
local humanoid = character:WaitForChild("Humanoid")humanoid.Died:Connect(function()respawnPlayerInLobby(player)end)Uruchom serwer i rozegraj dopasowywać.Sprawdź, czy gdy gracz umrze, odrodzą się w lobby.Aby pokonać graczy, podejdź do nich i użyj swojej broni, dopóki nie potwierdzisz, że odrodziły się w lobby.
Atakowanie gracza2 Gracz2 w lobby po odrodzeniu
Uwaga, istnieją również różne sposoby testowania, jeśli jest to pożądane.
- Aby zabić gracza, w oknie Server > Output > Command Bar skopiuj i wklej: workspace.Player1.Humanoid.Health = 0 .Naciśnij Enter , aby wykonać polecenie.Aby usunąć innych graczy, użyj Player2, Player3 itp.
- Ustawienie GameSettings > matchDuration na dłuższy czas może dać ci więcej czasu na znalezienie i wyeliminowanie wszystkich graczy.
- Aby przeprowadzać szybsze testy, zmień GameSettings > minimumPlayers na mniejszą liczbę, taką jak 2.
Zakończ gra
Teraz, gdy pokonani gracze odrodziły się, zacznij pracować nad zakończeniem gry.Pamiętasz tworzenie wydarzenia MatchEnd? Zostanie uruchomiony, gdy skończy się czas lub znaleziono zwycięzcę.
Aby powiedzieć innym skryptom, które warunki zakończyły gra, stwórz tabelę z zmiennymi dla TimerUp i FoundWinner.Gdy wydarzenie końcowe meczu się wystrzeli, przekaże zmienną, aby inne skrypty mogły odpowiedzieć.
W ustawieniach gry utwórz pustą tabelę modułów o nazwie endStates.
local GameSettings = {}-- Zmienne gryGameSettings.intermissionDuration = 5GameSettings.matchDuration = 10GameSettings.minimumPlayers = 2GameSettings.transitionTime = 5-- Możliwe sposoby, w jakie gra może się zakończyć.GameSettings.endStates = {}return GameSettingsStwórz dwie zmienne o nazwie TimerUp i FoundWinner. Każdą z nich ustaw na strunę pasującą do jej nazwy. Te struny zostaną użyte do testowania kodu.
GameSettings.endStates = {TimerUp = "TimerUp",FoundWinner = "FoundWinner"}
Zakończ z timera
Gdy czasomierz się skończy, uruchom wydarzenie Koniec meczu i wysyłaj odpowiadającą zmienną końcowego stanu.W ten sposób inne skrypty słuchające tego wydarzenia mogą odpowiednio reagować.Pamiętaj, że podczas wystrzeliwania sygnałów zdarzeń można również wysyłać dane otrzymane przez skrypty słuchające, takie jak TimerUp lub FoundWinner.
W GameManager , w pętli while prawda, znajdź linię matchEnd.Event:Wait(). Na początku linii dodaj 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()endAby potwierdzić, że otrzymano poprawne stanowisko, dodaj oświadczenie drukujące, w tym 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)endW MatchManager znajdź timeUp() i usuń oświadczenie drukujące.Następnie, aby uruchomić wydarzenie końcowe meczu, wpisz matchEnd:Fire() i przekaż gameSettings.endStates.TimerUp.
-- Wartościlocal displayValues = ReplicatedStorage:WaitForChild("DisplayValues")local timeLeft = displayValues:WaitForChild("TimeLeft")-- Tworzy nowy obiekt minutnika, który ma być używany do śledzenia czasu meczu.local myTimer = timer.new()-- Lokalne funkcjelocal function timeUp()matchEnd:Fire(gameSettings.endStates.TimerUp)endPrzetestuj dopasowywać. Po wyczerpaniu czasu sprawdź, czy oświadczenie drukujące zawiera ciąg przechowany w zmiennej TimerUp.
Wskazówki dotyczące rozwiązywania problemów
W tym momencie wiadomość nie została wyświetlona, spróbuj jednej z poniższych opcji.
- Sprawdź, że gdziekolwiek są wywoływane zmienne stanu końcowego, są one zapisane dokładnie, tak jak tutaj: gameSettings.endStates.TimerUp .
- Upewnij się, że używasz : (operator kolonki) zamiast operatora kropki, tak jak w Fire() zamiast operatora kropki, jak w matchEnd:Fire() .
Zrealizuj wygraną dopasowywać
Następnie skrypt musi zidentyfikować zwycięskich graczy, usunąć przegrywających graczy i uruchomić sprzątanie, takie jak zatrzymanie timera.Rozgrywki zakończą się również, jeśli jeden gracz zostanie wykluczony.Aby sprawdzić, czy spełniona jest warunek FoundWinner, potrzebujesz funkcji, która sprawdza numer pozostawiony w tabeli śledzącej graczy w dopasowywać.
Sprawdź liczbę graczy
Rozgrywki zakończą się, jeśli pozostanie tylko jeden gracz.Aby to sprawdzić, skrypt musi śledzić graczy w rundzie.Gdy jeden gracz zostanie wyeliminowany, można przydzielić zwycięzcę.
W PlayerManager określ następujące zmienne:
- Katalog ModuleScripts
- Moduł GameSettings - Używany do dostępu do zmiennych stanu końcowego
- Katalog wydarzeń i wydarzenie MatchEnd - Wydarzenie ognia
local PlayerManager = {}-- Usługilocal Players = game:GetService("Players")local ServerStorage = game:GetService("ServerStorage")local ReplicatedStorage = game:GetService("ReplicatedStorage")-- Modułylocal moduleScripts = ServerStorage:WaitForChild("ModuleScripts")local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))-- Wydarzenialocal events = ServerStorage:WaitForChild("Events")local matchEnd = events:WaitForChild("MatchEnd")Powyżej respawnPlayerInLobby(), dodaj nową lokalną funkcję o nazwie checkPlayerCount().
-- Zmienne graczalocal activePlayers = {}local playerWeapon = ServerStorage.Weaponlocal function checkPlayerCount()endlocal function respawnPlayerInLobby(player)W ramach tej funkcji użyj oświadczenia if następnie, aby sprawdzić, czy występuje zwycięzca. W tym oświadczeniu:
- Sprawdź, czy rozmiar tabeli activePlayers jest 1.
- Jeśli tak, strzelaj matchEnd i przekaż gameSettings.endStates.FoundWinner.
local function checkPlayerCount()if #activePlayers == 1 thenmatchEnd:Fire(gameSettings.endStates.FoundWinner)endend
Usuń gracza
Dokładny licznik nie może być utrzymywany, chyba że gracze zostaną usunięci.Gdy gracz zostanie pokonany, utrzymaj dokładną liczbę graczy, usuwając ich z tabeli graczy.Następnie sprawdź rozmiar aktywnego stołu graczy, aby zobaczyć, czy jest zwycięzca.
Poniżej checkPlayerCount(), utwórz nową lokalną funkcję o nazwie removeActivePlayer() z parametrem o nazwie player.
local function checkPlayerCount()if #activePlayers == 1 thenmatchEnd:Fire(gameSettings.endStates.FoundWinner)endendlocal function removeActivePlayer(player)endAby znaleźć gracza w tabeli activePlayers, powtórz go za pomocą pętli for.Następnie dodaj oświadczenie if, które uruchamia się, gdy znaleziono gracza pasującego do nazwy przekazanej do funkcji.
local function removeActivePlayer(player)for playerKey, whichPlayer in activePlayers doif whichPlayer == player thenendendendAby usunąć gracza, w oświadczeniu if:
- Wezwij table.remove(). W nawiasach przekaż activePlayers , tabelę, którą należy sprawdzić, oraz playerKey - gracza, który należy usunąć z tabeli.
- Ustaw wartość obiektu playersLeft na #activePlayers.
- Sprawdź, czy jest zwycięski gracz, uruchamiając checkPlayerCount() .
local function removeActivePlayer(player)for playerKey, whichPlayer in activePlayers doif whichPlayer == player thentable.remove(activePlayers, playerKey)playersLeft.Value = #activePlayerscheckPlayerCount()endendend
Połącz wydarzenia i przetestuj
Aby skorzystać z właśnie utworzonej funkcji, wezwij ją z wewnątrz anonimowej funkcji połączonej z wydarzeniem gracza Died.
Znajdź preparePlayer() . W anonimowej funkcji z połączeniem wydarzenia Died wezwij removeActivePlayer() . Następnie przekaż gracza jako parametr.
humanoid.Died:Connect(function()respawnPlayerInLobby(player)removeActivePlayer(player)end)Aby sprawdzić, czy znaleziono zwycięskiego gracza, uruchom serwer testowy .Gdy pozostaje tylko jeden gracz, powinieneś zobaczyć FoundWinner w oknie wyjściowym.
Kontynuuj testy i pozwól, aby mecz się kończyć. Zauważ, jak nowy mecz się rozpoczyna, pojawia się błąd w oknie wyjściowym:
Ten błąd wynika z tego, że czasomierz nie został zatrzymany, co zostanie naprawione w następnej sekcji.
Zatrzymaj minutnik
Zawsze, gdy mecz kończy się wygraną graczem, czasomierz również powinien się zatrzymać.Aby zatrzymać zegar przed upływem czasu, zatrzymaj zegar za każdym razem, gdy uruchamia się wydarzenie końca meczu.Jest to jedna z korzyści z tworzenia wydarzeń.Można je ponownie wykorzystać w wielu sytuacjach, aby zapisać relacje przyczyny i skutku skryptu.
W MatchManager stwórz nową lokalną funkcję o nazwie stopTimer(). Wewnątrz wpisz myTimer:stop() , aby zatrzymać zegar.
-- Tworzy nowy obiekt minutnika, który ma być używany do śledzenia czasu meczu.local myTimer = timer.new()-- Lokalne funkcjelocal function stopTimer()myTimer:stop()endlocal function timeUp()matchEnd:Fire(gameSettings.endStates.TimerUp)endAby zatrzymać zegar, gdy mecz się zakończy, połącz wydarzenie matchEnd z stopTimer().
-- Funkcje modułufunction MatchManager.prepareGame()playerManager.sendPlayersToMatch()matchStart:Fire()endmatchStart.Event:Connect(startTimer)matchEnd.Event:Connect(stopTimer)return MatchManagerTestuj , że poprzedni błąd nie pojawia się już, uruchamiając serwer .Wyeliminuj wszystkich, ale jednego gracza, a następnie poczekaj kilka sekund, gdy mecz się zakończy.
Kolejne kroki
Choć warunki wygranej obu stron są skończone, nadal pozostają niektóre zadania do zakończenia pętla gry.Na instancja, wygrywający gracz nigdy nie jest teleportowany do lobby.W następnej lekcji wyświetlisz, jak mecz zakończył się dla graczy i zresetujesz grę, wreszcie ukończywszy całą pętlę.
Zakończone skrypty
Poniżej są ukończone skrypty do sprawdzenia podwójnego swojej pracy.
Skrypt menedżera graczy
local PlayerManager = {}
-- Usługi
local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Moduły
local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
-- Wydarzenia
local events = ServerStorage:WaitForChild("Events")
local matchEnd = events:WaitForChild("MatchEnd")
-- Zmienne mapy
local lobbySpawn = workspace.Lobby.StartSpawn
local arenaMap = workspace.Arena
local spawnLocations = arenaMap.SpawnLocations
-- Wartości
local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")
local playersLeft = displayValues:WaitForChild("PlayersLeft")
-- Zmienne gracza
local activePlayers = {}
local playerWeapon = ServerStorage.Weapon
-- Lokalne funkcje
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
-- Funkcje modułu
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
-- Wydarzenia
Players.PlayerAdded:Connect(onPlayerJoin)
return PlayerManager
Skrypt ustawień gry
local GameSettings = {}-- Zmienne gryGameSettings.intermissionDuration = 5GameSettings.matchDuration = 10GameSettings.minimumPlayers = 2GameSettings.transitionTime = 5-- Możliwe sposoby, w jakie gra może się zakończyć.GameSettings.endStates = {TimerUp = "TimerUp",FoundWinner = "FoundWinner"}return GameSettings
Skrypt Menadżera gry
-- Usługilocal ServerStorage = game:GetService("ServerStorage")local Players = game:GetService("Players")-- Skrypty modułowelocal moduleScripts = ServerStorage:WaitForChild("ModuleScripts")local matchManager = require(moduleScripts:WaitForChild("MatchManager"))local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))local displayManager = require(moduleScripts:WaitForChild("DisplayManager"))-- Wydarzenialocal 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
Skrypt Menadżera meczów
local MatchManager = {}
-- Usługi
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Skrypty modułowe
local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
local playerManager = require(moduleScripts:WaitForChild("PlayerManager"))
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
local timer = require(moduleScripts:WaitForChild("Timer"))
-- Wydarzenia
local events = ServerStorage:WaitForChild("Events")
local matchStart = events:WaitForChild("MatchStart")
local matchEnd = events:WaitForChild("MatchEnd")
-- Wartości
local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")
local timeLeft = displayValues:WaitForChild("TimeLeft")
-- Tworzy nowy obiekt minutnika, który ma być używany do śledzenia czasu meczu.
local myTimer = timer.new()
-- Lokalne funkcje
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
-- Dodanie +1 sprawia, że wyświetlanie czasu kończy się na 1 zamiast na 0.
timeLeft.Value = (myTimer:getTimeLeft() + 1) // 1
-- Nie ustawiając czasu oczekiwania, oferuje dokładniejsze pętle
task.wait()
end
end
-- Funkcje modułu
function MatchManager.prepareGame()
playerManager.sendPlayersToMatch()
matchStart:Fire()
end
matchStart.Event:Connect(startTimer)
matchEnd.Event:Connect(stopTimer)
return MatchManager