La invisibilidad del infiltrado crea un problema interesante a la hora de hacerse con el objetivo del defensor. ¿Cómo van a encontrar los defensores a un jugador invisible que podría estar esprintando de vuelta a la base con su objetivo? Para resolver este problema, puedes utilizar una ayuda visual, en este caso un elemento, para mostrar a los defensores dónde está el infiltrado.
Sigue los pasos que se indican a continuación para aprender a crear un objeto que flote sobre la cabeza de un jugador cuando lleve un objetivo consigo.
Cómo crear el Gestor de captura de objetos
- Crea un nuevo dispositivo de Verse llamado item_capture_manager desde el explorador de Verse y arrastra el dispositivo al nivel.
- En la parte superior del archivo
item_capture_manager:- Añade
using { /UnrealEngine.com/Temporary/SpatialMath }para acceder a la estructuravector3. Lo utilizarás para saber dónde teletransportar los indicadores que flotan sobre la cabeza de un jugador. Añade tambiénusing { /Fortnite.com/Characters }para acceder a la funciónfort_characterdel jugador.using { /Fortnite.com/Devices } using { /Verse.org/Simulation } using { /Fortnite.com/Characters } using { /UnrealEngine.com/Temporary/Diagnostics } using { /UnrealEngine.com/Temporary/SpatialMath }
- Añade
- En la definición de la clase
item_capture_manager, añade los siguientes campos:- Una matriz editable de dispositivos Generador de objetos de captura llamada
CaptureItemSpawners. Esta matriz contiene el dispositivo Generador de objetos de captura para los infiltrados.item_capture_manager := class(creative_device): Logger:log = log{Channel := triad_item_capture_log_channel} # Captura el generador de objetos que genera el objeto a capturar. @editable CaptureItemSpawner:capture_item_spawner_device = capture_item_spawner_device{} - Un elemento creativo editable llamado
CaptureItemIndicator. Este es el elemento que flotará sobre la cabeza de un infiltrado cuando consiga el objetivo.# Captura el generador de objetos que genera el objeto a capturar. @editable CaptureItemSpawner:capture_item_spawner_device = capture_item_spawner_device{} # Elemento que flota sobre la cabeza de un jugador cuando lleva un objeto consigo del # CaptureItemSpawner. @editable CaptureItemIndicator:creative_prop = creative_prop{} - Un dispositivo indicador del mapa editable llamado
MapIndicator. Se situará bajo el CaptureItemSpawner del nivel y mostrará en el mapa dónde están los objetivos de cada equipo.# Elemento que flota sobre la cabeza de un jugador cuando lleva un objeto consigo del # CaptureItemSpawner. @editable CaptureItemIndicator:creative_prop = creative_prop{} # Indicador que muestra en el mapa dónde están los objetivos de cada equipo. @editable MapIndicator:map_indicator_device = map_indicator_device{} - Hay dos float editables:
UpdateRateSecondsyVerticalOffset. El primero controla la rapidez con que cambia la posición deCaptureItemIndicator, y el segundo controla la distancia a la que flotaCaptureItemIndicatorpor encima de la cabeza del jugador.# Indicador que muestra en el mapa dónde están los objetivos de cada equipo. @editable MapIndicator:map_indicator_device = map_indicator_device{} # Frecuencia con la que el CaptureItemIndicator actualiza su posición. @editable UpdateRateSeconds:float = 0.15 # Indica a qué altura sobre la cabeza del jugador flota el CaptureItemIndicator. @editable VerticalOffset:float = 180.0 - Un dispositivo de mensaje del HUD editable llamado
ItemGrabbedMessageDevice. Esto envía un mensaje a cada jugador cuando se recoge un objetivo.# Indica a qué altura sobre la cabeza del jugador flota el CaptureItemIndicator. @editable VerticalOffset:float = 180.0 # Muestra un mensaje cuando un jugador consigue el objeto de captura. @editable ItemGrabbedMessageDevice:hud_message_device = hud_message_device{} - Un dispositivo gestor de puntuación editable llamado
ScoreManagerDevice. Esto otorga puntuación a un equipo cada vez que un jugador captura el objetivo.# Muestra un mensaje cuando un jugador consigue el objeto de captura. @editable ItemGrabbedMessageDevice:hud_message_device = hud_message_device{} # Otorga puntuación cuando un jugador captura el objeto de captura. @editable ScoreManagerDevice:score_manager_device = score_manager_device{} - Un float editable llamado
ReturnTime. Si el objeto de captura tiene un tiempo de retorno antes de volver al CaptureItemSpawner, debes rastrear la duración de ese tiempo de retorno para saber cuándo devolver los indicadores de nuevo al CaptureItemSpawner.
- Una matriz editable de dispositivos Generador de objetos de captura llamada
- Añade un nuevo método
FollowCharacter()a la definición de la claseitem_capture_manager. Este método toma unfort_charactery lo rastrea usando los indicadores sobre su cabeza. Añade el especificador<suspends>a esta función, ya que quieres que aparezca uno de estos para un jugador siempre que lleve un objetivo.# Hace que el CaptureItemIndicator siga continuamente a un jugador por encima de su cabeza. # Compite entre el bucle de actualización del CaptureItemIndictator, y si el jugador # captura el objeto, lo suelta o es eliminado. FollowCharacter(FortCharacter:fort_character)<suspends>:void= Logger.Print("Se ha generado la función FollowCharacter")
Cómo correr una carrera llevando el objetivo
Es importante pensar en qué ocurre cuando un jugador consigue el objetivo. El jugador puede:
- Desplazarse, en cuyo caso tus indicadores CaptureItem y Map deben actualizarse continuamente según la posición del jugador. Esto puede hacerse con un bucle.
- Capturar el objetivo, en cuyo caso tus indicadores deben volver al CaptureItemSpanwer en algún lugar oculto ya que no deberían ser visibles a menos que un jugador lleve consigo el objeto de captura.
- Soltar el objetivo o ser eliminado, en cuyo caso los indicadores deben permanecer donde se soltó el objeto y volver al CaptureItemSpawner cuando el objeto de captura regrese.
Para conseguirlo, vas a configurar una expresión race. Utilizando una expresión race entre las tres condiciones anteriores, puedes seguir actualizando la posición de los indicadores mientras esperas a que el jugador suelte o capture el objetivo.
- Añade una expresión
raceaFollowCharacter(). Configura la carrera para que se ejecute entre unloop, unAwait()para elItemCapturedEventdelCaptureItemSpawner, unAwait()para elItemCapturedDroppedEventdelCaptureItemSpawnery unAwait()para elEliminatedEvent()delFortCharacter.FollowCharacter(FortCharacter:fort_character)<suspends>:void= Logger.Print("Se ha generado la función FollowCharacter") race: loop: CaptureItemSpawner.ItemCapturedEvent.Await() CaptureItemSpawner.ItemDroppedEvent.Await() FortCharacter.EliminatedEvent().Await() - En el
loop, obtén la posición deFortCharactery guárdala en una variableTransform.loop: Transform := FortCharacter.GetTransform() - Ahora genera un
MoveTo()para mover tanto elCaptureItemIndicatorcomo elMapIndicatora la traslación y rotación de laTransformmás laVerticalOffsetque ya has establecido durante un periodo de tiempoUpdateRateSeconds. Debes ejecutarSpawn{}en ambas funcionesMoveTo()porque tanto elCaptureItemIndicatorcomo elMapIndicatorhan de moverse exactamente al mismo tiempo, en lugar de esperar a que la expresión del otro se complete. Como la traslación es unvector3formado por coordenadasX,YyZ, tendrás que poner elVerticalOffsetdentro de un nuevovector3. Como elVerticalOffsetes la distancia vertical por encima de la cabeza del jugador, establécelo como el valorZdelvector3.loop: Transform := FortCharacter.GetTransform() spawn{CaptureItemIndicator.MoveTo(Transform.Translation + vector3{Z := VerticalOffset}, Transform.Rotation, UpdateRateSeconds)} spawn{MapIndicator.MoveTo(Transform.Translation + vector3{Z := VerticalOffset}, Transform.Rotation, UpdateRateSeconds)} - Finalmente, haz que el código ejecute Sleep durante
0.0segundos. Esto asegura que el bucle se ejecute solo una vez por actualización de simulación y no se descontrole al generar funcionesMoveTo(). Tu códigoFollowCharacter()debería tener el siguiente aspecto:# Hace que el CaptureItemIndicator siga continuamente a un jugador por encima de su cabeza. # Compite entre el bucle de actualización del CaptureItemIndictator, y si el jugador # captura el objeto, lo suelta o es eliminado. FollowCharacter(FortCharacter:fort_character)<suspends>:void= Logger.Print("Se ha generado la función FollowCharacter") race: loop: Transform := FortCharacter.GetTransform() spawn{CaptureItemIndicator.MoveTo(Transform.Translation + vector3{Z := VerticalOffset}, Transform.Rotation, UpdateRateSeconds)} spawn{MapIndicator.MoveTo(Transform.Translation + vector3{Z := VerticalOffset}, Transform.Rotation, UpdateRateSeconds)} # Debemos asegurarnos de que este bucle se ejecuta solo una vez por cada actualización de la simulación, así que permanecemos inactivos durante un tic de juego. Sleep(0.0) CaptureItemSpawner.ItemCapturedEvent.Await() CaptureItemSpawner.ItemDroppedEvent.Await() FortCharacter.EliminatedEvent().Await() Logger.Print("Objetivo soltado o capturado")Cómo restablecer los indicadores
- Cuando el objeto de captura se captura o devuelve, tienes que devolver los indicadores al
CaptureItemSpawneren algún lugar oculto. En este caso, lo teletransportarás muy por encima delCaptureItemSpawner. Para ello, añade una función llamadaReturnIndicators()a la definición de la claseitem_capture_manager.# Devuelve los indicadores del mapa y del objeto de captura a sus posiciones iniciales sobre los generadores. ReturnIndicators(InAgent:agent):void= - Obtén la transformación del
CaptureItemSpawnery guárdala en una variableSpawnerTransform. A continuación, genera unMoveTo()para elCaptureItemIndicatory elMapIndicatorcon la transformación y rotación delCaptureItemSpawner. Para ello, añade laVerticalOffsetde la misma manera que hiciste en ellooppara ponerlos por encima delCaptuerItemSpawnwer. Si quieres que tu elemento quede oculto, puedes multiplicarVerticalOffsetpor un número grande, en este caso 10. Tu métodoReturnIndicators()completo debería tener el siguiente aspecto:# Devuelve los indicadores del mapa y del objeto de captura a sus posiciones iniciales sobre los generadores. ReturnIndicators():void= SpawnerTransform := CaptureItemSpawner.GetTransform() # Teletransporta de vuelta al generador y oculta el CaptureItemIndicator y el MapIndicator por encima del mapa. spawn{CaptureItemIndicator.MoveTo(SpawnerTransform.Translation + vector3{Z := VerticalOffset * 10.0}, SpawnerTransform.Rotation, UpdateRateSeconds)} spawn{MapIndicator.MoveTo(SpawnerTransform.Translation + vector3{Z := VerticalOffset * 10.0}, SpawnerTransform.Rotation, UpdateRateSeconds)} Logger.Print("Indicadores devueltos para capturar el generador.")
Cómo gestionar a los jugadores que consiguen, sueltan y capturan el objetivo
- Añade un nuevo método
OnItemPickedUp()a la definición de la claseitem_capture_manager. Este método toma unagenty genera una instancia deFollowCharacter()para ese personaje.# Avisa a cada jugador cuando un jugador consigue el objetivo. OnItemPickedUp(InAgent:agent):void= Logger.Print("Objetivo conseguido") - Obtén el
FortCharacterparaInAgenty crea una funciónFollowCharacter()utilizando eseFortCharacter. Tu métodoOnItemPickedUp()completo debería tener el siguiente aspecto:# Avisa a cada jugador cuando un jugador consigue el objetivo. OnItemPickedUp(InAgent:agent):void= Logger.Print("Objetivo conseguido") if(FortCharacter := InAgent.GetFortCharacter[]): ItemGrabbedMessageDevice.Show() spawn{FollowCharacter(FortCharacter)} - Añade un nuevo método
OnItemCaptured()a la definición de la claseitem_capture_manager. Este método toma elagentque ha capturado el objetivo.# Cuando se captura el objeto, otorga puntuación al equipo de captura y devuelve los indicadores. OnItemCaptured(CapturingAgent:agent):void= Logger.Print("Objetivo capturado") - En
OnItemCaptured(), activa elScoreManagerDevicepara otorgar la puntuación del equipo del jugador que captura, y llama aReturnIndicators()para devolver los indicadores.# Cuando se captura el objeto, otorga puntuación al equipo de captura y devuelve los indicadores. OnItemCaptured(CapturingAgent:agent):void= Logger.Print("Objetivo capturado") ScoreManagerDevice.Activate() ReturnIndicators() - Añade un nuevo método
OnItemDropped()a la definición de la claseitem_capture_manager. Este método toma elagentque ha soltado el objeto.# Cuando un jugador suelta un objeto, genera una función WaitForReturn() # si el ReturnTime es mayor que 0. OnItemDropped(InAgent:agent):void= Logger.Print("Objetivo soltado") - Cuando se suelta el objetivo, los indicadores deben permanecer cerca del objetivo hasta que este se recoja o vuelva al
CaptureItemSpawner. Para saber cuándo devolver los indicadores, utilizarás la variableReturnTimeque ya has configurado. SiReturnTimees mayor o igual a0.0, debes esperar esa cantidad de tiempo y luego devolver los indicadores. SiReturnTimees negativo, el objetivo no tiene tiempo de retorno, por lo que no tienes que mover los indicadores. Para deshacer el movimiento de los indicadores, genera una nueva función auxiliar llamadaWaitForReturn(), que definirás en el siguiente paso.# Cuando un jugador suelta un objeto, genera una función WaitForReturn() # si el ReturnTime es mayor que 0. OnItemDropped(InAgent:agent):void= Logger.Print("Objetivo soltado") if(ReturnTime >= 0.0): spawn{WaitForReturn()} else: Logger.Print("El objetivo soltado no se devuelve.") - Añade un nuevo método
WaitForReturn()a la definición de la claseitem_capture_manager. Esta función espera una cantidad de tiempoReturnTimey, a continuación, lleva a cabo la devolución si el objetivo no se recogió antes de que la espera se completara. Añade el modificador<suspends>a este método para permitir que se ejecuteSleep().# Espera una cantidad de tiempo ReturnTime y, a continuación, devuelve los indicadores. WaitForReturn()<suspends>:void= Logger.Print("Esperando a que se devuelvan los indicadores…") - La necesidad o no de devolver los indicadores depende de si el objetivo se recogió antes de que termine
ReturnTime. Si asi fue, no devuelvas los indicadores ya que volverían inmediatamente de nuevo al jugador, y esto podría causar efectos visuales extraños. Para solucionarlo utilizarás una variable lógica cuyo valor es igual al resultado de una carrera.# Espera una cantidad de tiempo ReturnTime y, a continuación, devuelve los indicadores. WaitForReturn()<suspends>:void= Logger.Print("Esperando a que se devuelvan los indicadores…") # Devuelve los indicadores CaptureItem y Map si el objeto de captura # no se recoge antes de que acabe el tiempo. ShouldReturn:logic := race: - Tu función
WaitForReturn()debe competir entre dos condiciones. ElReturnTimese agota y el objetivo vuelve alCaptureItemSpawner, en cuyo caso debe devolver los indicadores yShouldReturndebe sertrue. O el objetivo se recoge antes de que se agote elReturnTime, en cuyo casoShouldReturndebe serfalse. Dado que cada una de estas condiciones devuelve un valor, ejecutarás la carrera mediante dosblocksindependientes.ShouldReturn:logic := race: block: block: - En el primer bloque, se llama a
Sleep()durante una cantidad de tiempoReturnTimey, a continuación, se devuelvetrue. En el segundo bloque, se ejecutaAwait()para elCaptureItemSpawner.ItemPickedUpEventy, a continuación, se devuelve false. La variableShouldReturnse inicializará para lo que se complete primero.ShouldReturn:logic := race: block: Sleep(ReturnTime) true block: CaptureItemSpawner.ItemPickedUpEvent.Await() false - Si
ShouldReturnes true, hay que devolver los indicadores. Llama aReturnIndicators()siShouldReturnse evalúa comotrue. Tu códigoWaitForReturn()completo debería tener el siguiente aspecto:# Espera una cantidad de tiempo ReturnTime y, a continuación, devuelve los indicadores. WaitForReturn()<suspends>:void= Logger.Print("Esperando a que se devuelvan los indicadores…") # Devuelve los indicadores CaptureItem y Map si el objeto de captura # no se recoge antes de que acabe el tiempo. ShouldReturn:logic := race: block: Sleep(ReturnTime) true block: CaptureItemSpawner.ItemPickedUpEvent.Await() false if(ShouldReturn?): ReturnIndicators() - Ahora en
OnBegin(), suscribe elItemPickedUpEventdelCaptureItemSpawneraOnItemPickedUp(), elItemCapturedEventaOnItemCaptured(), y elItemDroppedEventaOnItemDropped().OnBegin<override>()<suspends>:void= CaptureItemSpawner.ItemPickedUpEvent.Subscribe(OnItemPickedUp) CaptureItemSpawner.ItemCapturedEvent.Subscribe(OnItemCaptured) CaptureItemSpawner.ItemDroppedEvent.Subscribe(OnItemDropped) SpawnerTransform := CaptureItemSpawner.GetTransform() - Por último, en
OnBegin(), coloca los indicadores en sus posiciones iniciales cuando se ejecute la secuencia de comandos llamando aMoveTo() en elCaptureItemIndicatoryMapIndicator. Tu códigoOnBegin()` debería tener el siguiente aspecto:OnBegin<override>()<suspends>:void= CaptureItemSpawner.ItemPickedUpEvent.Subscribe(OnItemPickedUp) CaptureItemSpawner.ItemCapturedEvent.Subscribe(OnItemCaptured) CaptureItemSpawner.ItemDroppedEvent.Subscribe(OnItemDropped) SpawnerTransform := CaptureItemSpawner.GetTransform() # Teletransporta de vuelta al generador y oculta el CaptureItemIndicator debajo del mapa. CaptureItemIndicator.MoveTo(SpawnerTransform.Translation + vector3{Z := VerticalOffset * 10.0}, SpawnerTransform.Rotation, UpdateRateSeconds) MapIndicator.MoveTo(SpawnerTransform.Translation + vector3{Z := VerticalOffset * 10.0}, SpawnerTransform.Rotation, UpdateRateSeconds) -
De nuevo en el editor, guarda la secuencia de comandos, compílala y arrastra el dispositivo al nivel. Elige un elemento apropiado que quieras que sirva como
CaptureItemIndicatoren tu nivel. Puede ser cualquier cosa, siempre que sea lo suficientemente visible. En este ejemplo, utilizarás un diamante. En el panel Detalles, asigna CaptureItemSpawner al InfiltratorCaptureSpawner y CaptureItemIndicator al elemento que has elegido. Asigna también MapIndicator al indicador del mapa del infiltrado, ItemGrabbedMessageDevice al dispositivo de mensajes del HUD del infiltrado y ScoreManagerDevice al gestor de puntuación del infiltrado. Establece ReturnTime en un número negativo, ya que el objeto de captura del infiltrado no regresa.También debes configurar una instancia de
item_capture_managerpara los atacantes. Recuerda cambiar el CaptureItemIndicator por un elemento distinto de los elementos del infiltrado para evitar confusiones visuales a los equipos, y asegúrate de asignar el resto de dispositivos. Establece ReturnTime en un número positivo, ya que el objeto de captura del atacante regresa después de un tiempo establecido. - Haz clic en Abrir sesión en la barra de herramientas de UEFN para poner a prueba el nivel. Cuando pruebes tu nivel, el jugador debe tener un elemento sobre su cabeza cuando consiga un objetivo. El elemento debe moverse con el jugador, y cuando este deje caer o capture el objetivo, el elemento debe teletransportarse de vuelta al generador de objetos de captura.

Siguiente paso
En el siguiente paso de este tutorial, aprenderás a indicar rápidamente a los jugadores lo que deben hacer en una partida, y en qué centrarte para mejorar la experiencia del jugador.