Aby uzyskać efekt wizualny migotania infiltratorów, musisz naprzemiennie ukrywać i pokazywać postać każdego gracza. Chcesz ustawić takie zachowanie w funkcji za każdym razem, gdy infiltrator odniesie obrażenia, jednak musisz również upewnić się, że pozostała część kodu będzie nieprzerwanie wykonywana, gdy funkcja ta zostanie wywołana. Sytuacja komplikuje się jeszcze bardziej, gdy masz wielu infiltratorów. W trakcie gry wielu infiltratorów może doznać obrażeń równocześnie, dlatego musisz opracować kod, który pozwoli obsłużyć każdego z nich z osobna.
W tym celu intensywnie wykorzystasz wyrażenie spawn. Spawnowanie funkcji umożliwia uruchamianie jej w sposób asynchroniczny, bez wstrzymywania wykonywania reszty kodu. Spawnując funkcję dla każdego infiltratora zyskujesz pewność, że migotanie każdego z infiltratorów odbywa się w sposób niezależny od pozostałych.
Poniższa procedura ilustruje, w jaki sposób skonfigurować migotanie postaci poszczególnych infiltratorów, gdy odnoszą oni obrażenia.
Tworzenie pętli migotania
- Dodaj nową funkcję
FlickerCharacter()
do definicji klasyinvisibility_manager
. Ta funkcja pobierafort_character
i naprzemiennie włącza i wyłącza widoczność postaci w celu uzyskania efektu migotania. Dodaj specyfikator<suspends>
do tej funkcji, aby umożliwić uruchamianie jej w sposób asynchroniczny.# Zmienia widoczność agenta poprzez wielokrotne ukrywanie i pokazywanie jego fort_character FlickerCharacter(InCharacter:fort_character)<suspends>:void= Logger.Print("Wywołano FlickerCharacter()")
- W funkcji
FlickerCharacter()
zapętlHide()
dlaInCharacter
, ustaw wSleep()
określoną ilość czasu (zdefiniowaną wcześniej wartośćFlickerRateSeconds
), pokaż postać za pomocą funkcjiShow()
, a następnie ponownie zastosuj uśpienie. Pozwoli to uzyskać efekt migotania postaci, dzięki któremu gracze drużyn przeciwnych będą mogli wyśledzić postać, jednak krótkie okresy niewidoczności utrudnią im celowanie.# Zmienia widoczność agenta poprzez wielokrotne ukrywanie i pokazywanie jego fort_character FlickerCharacter(InCharacter:fort_character)<suspends>:void= Logger.Print("Wywołano FlickerCharacter()") # Pętla powodująca ukrywanie i pokazywanie postaci w celu uzyskania efektu migotania. loop: InCharacter.Hide() Sleep(FlickerRateSeconds) InCharacter.Show() Sleep(FlickerRateSeconds)
Przerywanie pętli
Musisz mieć możliwość przerwania tej zapętlonej funkcji, gdy postać ma przestać migotać. Skonfigurowana wcześniej mapa
PlayerVisibilitySeconds
śledzi pozostałą ilość czasu, przez jaką gracz będzie jeszcze migotał, dlatego w trakcie trwania każdej pętli musisz skracać ten czas. Gdy licznik odliczający pozostały czas osiągnie 0, migotanie gracza powinno ustać, umożliwiając przerwanie pętli. - Pobierz pozostały czas, przez jaki gracz będzie migotał. W tym celu uzyskaj dostęp do mapy
PlayerVisibilitySeconds
, używając elementuInCharacter.GetAgent[]
jako klucza i zapisując go w zmiennejTimeRemaining
. Właściwie w tym samym wyrażeniu możesz ustawić pozostałą ilość czasu w mapie, zmniejszając wartość oFlickerRateSeconds * 2
. W ten sposóbTimeRemaining
przyjmie wartość zdefiniowaną wPlayerVisibilitySeconds
po rozwiązaniu wyrażeniaset
. Zwróć uwagę na konieczność pomnożeniaFlickerRateSeconds
przez 2 ze względu na dwukrotne wywołanieSleep()
w pętli.# Zmienia widoczność agenta poprzez wielokrotne ukrywanie i pokazywanie jego fort_character FlickerCharacter(InCharacter:fort_character)<suspends>:void= Logger.Print("Wywołano FlickerCharacter()") # Pętla powodująca ukrywanie i pokazywanie postaci w celu uzyskania efektu migotania. loop: InCharacter.Hide() Sleep(FlickerRateSeconds) InCharacter.Show() Sleep(FlickerRateSeconds) # W przypadku każdej pętli skróć czas migotania gracza o FlickerRateSeconds. # Jeśli pozostały czas osiągnie wartość 0, przerwij pętlę. if: TimeRemaining := set PlayerVisibilitySeconds[InCharacter.GetAgent[]] -= FlickerRateSeconds * 2
- Sprawdź, czy wartość
TimeRemaining
jest równa 0 lub mniejsza, co wskazuje, że gracz powinien przestać migotać. W tym celu wywołaj funkcjęHide()
dla postaci, aby ponownie ustawić jej niewidoczność i przerwać pętlę za pomocą wyrażeniabreak
. Otrzymana funkcjaFlickerCharacter()
powinna wyglądać następująco:# Zmienia widoczność agenta poprzez wielokrotne ukrywanie i pokazywanie jego fort_character FlickerCharacter(InCharacter:fort_character)<suspends>:void= Logger.Print("Wywołano FlickerCharacter()") # Pętla powodująca ukrywanie i pokazywanie postaci w celu uzyskania efektu migotania. loop: InCharacter.Hide() Sleep(FlickerRateSeconds) InCharacter.Show() Sleep(FlickerRateSeconds) # W przypadku każdej pętli skróć czas migotania gracza o FlickerRateSeconds. # Jeśli pozostały czas osiągnie wartość 0, przerwij pętlę. if: TimeRemaining := set PlayerVisibilitySeconds[InCharacter.GetAgent[]] -= FlickerRateSeconds * 2 TimeRemaining <= 0.0 then: InCharacter.Hide() break
Uruchamianie i resetowanie migotania
Zastanów się, co ma się zdarzyć, gdy infiltrator odniesie obrażenia już w trakcie migotania. W tym przypadku zespawnowanie kolejnej funkcji FlickerCharacter()
może szybko wymknąć się spod kontroli, ponieważ każda kolejna instancja obrażeń spawnuje kolejną funkcję, co może doprowadzić do wykonywania kilkunastu funkcji równocześnie dla tej samej postaci. Zamiast tego za każdym razem, gdy gracz odnosi obrażenia, jego wartość w PlayerVisibilitySeconds
powinna być zerowana. W tym celu zdefiniujesz funkcję, która będzie sprawdzać, czy gracz migota. Jeśli tak, zresetujesz ilość czasu, przez jaki gracz ma jeszcze migotać. Jeśli nie, zespawnujesz nowe zdarzenie migotania dla danej postaci.
- Dodaj nową funkcję pomocnika
IsFlickering()
do definicji klasyinvisibility_manager
. Posłuży ona do ustalenia, czy gracz migocze. Funkcja ta przyjmuje agenta jako argument i zwraca wartośćtrue
, jeśli jego wartośćPlayerVisibilitySeconds
jest większa od0.0
. Dodaj specyfikatorydecides
oraztransacts
do tej funkcji, aby ustawić jej zawodność oraz umożliwić jej cofnięcie w przypadku niepowodzenia.# Zwraca informację, czy graczowi pozostał czas do końca migotania IsFlickering(InAgent:agent)<decides><transacts>:void= PlayerVisibilitySeconds[InAgent] > 0.0
- Dodaj nową funkcję
StartOrResetFlickering()
do definicji klasyinvisibility_manager
. Funkcja ta przyjmuje agenta jako argument i określa, czy migotanie gracza powinno zostać uruchomione czy zresetowane.# Uruchamia nowe zdarzenie migotania, jeśli agent był niewidoczny, w przeciwnym razie # resetuje trwające migotanie agenta. StartOrResetFlickering(InAgent:agent):void=
- W
StartOrResetFlickering()
sprawdź, czy podany agent nie migocze. Jeśli nie, musisz uruchomić nowe zdarzenie migotania dla tego agenta. Pobierz dla agenta obiektfort_character
i zapisz go w zmiennejFortCharacter
.# Uruchamia nowe zdarzenie migotania, jeśli agent był niewidoczny, w przeciwnym razie # resetuje trwające migotanie agenta. StartOrResetFlickering(InAgent:agent):void= if (not IsFlickering[InAgent], FortCharacter := InAgent.GetFortCharacter[]): Logger.Print("Próbuję uruchomić NOWE zdarzenie FlickerEvent dla tej postaci")
- Ustaw wartość agenta w
PlayerVisibilitySeconds
zgodnie zVulnerableSeconds
, a następnie za pomoc wyrażeniaspawn
zespawnuj nową funkcjęFlickerCharacter()
dla tego agenta, przekazując jego zmiennąFortCharacter
.if (not IsFlickering[InAgent], FortCharacter := InAgent.GetFortCharacter[]): Logger.Print("Próbuję uruchomić NOWE zdarzenie FlickerEvent dla tej postaci") # Uruchomiono nowe migotanie if (set PlayerVisibilitySeconds[InAgent] = VulnerableSeconds): spawn{FlickerCharacter(FortCharacter)} Logger.Print("Zespawnowano FlickerEvent dla tej postaci")
- Jeśli agent już migotał, musisz jedynie zresetować wartość w
PlayerVisibilitySeconds
doVulnerableSeconds
. Pamiętaj, że wcześniejsza funkcjaFlickerCharacter()
będzie odczytywać tę wartość asynchronicznie, zatem jeśli wartość zostanie zresetowana w trakcie odtwarzania pętliFlickerCharacter()
, pętla będzie kontynuowana bez przerywania za pomocą wyrażeniabreak
. Otrzymana funkcjaStartOrResetFlickering()
powinna wyglądać następująco:# Uruchamia nowe zdarzenie migotania, jeśli agent był niewidoczny, w przeciwnym razie # resetuje trwające migotanie agenta. StartOrResetFlickering(InAgent:agent):void= if (not IsFlickering[InAgent], FortCharacter := InAgent.GetFortCharacter[]): Logger.Print("Próbuję uruchomić NOWE zdarzenie FlickerEvent dla tej postaci") # Uruchomiono nowe migotanie if (set PlayerVisibilitySeconds[InAgent] = VulnerableSeconds): spawn{FlickerCharacter(FortCharacter)} Logger.Print("Zespawnowano FlickerEvent dla tej postaci") else: # Zresetuj trwające migotanie if (set PlayerVisibilitySeconds[InAgent] = VulnerableSeconds): Logger.Print("Resetuj wartość FlickerTimer postaci do VulnerableSeconds")
Migotanie infiltratorów w przypadku odniesienia obrażeń
Aby powiązać ze sobą wszystkie te funkcje, zdefiniujesz funkcję, która będzie określała zdarzenia następujące, gdy infiltrator odniesie obrażenia. Podobnie jak w przypadku funkcji FlickerCharacter()
, musisz śledzić każdego infiltratora z osobna, aby ustalić, czy odniósł on obrażenia. Zastosowana do tego funkcja musi być asynchroniczna, aby móc zespawnować taką funkcję dla każdego infiltratora.
- Dodaj nową funkcję
OnInfiltratorDamaged()
do definicji klasyinvisibility_manager
. Ta funkcja pobiera agenta i obsługuje wywołanieStartOrResetFlickering()
, gdy agent odniesie obrażenia. Dodaj specyfikator<suspends>
do tej funkcji, aby umożliwić uruchamianie jej w sposób asynchroniczny.# Powoduje migotanie widoczności agenta za każdym razem, gdy otrzyma on obrażenia OnInfiltratorDamaged(InAgent:agent)<suspends>:void= Logger.Print("Próbuję uruchomić migotanie dla tej postaci")
- Pobierz
fort_team_collection
dla bieżącej przestrzeni gry i zapisz w zmiennejTeamCollection
. Następnie pobierzfort_character
dla agenta przekazanego do tej funkcji.# Powoduje migotanie widoczności agenta za każdym razem, gdy otrzyma on obrażenia OnInfiltratorDamaged(InAgent:agent)<suspends>:void= Logger.Print("Próbuję uruchomić migotanie dla tej postaci") TeamCollection := GetPlayspace().GetTeamCollection() if (FortCharacter := InAgent.GetFortCharacter[]):
- Ta funkcja wymaga ciągłego monitorowania przekazanego do niej agenta, dlatego wymaga użycia pętli. Pętla ta powinna być uruchamiana za każdym razem, gdy dana postać odniesie obrażenia, i wywoływać
StartOrResetFlickering
dla agenta monitorowanego przez funkcję. Dodaj pętlę doOnInfiltratorDamaged
.# Powoduje migotanie widoczności agenta za każdym razem, gdy otrzyma on obrażenia OnInfiltratorDamaged(InAgent:agent)<suspends>:void= Logger.Print("Próbuję uruchomić migotanie dla tej postaci") TeamCollection := GetPlayspace().GetTeamCollection() if (FortCharacter := InAgent.GetFortCharacter[]): loop:
- Wewnątrz pętli sprawdź, czy
IsVisibilityShared
ma wartość true. Jeśli tak, oznacza to, że gdy jeden infiltrator odniesie obrażenia, wszyscy infiltratorzy w drużynie zaczną migotać. Jeśli to ustawienie jest włączone, pobierz drużynę dla danego agenta oraz graczy należących do tej drużyny, wywołując odpowiednioGetTeam[]
iGetAgents[]
.if (FortCharacter := InAgent.GetFortCharacter[]): loop: if(IsVisibilityShared?, CurrentTeam := TeamCollection.GetTeam[InAgent], TeamAgents := TeamCollection.GetAgents[CurrentTeam]):
- Teraz w pętli
for
wywołajStartOrResetFlickering
dla każdego członka drużyny.if(IsVisibilityShared?, CurrentTeam := TeamCollection.GetTeam[InAgent], TeamAgents := TeamCollection.GetAgents[CurrentTeam]): # Dla każdego członka drużyny, ustaw wartość w PlayerVisibility i zespawnuj FlickerEvent for(Teammate:TeamAgents): Logger.Print("Wywoływanie StartOrResetFlickering dla członka drużyny") StartOrResetFlickering(Teammate)
- Jeśli widoczność nie jest współdzielona, wywołaj
StartOrResetFlickering
dla agenta, którego monitoruje ta funkcja.loop: if(IsVisibilityShared?, CurrentTeam := TeamCollection.GetTeam[InAgent], TeamAgents := TeamCollection.GetAgents[CurrentTeam]): # Dla każdego członka drużyny, ustaw wartość w PlayerVisibility i zespawnuj FlickerEvent for(Teammate:TeamAgents): Logger.Print("Wywoływanie StartOrResetFlickering dla członka drużyny") StartOrResetFlickering(Teammate) else: # Włącz tylko migotanie postaci, która odniosła obrażenia Logger.Print("Wywoływanie StartOrResetFlickering dla InAgent") StartOrResetFlickering(InAgent)
- Na końcu pętli zastosuj
Await()
do zdarzeniaDamagedEvent()
danej postaci. Dzięki temu iteracja pętli będzie inicjowana tylko wówczas, gdy postać odniesie obrażenia. Zwróć uwagę, że pętla ta zostanie uruchomiona co najmniej raz, gdy funkcja zostanie zainicjowana, co oznacza co najmniej jedno wywołanieStartOrResetFlickering()
. W związku z tym infiltratorzy rozpoczynają grę od migotania, a następnie stają się niewidoczni. To z jednej strony przypomina infiltratorom, że są niewidoczni, a z drugiej wskazuje, że ich niewidoczność nie jest trwała. Otrzymana funkcjaOnInfiltratorDamaged()
powinna wyglądać następująco:# Powoduje migotanie widoczności agenta za każdym razem, gdy otrzyma on obrażenia OnInfiltratorDamaged(InAgent:agent)<suspends>:void= Logger.Print("Próbuję uruchomić migotanie dla tej postaci") TeamCollection := GetPlayspace().GetTeamCollection() if (FortCharacter := InAgent.GetFortCharacter[]): loop: if(IsVisibilityShared?, CurrentTeam := TeamCollection.GetTeam[InAgent], TeamAgents := TeamCollection.GetAgents[CurrentTeam]): # Dla każdego członka drużyny, ustaw wartość w PlayerVisibility i zespawnuj FlickerEvent for(Teammate:TeamAgents): Logger.Print("Wywoływanie StartOrResetFlickering dla członka drużyny") StartOrResetFlickering(Teammate) else: # Włącz tylko migotanie postaci, która odniosła obrażenia Logger.Print("Wywoływanie StartOrResetFlickering dla InAgent") StartOrResetFlickering(InAgent) FortCharacter.DamagedEvent().Await()
Spawnowanie funkcji dla postaci na początku gry
Wróć do StartInvisibilityManager()
i przed wywołaniem Hide()
dla postaci gracza zespawnuj funkcję OnInfiltratorDamaged()
dla tej postaci. Dzięki temu każdy infiltrator ma funkcję, która monitoruje go w sposób asynchroniczny i obsługuje całą logikę związaną z jego migotaniem. Funkcja StartInvisibilityManager()
powinna wyglądać następująco:
StartInvisibilityManager<public>(AllTeams:[]team, AllPlayers:[]player, Infiltrators:team):void=
Logger.Print("Uruchomiono skrypt niewidzialności!")
set Teams = GetPlayspace().GetTeamCollection().GetTeams()
for(PlayerSpawner:PlayersSpawners):
PlayerSpawner.SpawnedEvent.Subscribe(OnPlayerSpawn)
# W przypadku każdego gracza, sprawdź, czy został zespawnowany w drużynie infiltratorów, a jeśli tak, zespawnuj
# dla niego funkcję OnInfiltratorDamaged. Następnie spraw, aby jego postać była niewidoczna.
for (TeamPlayer:AllPlayers):
if:
FortCharacter:fort_character = TeamPlayer.GetFortCharacter[]
CurrentTeam := GetPlayspace().GetTeamCollection().GetTeam[TeamPlayer]
Logger.Print("Pobrano bieżącą drużynę tego gracza")
Teams[0] = CurrentTeam
set PlayerVisibilitySeconds[TeamPlayer] = 0.0
Logger.Print("Dodano gracza do PlayerVisibilitySeconds")
then:
spawn{OnInfiltratorDamaged(TeamPlayer)}
Logger.Print("Gracz został zespawnowany jako infiltrator, ustawiam niewidoczność gracza")
FortCharacter.Hide()
else:
Logger.Print("Ten gracz nie jest infiltratorem")
Zapisz skrypt, skompiluj go, a następnie na pasku narzędzi UEFN kliknij opcję Uruchom sesję, aby przetestować poziom w grze. W trakcie testowania poziomu w grze każdy infiltrator powinien migotać w momencie uruchomienia skryptu, a następnie stać się niewidoczny. Po odniesieniu obrażeń infiltratorzy powinni zacząć migotać, każdy z osobna lub jako drużyna, w zależności od ustawienia IsVisibilityShared
.

Następny krok
W następnym kroku tego samouczka nauczysz się postępowania z graczami dołączającymi do gry w trakcie jej trwania.