Pokazywanie i odawianie

*Ta zawartość została przetłumaczona przy użyciu narzędzi AI (w wersji beta) i może zawierać błędy. Aby wyświetlić tę stronę w języku angielskim, kliknij tutaj.

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óż .
Zespół ASPR
TeamBSpawn

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

Neutralny

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.

Studio's Find All window with the Players.PlayerAdded results highlighted.

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 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.

Studio's Test tab with the the players dropdown highlighted. This setting needs to be at least two players to see the impact of your new settings.

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

First-person force field visuals include a futuristic hexagonal grid on the perimeter of the screen.
Widoki sił pola sił w pierwszej osobie
Third-person force field visuals include a blue sparkling orb around the player spawning into the experience.
Widoki sił pola widzenia trzeciej osoby

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.

Roblox's settings menu with the Reset Character button highlighted.
Przycisk Reset Character Button
The respawn screen displays as a player respawns back into the round.
Odtwórz ekran

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.