Para conseguir el efecto visual de parpadeo en los infiltrados, vas a ocultar y mostrar repetidamente el personaje de cada jugador. Quieres que esto ocurra en una función cada vez que se daña a un Infiltrado, pero también necesitas asegurarte de que el resto de tu código siga ejecutándose cuando se llama a esta función. Esto se complica aún más en situaciones en las que tienes varios Infiltrados. Puede haber varios infiltrados dañados al mismo tiempo durante una partida, por lo que necesitarás un código que pueda controlar a cada uno de ellos de forma individual.
Para conseguirlo, vas a utilizar mucho la expresión generar. Generar una función te permite ejecutarla de forma asíncrona, sin poner en espera el resto del código. Al generar una función para cada infiltrado, puedes asegurarte de que el parpadeo de cada uno ocurra independientemente del resto.
Sigue estos pasos para aprender a hacer parpadear a los personajes infiltrados cuando reciben daño.
Cómo crear el bucle de parpadeo
- Añade una nueva función
FlickerCharacter()a la definición de la claseinvisibility_manager. Esta función toma a unfort_charactery hace que su personaje parpadee para que aparezca y desaparezca. Añade el especificador<suspends>a esta función para permitirle que se ejecute de forma asíncrona.# Hace que parpadee la visibilidad de un agente ocultando y mostrando de manera repetida a su fort_character. FlickerCharacter(InCharacter:fort_character)<suspends>:void= Logger.Print("FlickerCharacter() invoked") - En
FlickerCharacter(), haz un bucle deHide()enInCharacter,Sleep()por un tiempo determinado (losFlickerRateSecondsque estableciste antes),Show()el personaje y descansa otra vez. Esto creará un efecto de parpadeo en el personaje que le permitirá a los jugadores enemigos rastrearlo, aunque se les dificultará apuntarle debido a los breves periodos de invisibilidad.# Hace que parpadee la visibilidad de un agente ocultando y mostrando de manera repetida a su fort_character. FlickerCharacter(InCharacter:fort_character)<suspends>:void= Logger.Print("FlickerCharacter() invoked") # Cómo hacer un bucle de ocultar y mostrar el personaje para crear un efecto de parpadeo. loop: InCharacter.Hide() Sleep(FlickerRateSeconds) InCharacter.Show() Sleep(FlickerRateSeconds)Cómo interrumpir el bucle
Necesitas una manera de interrumpir este bucle cuando el personaje debe dejar de parpadear. La asignación de
PlayerVisibilitySecondsque configuraste antes registra la cantidad de tiempo que le queda a un jugador para parpadear, así que tendrás que disminuir ese tiempo durante cada bucle. Cuando el tiempo restante llegue a 0, el jugador dejará de parpadear y podrás interrumpir el bucle. - Obtén la cantidad de tiempo que le queda de parpadeo a un jugador mediante el acceso al mapa
PlayerVisibilitySecondscon la claveInCharacter.GetAgent[]y su almacenamiento en una variableTimeRemaining. En realidad se puede establecer la cantidad de tiempo restante en el mapa de la misma expresión al disminuir el valor enFlickerRateSeconds * 2. De esta forma,TimeRemainingse convertirá en el valor dePlayerVisibilitySecondsdespués de que se resuelva la expresiónset. Ten en cuenta queFlickerRateSecondstiene que multiplicarse por 2, ya que llamas aSleep()dos veces por bucle.# Hace que parpadee la visibilidad de un agente ocultando y mostrando de manera repetida a su fort_character. FlickerCharacter(InCharacter:fort_character)<suspends>:void= Logger.Print("FlickerCharacter() invoked") # Cómo hacer un bucle de ocultar y mostrar el personaje para crear un efecto de parpadeo. loop: InCharacter.Hide() Sleep(FlickerRateSeconds) InCharacter.Show() Sleep(FlickerRateSeconds) # En cada bucle, disminuye la cantidad de tiempo que el personaje parpadea en FlickerRateSeconds. # Si el tiempo restante llega a 0, interrumpe el bucle. if: TimeRemaining := set PlayerVisibilitySeconds[InCharacter.GetAgent[]] -= FlickerRateSeconds * 2 - Comprueba si
TimeRemaininges menor o igual que 0, lo que indica que el personaje debe dejar de parpadear. Para hacer esto, llama aHide()en el personaje para hacerlo invisible de nuevo ybreakel bucle. Tu funciónFlickerCharacter()debe verse de la siguiente manera:# Hace que parpadee la visibilidad de un agente ocultando y mostrando de manera repetida a su fort_character. FlickerCharacter(InCharacter:fort_character)<suspends>:void= Logger.Print("FlickerCharacter() invoked") # Cómo hacer un bucle de ocultar y mostrar el personaje para crear un efecto de parpadeo. loop: InCharacter.Hide() Sleep(FlickerRateSeconds) InCharacter.Show() Sleep(FlickerRateSeconds) # En cada bucle, disminuye la cantidad de tiempo que el personaje parpadea en FlickerRateSeconds. # Si el tiempo restante llega a 0, interrumpe el bucle. if: TimeRemaining := set PlayerVisibilitySeconds[InCharacter.GetAgent[]] -= FlickerRateSeconds * 2 TimeRemaining <= 0.0 then: InCharacter.Hide() break
Cómo iniciar y reiniciar el parpadeo
Considera lo que ocurre cuando un Infiltrado recibe daño mientras parpadea. En este caso, la generación de otra función FlickerCharacter() podría descontrolarse, ya que cada instancia posterior de daño genera otra función, y podrías terminar con docenas de funciones actuando sobre el mismo personaje. En cambio, el valor del jugador en PlayerVisibilitySeconds debe restablecerse cada vez que recibe daño. Para ello, definirás una función que compruebe si un jugador parpadea. Si lo hace, restablece la cantidad de tiempo que deben parpadear. Si no lo hace, genera un nuevo evento de parpadeo para ese personaje.
- Agrega una nueva función de ayuda
IsFlickering()a la definición de la claseinvisibility_manager, que usarás para determinar si un jugador está parpadeando. Esta función toma un agente como argumento y devuelvetruesi su valor enPlayerVisibilitySecondses mayor que0.0. Añade los especificadoresdecidesytransactsa esta función tanto para hacerla falible como para permitir su reversión en caso de fallo.# Indica si al jugador le queda algo de tiempo para parpadear. IsFlickering(InAgent:agent)<decides><transacts>:void= PlayerVisibilitySeconds[InAgent] > 0.0 - Añade una nueva función
StartOrResetFlickering()a la definición de la claseinvisibility_manager. Esta función toma un agente como argumento y determina si un jugador debe comenzar y reiniciar el parpadeo.# Inicia un nuevo evento de parpado si el agente estaba invisible, de lo contrario, # restablece el parpadeo en curso del agente. StartOrResetFlickering(InAgent:agent):void= - En
StartOrResetFlickering(), comprueba si el agente dado no parpadea. Si no lo hace, debes iniciar un nuevo evento de parpadeo para este agente. RecuperaFortCharacterpara ese agente y guárdalo en una variableFortCharacter.# Inicia un nuevo evento de parpado si el agente estaba invisible, de lo contrario, # restablece el parpadeo en curso del agente. StartOrResetFlickering(InAgent:agent):void= if (not IsFlickering[InAgent], FortCharacter := InAgent.GetFortCharacter[]): Logger.Print("Attempting to start NEW FlickerEvent for this character") - Establece el valor del agente en
PlayerVisibilitySecondsaVulnerableSeconds; luego,spawnuna nueva funciónFlickerCharacter()para este agente, pasando suFortCharacter.if (not IsFlickering[InAgent], FortCharacter := InAgent.GetFortCharacter[]): Logger.Print("Attempting to start NEW FlickerEvent for this character") # Comenzó un nuevo parpadeo if (set PlayerVisibilitySeconds[InAgent] = VulnerableSeconds): spawn{FlickerCharacter(FortCharacter)} Logger.Print("Spawned a FlickerEvent for this character") - Si el agente ya parpadeaba, solo tienes que restablecer su valor en
PlayerVisibilitySecondsaVulnerableSeconds. Recuerda que, en la función anteriorFlickerCharacter(), se leerá este valor de forma asíncrona, por lo que si el valor se restablece mientrasFlickerCharacter()está en bucle, continuará el bucle sinbreak. Tu funciónStartOrResetFlickering()debe verse de la siguiente manera:# Inicia un nuevo evento de parpado si el agente estaba invisible, de lo contrario, # restablece el parpadeo en curso del agente. StartOrResetFlickering(InAgent:agent):void= if (not IsFlickering[InAgent], FortCharacter := InAgent.GetFortCharacter[]): Logger.Print("Attempting to start NEW FlickerEvent for this character") # Comenzó un nuevo parpadeo if (set PlayerVisibilitySeconds[InAgent] = VulnerableSeconds): spawn{FlickerCharacter(FortCharacter)} Logger.Print("Spawned a FlickerEvent for this character") else: # Cómo reiniciar el parpadeo en curso if (set PlayerVisibilitySeconds[InAgent] = VulnerableSeconds): Logger.Print("Reset character's FlickerTimer to VulnerableSeconds")
Cómo hacer parpadear a los infiltrados cuando se los daña
Para unir todas estas funciones, definirás una función que controle lo que sucede cuando se daña a un infiltrado. Al igual que con FlickerCharacter(), necesitas rastrear cada Infiltrado de forma individual para determinar si recibieron un daño. Es necesario que esta función sea asíncrona para que puedas generar uno por cada Infiltrado.
- Añade una nueva función
OnInfiltratorDamaged()a la definición de la claseinvisibility_manager. Esta función toma un agente y se encarga de llamar aStartOrResetFlickering()cuando se daña al agente. Añade el especificador<suspends>a esta función para permitirle que se ejecute de forma asíncrona.# Hace parpadear la visibilidad de un agente cada vez que este recibe daño. OnInfiltratorDamaged(InAgent:agent)<suspends>:void= Logger.Print("Attempting to start flickering this character") - Obtén la
fort_team_collectiondel espacio de juego actual y guárdala en una variableTeamCollection. Luego, obtén elfort_characterpara el agente pasado a esta función`.# Hace parpadear la visibilidad de un agente cada vez que este recibe daño. OnInfiltratorDamaged(InAgent:agent)<suspends>:void= Logger.Print("Attempting to start flickering this character") TeamCollection := GetPlayspace().GetTeamCollection() if (FortCharacter := InAgent.GetFortCharacter[]): - Como esta función necesita monitorizar de forma continua el agente que se le pasa, necesita hacer un bucle. Este bucle debe ejecutarse cada vez que se daña al personaje dado y llama a
StartOrResetFlickeringen el agente que la función monitoriza. Añade un bucle aOnInfiltratorDamaged.# Hace parpadear la visibilidad de un agente cada vez que este recibe daño. OnInfiltratorDamaged(InAgent:agent)<suspends>:void= Logger.Print("Attempting to start flickering this character") TeamCollection := GetPlayspace().GetTeamCollection() if (FortCharacter := InAgent.GetFortCharacter[]): loop: - Dentro del bucle, comprueba si
IsVisibilitySharedes verdadero. Si es así, significa que cuando se daña a un infiltrado, todos los infiltrados del equipo deberían empezar a parpadear. Si esta opción está activada, obtén al equipo de este agente y a los jugadores de ese equipo a través de las llamadas aGetTeam[]yGetAgents[]respectivamente.if (FortCharacter := InAgent.GetFortCharacter[]): loop: if(IsVisibilityShared?, CurrentTeam := TeamCollection.GetTeam[InAgent], TeamAgents := TeamCollection.GetAgents[CurrentTeam]): - Ahora en un bucle
for, llama aStartOrResetFlickeringpara cada compañero de equipo.if(IsVisibilityShared?, CurrentTeam := TeamCollection.GetTeam[InAgent], TeamAgents := TeamCollection.GetAgents[CurrentTeam]): # Configura los segundos de PlayerVisibility de cada compañero de equipo y genera un FlickerEvent for(Teammate:TeamAgents): Logger.Print("Calling StartOrResetFlickering on a Teammate") StartOrResetFlickering(Teammate) - Si la visibilidad no se comparte, llama a
StartOrResetFlickeringen el agente que esta función monitoriza.loop: if(IsVisibilityShared?, CurrentTeam := TeamCollection.GetTeam[InAgent], TeamAgents := TeamCollection.GetAgents[CurrentTeam]): # Configura los segundos de PlayerVisibility de cada compañero de equipo y genera un FlickerEvent for(Teammate:TeamAgents): Logger.Print("Calling StartOrResetFlickering on a Teammate") StartOrResetFlickering(Teammate) else: # Cómo lograr que solo parpadee el personaje dañado Logger.Print("Calling StartOrResetFlickering on InAgent") StartOrResetFlickering(InAgent) - Por último, al final del bucle,
Await()elDamagedEvent()del personaje dado. De esta forma el bucle solo iterará cuando un personaje esté dañado. Ten en cuenta que este bucle se ejecutará al menos una vez cuando se inicie la función, lo que implica al menos una llamada aStartOrResetFlickering(). Por esto, al comenzar el juego, los infiltrados parpadean y, luego, se vuelven invisibles. Esto ayuda a los infiltrados a recordar que son invisibles, pero también que la invisibilidad no es permanente. Tu funciónOnInfiltratorDamaged()debe verse de la siguiente manera:# Hace parpadear la visibilidad de un agente cada vez que este recibe daño. OnInfiltratorDamaged(InAgent:agent)<suspends>:void= Logger.Print("Attempting to start flickering this character") TeamCollection := GetPlayspace().GetTeamCollection() if (FortCharacter := InAgent.GetFortCharacter[]): loop: if(IsVisibilityShared?, CurrentTeam := TeamCollection.GetTeam[InAgent], TeamAgents := TeamCollection.GetAgents[CurrentTeam]): # Configura los segundos de PlayerVisibility de cada compañero de equipo y genera un FlickerEvent for(Teammate:TeamAgents): Logger.Print("Calling StartOrResetFlickering on a Teammate") StartOrResetFlickering(Teammate) else: # Cómo lograr que solo parpadee el personaje dañado Logger.Print("Calling StartOrResetFlickering on InAgent") StartOrResetFlickering(InAgent) FortCharacter.DamagedEvent().Await()
Funciones de aparición de personajes al inicio de la partida
En StartInvisibilityManager(), antes de llamar a Hide() en el personaje de un jugador, genera una función OnInfiltratorDamaged() para ese personaje. De esta forma, cada infiltrado tiene una función que lo monitorea de forma asíncrona y controla toda la lógica relacionada con su parpadeo. La función StartInvisibilityManager() debería verse de la siguiente manera:
StartInvisibilityManager<public>(AllTeams:[]team, AllPlayers:[]player, Infiltrators:team):void=
Logger.Print("Invisibility script started!")
set Teams = GetPlayspace().GetTeamCollection().GetTeams()
for(PlayerSpawner:PlayersSpawners):
PlayerSpawner.SpawnedEvent.Subscribe(OnPlayerSpawn)
# Para cada jugador, si apareció en el equipo de infiltrados, crea una función OnInfiltratorDamaged para ese
# jugador. A continuación, hace invisible a su personaje.
for (TeamPlayer:AllPlayers):
if:
FortCharacter:fort_character = TeamPlayer.GetFortCharacter[]
CurrentTeam := GetPlayspace().GetTeamCollection().GetTeam[TeamPlayer]
Logger.Print("Got this player's current team")
Teams[0] = CurrentTeam
set PlayerVisibilitySeconds[TeamPlayer] = 0.0
Logger.Print("Added player to PlayerVisibilitySeconds")
then:
spawn{OnInfiltratorDamaged(TeamPlayer)}
Logger.Print("Jugador generado como infiltrado, por lo que se ha hecho invisible.")
FortCharacter.Hide()
else:
Logger.Print("This player isn't an infiltrator")
Guarda la secuencia de comandos, compílala y haz clic en Comenzar sesión en la barra de herramientas de UEFN para probar el nivel. Cuando pruebes tu nivel, cada Infiltrado debería parpadear cuando se inicie la secuencia de comandos, y luego volverse invisible. Al recibir daño, deberían parpadear, ya sea individualmente o en equipo, en función de lo que establezcas en IsVisibilityShared.

Próximo paso
En el próximo paso de este tutorial, aprenderás a manejar a los jugadores que se unen a la partida en curso.