Generowanie to proces tworzenia obiektu lub postaci w doświadczeniu, a respawning to proces dodawania obiektu lub postaci do doświadczenia po spełnieniu warunku usunięcia, takiego jak zdrowie postaci osiągające zero lub spadające z mapy. Obie procesy są ważne, ponieważ zapewniają, że gracze mogą dołączyć do doświadczenia i nadal grać
Używając do referencji doświadczenie laserowe przy użyciu wtyczki Roblox, ta sekcja samouczka nauczy cię, jak używać i dostosowywać zbudowane funkcje Roblox, w tym kierunki skryptów na:
- Konfiguruj lokalizacje spawn, aby gracze mogli tylko spawnować w swojej strefie spawn.
- Dodawanie nowych graczy i ich postaci do rundy, gdy dołączają do doświadczenia.
- Dostosowywanie siłowych polów zapobiega uszkodzeniom podczas gdy gracze się pojawiają i odchodzą.
- Zarządzanie stanem klienta, aby zachować prawidłowe działanie gry w odpowiednim czasie.
- Respawning postaci po tym, jak zostały one oznaczone zakończenia rundy.
- Wykonanie małych, różnych akcji, które są niezbędne do ustawienia parametrów gry i postaci.
Ta sekcja zawiera mnóstwo treści skryptowej, ale zamiast wszystkiego od czegoś nowego przy tworzeniu doświadczenia, zachęca do wykorzystania już istniejących komponentów, szybkiego iterytowania i znalezienia tych systemów, które wymagają niestandardowej implementacji, aby zesynchronizować ich wizję. Po zakończeniu tej sekcji nauczysz się, jak zaimplementować rundowe gry, które śledzą punkty, monitorują stan grac
Konfiguruj lokalizacje spawn
Jeśli zagraszalibyście teraz w grę, wszystkie gracze pojawiłyby się losowo w obszarze SpawnLocation lub w obszarze SpawnLocation w obszarze różowej drużyny lub w obszarze Class.SpawnLocation w obszarze zielonej drużyny. To przedstawia problem gameplay, w którym gracze mogą tagować siebie n
Aby zmniejszyć ten problem, doświadczenie samplaser tag wykonuje obie lokalizacje spawnu z ustawieniem Neutral na fałszywy , aby ograniczyć graczy przeciwnej drużyny z spawn
- TeamASpawn – Miejsce pojawienia się w strefie spawn zespołu zielnego z zestawem właściwości TeamColor ustawionym na Mint .
- TeamBSpawn – Miejsce pojawienia się w strefie spawn zespołu różowego z zestawem właściwości TeamColor ustawionym na Karmazynowy Róż .
Gdy gracz dołącza do doświadczenia, ServerScriptService > Gameplay > Rounds > 1> Rounds1> > 4> spawnePlayersInMap4> sprawdza, ile graczy jest już na każdej drużynie, a następnie wraca drużynę z najmniejszą liczbą graczy.
spawnGraczyNaMapie
local function getSmallestTeam(): Team
local teams = Teams:GetTeams()
-- Sortuj zespoły w rosnąco mniejszej kolejności od najmniejszego do największego
table.sort(teams, function(teamA: Team, teamB: Team)
return #teamA:GetPlayers() < #teamB:GetPlayers()
end)
-- Wróć najmniejszy zespół
return teams[1]
end
Gdy wie, że drużyna ma najmniej graczy, sortuje gracza w tę drużynę, ustawia jego właściwość Player.Neutral na fałszywą tak, że gracz może tylko zostać wygenerowany i odrodzony w lokalizacji wyrodziny swojej drużyny, a następnie ustawiть jego PlayerState na
spawnGraczyNaMapie
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
Jeśli zbadasz Przestrzeń roboczą > Świat > Mapę > 1>Spawn1>>, możesz zobaczyć, że ist
Na przykład, jeśli runda jest aktywna, właściwość Neutral ustawiona na fałsz, aby spawnPlayersIn
Aby pokazać, jeśli zbadasz ServerScriptService > Gry > Rounds > 2>Roundy2> > 5>SpawnePlayersInLobby5>, który biegnie na końcu rundy, możesz zobaczyć, że dla każdego gracza, który jest przepustany do tabeli 8>players: player8>, skrypt:
- Ustawia ich właściwość Player.Neutral na prawdę, aby automatycznie ustawić ich Player.Team na nil, pozwalając graczowi na respawn w lobby, gdy rundy nie są aktywne, ponieważ właściwość Neutral jest również ustawiona na 1> prawdę1>.
- Zmienia ich PlayerState na InLobby, aby usunąć wizualne blastera gracza i pierwszej osoby interfejsu.
Dla więcej informacji na temat strefy neutralnego powstawania i jej funkcjonalności dla każdego rundy, zobacz Dodawanie rund w następnym sekcji tutorialu.
spawnGry w lobby
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
Połącz nowych graczy
Kod Luau w Studio jest często oparty na wydarzeniach, co oznacza, że skrypty słuchają wydarzeń z usługi Roblox, a następnie wzywają funkcję w odpowiedzi. Na przykład, przy dodawaniu nowych graczy do doświadczenia wieloosobowego, musi być wydarzenie, które obsługuje wszystko niezbędne dla graczy, aby połączyć się pomyślnie. W przykładzie laser tag doświadczenia, ten od
Players.PlayerAdded:Connect jest częścią wielu skryptów w doświadczeniu. Jeśli użyjesz skrótu Ctrl/Commands+Shift+F i szukasz Players.PlayerAdded:Connect, wyniki zapewniają dobry punkt wyjścia do zrozumienia początkowego ustawienia doświadczenia.
Aby pokazać, otwórz ServerScriptService > SetupHumanoid . Różnica między Player a 1> Class.Player.Character|Character1> jest kluczowa do zrozumienia tego skryptu:
- Gracz jest połączonym klientem, a model postaci jest Class.Humanoid model.
- Gracze muszą wybrać blaster i zostać dodani do tabeli ranking. Postacie muszą się zbierać i otrzymywać blaster.
SetupHumanoid natychmiastowo sprawdza, czy gracz ma postać (właśnie dołączył) lub nie (zrespawnuje). Po znalezieniu jednej z nich, wzywa
obsługaHumanoidAsync
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
Istotnym jest, że właściwości są całkowicie opcjonalne, co oznacza, że jeśli usuniesz pierwsze sześć linii funkcji, doświadczenie nadal działa poprawnie. Zamiast być wymaganiami funkcjonalnymi każda właściwość pozwala na podejmowanie decyzji projektowych, które spełniają twoje cele w grze. Na przykład:
- Jeśli chcesz, aby imiona postaci były wyświetlane w bliższych odległościach, zmniejsz wartość Humanoid.NameDisplayDistance .
- Jeśli chcesz tylko zdrowia postaci, aby było ono poniżej 100%, ustaw Humanoid.HealthDisplayType na Wyświetlaj kiedy uszkodzony .
- Jeśli chcesz, aby postacie się rozdzielały, gdy ich zdrowie osiągnie 0, ustaw Humanoid.BreakJointsOnDeath na Prawdziwy .
Jeśli zmienisz wartości tych właściwości, ważne jest, aby przetestować, abyś mógł zobaczyć wpływ swoich nowych ustawień. Możesz recenzować to, co doświadczają gracze w wielowymiarowej środowisku, wybierając co najmniej dwóch postaci w sekcji Klienci i serwerzy w zakładce Test.
Kolejnym przykładem wydarzenia Players.PlayerAdded:Connect jest w ServerScriptService > PlayerStateHandler . Tak jak w poprzednim przykładzie, 1> PlayerStatusHandler1> natych
Zaawansowana obsługa gracza
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)
Jedną z podstawowych zmiennych w PlayerStateHandler warunki dyskusji dotyczą attributeChangedConnectionByPlayer. Ta tabela przechowuje wszystkich graczy i ich Datatype.RBXScriptConnection|Connections
Zaawansowana obsługa gracza
local attributeChangedConnectionByPlayer = {}
local function onPlayerAdded(player: Player)
-- Zarządzaj wszystkimi przyszłymi aktualizacjami stanu gracza
attributeChangedConnectionByPlayer[player] = player
:GetAttributeChangedSignal(PlayerAttribute.playerState)
:Connect(function()
local newPlayerState = player:GetAttribute(PlayerAttribute.playerState)
onPlayerStateChanged(player, newPlayerState)
end)
end
-- Rozłącz się z zmienioną połączeniem atrybutu, gdy gracz wychodzi
local function onPlayerRemoving(player: Player)
if attributeChangedConnectionByPlayer[player] then
attributeChangedConnectionByPlayer[player]:Disconnect()
attributeChangedConnectionByPlayer[player] = nil
end
end
Możesz zobaczyć, że obie połączone funkcje w onPlayerAdded() wzywają onPlayerStateChanged() . Podczas pierwszej ustawy po tym, jak gracz sortuje się w drużyn
Zaawansowana obsługa gracza
local function onPlayerStateChanged(player: Player, newPlayerState: string)
-- Stan błękitnego jest „Gotowy”, tylko jeśli stan gracza jest „Gry”
local newBlasterState = if newPlayerState == PlayerState.Playing then BlasterState.Ready else BlasterState.Disabled
-- Zapisz logikę sił zniszczenia, gdy gracz zacznie grać
if newPlayerState == PlayerState.Playing then
scheduleDestroyForceField(player)
end
player:SetAttribute(PlayerAttribute.blasterStateServer, newBlasterState)
end
Jeśli dodasz breakpoints lub nawet tylko print()
Dostosuj pola siłowe
Zamiast używać niestandardowej implementacji, doświadczenie laserowego tagu przykładowego używa wbudowanej klasy ForceField , aby zapobiec graczom uszkodzenia, gdy wybierają swojego blastera. To zapewn
Podobnie jak setupHumanoidAsync , większość linii w ForceFieldClientVisuals jest opcjonalna. Na przykład, jeśli komentujesz treści funkcji, takie jak poniższy skrypt, doświadczenie używa pola sił świecącego domyślnie zamiast Heksagonowego Skryptu w StarterGui > 1>ForceFieldGui1> .
Komentowanie właściwości w ForceFieldClientVisuals
local function onCharacterAddedAsync(character: Model)
-- lokalne forceField = charakter:WaitForChild("ForceField", 3)
-- jeśli nie forceField to
-- zwróć
-- kończyć
-- forceField.Visible = fałszywy
-- localPlayer.PlayerGui:WaitForChild("ForceFieldGui").Enabled = prawdziwy
-- forceField.Destroying:Wait()
-- localPlayer.PlayerGui.ForceFieldGui.Enabled = fałszywy
end
Ponieważ niestandardowy force field jest GUI, a nie nowy ParticleEmitter, skrypt ForceFieldClientVisuals dotyczy tylko wizualizacji pierwszej osoby dla każdego gracza, nie wizualizacji trzeciej osoby, gdy gracze patrzą na innych graczy. Wizualizacje trzeciej osoby zachowują domy
Pole siłowe są przydatne, ponieważ daje graczom wystarczająco dużo czasu na pomiędzy pojawieniem się i odrodzeniem bez konieczności martwić się o graczy z wrogich gier, ale w końcu muszą one zniknąć dla głównej rozgrywkalaserowej. Skrypt, który traktuje usunięcie pola siłowego, znajduje się w ReplicatedStorage > scheduleDestroyForceField i sprawdza trzy unikalne warunki:
- Po wyborze graczy blaster, pola siłowe muszą być wystarczająco trwałe, aby umożliwić graczom przyzwyczenie się do swojego otoczenia.
- Podczas tego czasu aklimatyzacji pola siłowe nie mogą być zaletą, więc muszą zniknąć, gdy gracz wystrzeli swoją wyrzutnię.
- Pole siłowe musi zniknąć, gdy gracze resetują ich postacie przed wybuchiem lub przed upływem czasu pola siłowego.
Każdy z tych czynników w scheduleDestroyForceField skryptu wezwania endForceField() dla tych warunków.
scheduleZniszcz siłę
-- Zakończ pola siłowe, jeśli gracz wybucha
local blasterStateAttribute = getBlasterStateAttribute()
attributeChangedConnection = player:GetAttributeChangedSignal(blasterStateAttribute):Connect(function()
local currentBlasterState = player:GetAttribute(blasterStateAttribute)
if currentBlasterState == BlasterState.Blasting then
endForceField()
end
end)
-- Zakończ pola siłowe, jeśli gracz zresetuje
characterRespawnedConnection = player.CharacterRemoving:Connect(endForceField)
-- Zakończ pola siłowe po 8 sekundach
task.delay(MAX_FORCE_FIELD_TIME, endForceField)
endForceField() zawiera wydaje się dziwne if oświadczenie wokół forceFieldEnded funkcji. Ponieważ czynniki będą wykonane kolejno, skrypt może wezwywać funkcję 0> endForceField0> dwa lub nawet trzy razy. Funkcja 3> endForceField</
scheduleZniszcz siłę
local function endForceField()
if forceFieldEnded then
return
end
forceFieldEnded = true
attributeChangedConnection:Disconnect()
characterRespawnedConnection:Disconnect()
destroyForceField(player)
end
Zarządzanie stanem klienta
Podczas gdy większość tego sekcji koncentruje się na ServerScriptService > PlayerStateHandler , jest inny skrypt tego samego nazwy w ReplicatedStorage . Powodem podzielenia jest architektura klient-serwer:
Klient musi zrozumieć informacje o stanie gracza, aby mógł odpowiednio reagować w czasie rzeczywistym, takie jak wyświetlanie elementów interfejsu użytkownika lub umożliwienie graczom ruchu i eksplozji.
Serwer potrzebuje wszystkich tych samych informacji, aby mógł zapobiec wykorzystaniu. Na przykład, serwer potrzebuje również statusu gracza, aby wykonać akcje, takie jak generowanie i używanie postaci, dezaktywowanie pola sił i wyświetlanie tabeli ranking. To jest powodem, dla którego ten skrypt jest w ReplicatedStorage i nie jest lokalizacją stron internetowych.
Aby zobaczyć tę logikę rdzenia, przeglądaj następujący skrypt w ReplicatedStorage > PlayerStateHandler , który weryfikuje aktualny stan użytkownika i wzywa odpowiednią funkcję, która obsługuje odpowiednie działania dla tego stanu.
Zaawansowana obsługa gracza
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
Wszystkie odpowiedzi na wszystkie wydarzenia są logicznie zespożone w tym skrypcie, ponieważ wymagają one podobnego zachowania włączania lub wyłączania sterowania graczem, ruchu kamery i która warstwa UI jest widoczna. Na przykład, podczas wyboru blastera gracze muszą być zarówno niezawodni, jak i nie
Zaawansowana obsługa gracza
local function onSelectingBlaster()
togglePlayerCamera(true)
togglePlayerMovement(false)
setGuiExclusivelyEnabled(playerGui.PickABlasterGui)
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end
Funkcja onPlaying() jest podobnie prosta. Włącza ruch, przejścia do głównego ekranu HUD (HUD), włącza blaster i wzywa tę samą funkcję pola sił, jak na serwerze.
Zaawansowana obsługa gracza
local function onPlaying()
togglePlayerMovement(true)
setGuiExclusivelyEnabled(playerGui.HUDGui)
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Ready)
scheduleDestroyForceField()
end
Odrodzić postacie
Doświadczenie laserowe samplera porusza znacznie więcej znaków z powodu onTaggedOut() stanu w ReplicatedStorage > PlayerStateHandler . Jak w przypadku 2> on
Zaawansowana obsługa gracza
local function onTaggedOut()
-- Wyłącz sterowanie podczas gdy jesteś wyłączony
togglePlayerMovement(false)
togglePlayerCamera(false)
setGuiExclusivelyEnabled(playerGui.OutStateGui)
-- Wyłącz blaster, gdy jesteś niemarkowany
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end
Jeśli chcesz przetesterować ten zachowanie, możesz nacisnąć Esc, przejść do zakładki Ustawienia i następnie kliknąć przycisk Zresetuj postać . Zauważ, że gdy włączysz ekran rezpawnu, nie możesz się poruszać, obrócić kamerę lub eksplodować swojego blastera.
Ważne jest, aby zauważyć, że ten skrypt nie ma faktycznie postępujących post
Gdy gracze rezpawnują do rundy, zostaną one odrodzone w lokalizacji swojego zespołu zgodnie z właściwością SpawnLocation.TeamColor. Aby dostosować czas odrodzienia, można dodać następującą linię do góry SetupHumanoid . Aby dowiedzieć się więcej o tej technice, zobacz Class.Players.
Zwiazany człowiek
local Players = game:GetService("Players")Players.RespawnTime = 10 -- new line, in seconds
Różne Ustawienia
Jako część pierwszej ustawy, doświadczenie laserowego tagu próbuje również kilku małych, ale krytycznych kroków:
Doświadczenie zawiera pusty skrypt nazyający się StarterPlayer > StarterCharacterScripts > Health , który wyłącza domyślną regenerację zdrowia Roblox. Aby uzyskać wyjaśnienie zachowania tej właściwości, zobacz 1> Class.Humanoid.Health1> .
Doświadczenie używa kamery pierwszej osoby, ustawiając właściwość StarterPlayer.CameraMode.LockFirstPerson. Uwaga, jeśli chcesz pozwolić użytkownikom zmieniać między kamerkami pierwszej i trzeciej osoby, musisz zmienić programem właściwości, a nie po prostu ustawić go raz w Studio, aby kompensować zmianę perspektywy.
Doświadczenie używa zintegrowanego rankingu Roblox z jednostką "punktów", którzy gracze zarabiają za każdym razem, gdy oznaczają innego gracza. Możesz zobaczyć konfigurację w ServerScriptService > SetupLeader
Teraz, gdy gracze mogą się pojawić, wybierz blaster i celuj go z punktu widzenia pierwszej osoby, następny rozdział uczy cię o skryptach zaangażowanych w tworzenie rozgrywkaopartej na rundach.