La invisibilidad del infiltrado crea un problema interesante a la hora de atrapar el objetivo del defensor. ¿Cómo van a encontrar los defensores a un jugador invisible que podría estar corriendo de vuelta a la base con su objetivo? Para resolver este problema, puedes utilizar una ayuda visual, en este caso una utilería, 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 esté sosteniendo un objetivo.
Cómo crear el administrador de captura de objeto
- Crea un nuevo dispositivo de Verse denominado item_capture_manager con 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 del jugador. Agrega tambiénusing { /Fortnite.com/Characters }para acceder afort_characterde un 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 de aparición de objeto de captura llamada
CaptureItemSpawners. Esta matriz contiene el dispositivo generador de objetos de captura para los infiltrators.item_capture_manager := class(creative_device): Logger:log = log{Channel := triad_item_capture_log_channel} # Generador de objetos de captura que genera el elemento que se capturará. @editable CaptureItemSpawner:capture_item_spawner_device = capture_item_spawner_device{} - Una utilería creativa editable llamada
CaptureItemIndicator. Este es la utilería que flotará sobre la cabeza de un infiltrado cuando capture el objetivo.# Generador de objetos de captura que genera el elemento que se capturará. @editable CaptureItemSpawner:capture_item_spawner_device = capture_item_spawner_device{} # Utilería que flota sobre la cabeza de los jugadores cuando están sosteniendo el elemento de # CaptureItemSpawner. @editable CaptureItemIndicator:creative_prop = creative_prop{} - Un dispositivo indicador de mapa editable denominado
MapIndicator. Esto se ubicará debajo de CaptureItemSpawner en el nivel y mostrará en el mapa el lugar donde se encuentran los objetivos para cada equipo.# Utilería que flota sobre la cabeza de los jugadores cuando están sosteniendo el elemento de # CaptureItemSpawner. @editable CaptureItemIndicator:creative_prop = creative_prop{} # Indicador que muestra en el mapa el lugar donde se encuentran los objetivos de cada equipo que son. @editable MapIndicator:map_indicator_device = map_indicator_device{} - Dos floats editables
UpdateRateSecondsyVerticalOffset. El primero controla la rapidez con la que cambia la posición deCaptureItemIndicatory el segundo controla la distancia a la que flotaCaptureItemIndicatorpor encima de la cabeza del jugador.# Indicador que muestra en el mapa el lugar donde se encuentran los objetivos de cada equipo que son. @editable MapIndicator:map_indicator_device = map_indicator_device{} # Frecuencia con la que CaptureItemIndicator actualiza su posición. @editable UpdateRateSeconds:float = 0.15 # Altura a la que flota CaptureItemIndicator sobre la cabeza de un jugador. @editable VerticalOffset:float = 180.0 - Dispositivo de mensajes editable del HUD denominado
ItemGrabbedMessageDevice. Envía un mensaje a cada jugador cuando se recoge un objetivo.# Altura a la que flota CaptureItemIndicator sobre la cabeza de un jugador. @editable VerticalOffset:float = 180.0 # Muestra un mensaje cuando un jugador agarra el elemento de captura. @editable ItemGrabbedMessageDevice:hud_message_device = hud_message_device{} - Dispositivo administrador de puntaje editable denominado
ScoreManagerDevice. Otorga puntaje a un equipo cada vez que un jugador captura el objeto.# Muestra un mensaje cuando un jugador agarra el elemento de captura. @editable ItemGrabbedMessageDevice:hud_message_device = hud_message_device{} # Otorga la puntuación cuando un jugador captura el elemento de captura. @editable ScoreManagerDevice:score_manager_device = score_manager_device{} - Valor float editable denominado
ReturnTime. Si el elemento de captura tiene un tiempo de devolución antes de volver a CaptureItemSpawner, es necesario que hagas un seguimiento de cuánto dura ese tiempo de devolución para saber cuándo devolver los indicadores nuevamente a CaptureItemSpawner.
- Una matriz editable de dispositivos de aparición de objeto 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 con los indicadores que se muestran encima de la cabeza del personaje. Agrega el especificador<suspends>a esta función, ya que querrás generar uno de estos para un jugador siempre que sostenga un objetivo.# Hace que CaptureItemIndicator siga continuamente a un jugador encima de su cabeza. # Hace una carrera entre el bucle de actualización para CaptureItemIndictator, y si el jugador # captura el elemento, suelta el elemento o es eliminado. FollowCharacter(FortCharacter:fort_character)<suspends>:void= Logger.Print("Se generó la función FollowCharacter.")
Correr una carrera mientras sostiene el objetivo
Es importante pensar en lo que ocurre cuando un jugador captura el objetivo. El jugador puede hacer lo siguiente:
- Desplazarse, en cuyo caso necesitas que los indicadores de mapa y CaptureItem se actualicen constantemente según la posición del jugador. Esto puede hacerse en bucle.
- Capturar el objetivo, en cuyo caso necesitas que los indicadores regresen a CaptureItemSpawner en algún lugar donde no se vean, ya que no deberían ser visibles a menos que un jugador sostenga el elemento de captura.
- Soltar el objetivo o ser eliminado, en cuyo caso los indicadores tienen que permanecer donde se soltó el elemento y regresar a CaptureItemSpawner cuando se devuelve el elemento de captura.
Para conseguirlo, vas a configurar una expresión race (carrera). Al utilizar una race entre las tres condiciones anteriores, puedes continuar la actualización de 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()paraItemCapturedEventdeCaptureItemSpawner, unAwait()paraItemCapturedDroppedEventdeCaptureItemSpawnery unAwait()paraEliminatedEvent()deFortCharacter.FollowCharacter(FortCharacter:fort_character)<suspends>:void= Logger.Print("Se generó 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
MoveTo()para moverCaptureItemIndicatoryMapIndicatora la traslación y la rotación deTransformmás el valor deVerticalOffsetque configuraste anteriormente sobre una cantidad de tiempo enUpdateRateSeconds. Deseas generarSpawn{}las dos funciones deMoveTo()porque es necesario que tantoCaptureItemIndicatorcomoMapIndicatorse muevan en el mismo momento exacto, en lugar de esperar a que se complete la expresión de cada una. Como la traslación es unvector3que lo constituyen coordenadasX,YyZ, tendrás que colocarVerticalOffsetdentro de un nuevovector3. Dado queVerticalOffsetes la distancia vertical por encima de la cabeza de un 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)} - Por último, pon en pausa el proceso durante
0.0segundos. Esto garantiza que el bucle se ejecute una sola vez por actualización de simulación y no se salga de control al generar las funcionesMoveTo(). El códigoFollowCharacter()ahora debería verse de la siguiente manera:# Hace que CaptureItemIndicator siga continuamente a un jugador encima de su cabeza. # Hace una carrera entre el bucle de actualización para CaptureItemIndictator, y si el jugador # captura el elemento, suelta el elemento o es eliminado. FollowCharacter(FortCharacter:fort_character)<suspends>:void= Logger.Print("Se generó 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)} # Es conveniente asegurarnos de que este bucle se ejecute una sola vez por actualización de simulación, así que pausamos el proceso durante un solo tic de juego. Sleep(0.0) CaptureItemSpawner.ItemCapturedEvent.Await() CaptureItemSpawner.ItemDroppedEvent.Await() FortCharacter.EliminatedEvent().Await() Logger.Print("Objectivo soltado o capturado.")Cómo restablecer los indicadores
- Cuando el elemento de captura se captura o devuelve, es necesario que devuelvas los indicadores a
CaptureItemSpawneren algún lugar donde no se vean. En este caso, los teletransportarás a una altura sobreCaptureItemSpawner. Para hacer esto, agrega una función denominadaReturnIndicators()a la definición de claseitem_capture_manager.# Vuelve a colocar los indicadores de mapa y de elemento de captura en sus posiciones iniciales encima de los generadores. ReturnIndicators(InAgent:agent):void= - Obtén la transformación de
CaptureItemSpawnery guárdala en una variableSpawnerTransform. Luego, genera la variableMoveTo()paraCaptureItemIndicatoryMapIndicatoren la transformación y rotación deCaptureItemSpawner, y agregaVerticalOffsetde la misma forma que hiciste enlooppara ponerlos encima deCaptuerItemSpawnwer. Si quieres que tu utilería no se vea, puedes multiplicar el valor deVerticalOffsetpor un número grande, en este caso, 10. El métodoReturnIndicators()completado debería verse de la siguiente manera:# Vuelve a colocar los indicadores de mapa y de elemento de captura en sus posiciones iniciales encima de los generadores. ReturnIndicators():void= SpawnerTransform := CaptureItemSpawner.GetTransform() # Vuelve a teletransportar al generador y oculta CaptureItemIndicator y MapIndicator encima del mapa fuera del sitio. 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("Los indicadores regresaron a capture spawner.")
Cómo manejar a los jugadores que alcanzan, sueltan y capturan el objetivo
- Agrega un nuevo método,
OnItemPickedUp(), a la definición de claseitem_capture_manager. Este método toma unagenty genera una instancia deFollowCharacter()para ese personaje.# Señala a cada jugador cuando un jugador alcanza el objetivo. OnItemPickedUp(InAgent:agent):void= Logger.Print("Objectivo recogido.") - Obtén el
FortCharacterparaInAgent, y genera una funciónFollowCharacter()con eseFortCharacter. El métodoOnItemPickedUp()completado debería verse de la siguiente manera:# Señala a cada jugador cuando un jugador alcanza el objetivo. OnItemPickedUp(InAgent:agent):void= Logger.Print("Objectivo recogido.") if(FortCharacter := InAgent.GetFortCharacter[]): ItemGrabbedMessageDevice.Show() spawn{FollowCharacter(FortCharacter)} - Agrega un nuevo método,
OnItemCaptured(), a la definición de claseitem_capture_manager. Este método toma alagentque capturó el objetivo.# Cuando se captura el elemento, otorga puntuación al equipo capturador y devuelve los indicadores. OnItemCaptured(CapturingAgent:agent):void= Logger.Print("Objectivo capturado.") - En
OnItemCaptured(), activaScoreManagerDevicepara otorgar el puntaje de equipo del jugador que captura, y llama aReturnIndicators()para que se devuelvan los indicadores.# Cuando se captura el elemento, otorga puntuación al equipo capturador y devuelve los indicadores. OnItemCaptured(CapturingAgent:agent):void= Logger.Print("Objectivo capturado.") ScoreManagerDevice.Activate() ReturnIndicators() - Agrega un nuevo método,
OnItemDropped(), a la definición de claseitem_capture_manager. Este método toma alagentque soltó el elemento.# Cuando un jugador suelta un elemento, genera la función WaitForReturn() # si el valor de ReturnTime es mayor que 0. OnItemDropped(InAgent:agent):void= Logger.Print("Objectivo soltado.") - Cuando se suelta el objetivo, los indicadores deben permanecer cerca de este hasta que sea recogido o devuelto a
CaptureItemSpawner. Para saber cuándo hay que devolver los indicadores, usarás la variableReturnTimeque configuraste anteriormente. SiReturnTimees mayor o igual que0.0, es conveniente esperar esa cantidad de tiempo y, a continuación, devolver los indicadores. Si el valor deReturnTimees negativo, el objetivo no tiene tiempo de devolución, así que no es necesario que muevas los indicadores. Para mover los indicadores a las posiciones previas, genera una nueva función de ayuda denominadaWaitForReturn(), la cual definirás en el próximo paso.# Cuando un jugador suelta un elemento, genera la función WaitForReturn() # si el valor de ReturnTime es mayor que 0. OnItemDropped(InAgent:agent):void= Logger.Print("Objectivo soltado.") if(ReturnTime >= 0.0): spawn{WaitForReturn()} else: Logger.Print("El objetivo soltado no regresa.") - Agrega un nuevo método,
WaitForReturn(), a la definición de claseitem_capture_manager. Esta función espera una cantidad de tiempo deReturnTime, luego, devuelve los indicadores si el objetivo no se recogió antes de completarse la espera. Agrega el modificador<suspends>a este método para permitir que el proceso se ponga en pausa medianteSleep().# Espera la cantidad de tiempo de ReturnTime, luego devuelve los indicadores. WaitForReturn()<suspends>:void= Logger.Print("Esperando a que regresen los indicadores…") - Si es necesario o no devolver los indicadores dependerá de si el objetivo se recogió antes de que
ReturnTimehaya finalizado. Si así fue, no es conveniente devolver los indicadores, ya que volverían de inmediato al jugador, lo cual podría causar visuales extrañas. Para resolver esto, usarás una variable lógica donde el valor sea igual al resultado de una carrera.# Espera la cantidad de tiempo de ReturnTime, luego devuelve los indicadores. WaitForReturn()<suspends>:void= Logger.Print("Esperando a que regresen los indicadores…") # Devuelve los indicadores de CaptureItem y de mapa si el elemento de captura # no se recoge antes de que se agote el tiempo. ShouldReturn:logic := race: - Es necesario que la función
WaitForReturn()ejecute una carrera entre dos condiciones. Se agota el tiempo deReturnTimey el objetivo regresa aCaptureItemSpawner, en cuyo caso es necesario devolver los indicadores y el valor deShouldReturndebe sertrue. O si el objetivo se recoge antes de que se agote el tiempo deReturnTime, en cuyo caso el valor deShouldReturndebe serfalse. Debido a que cada una de estas condiciones devuelve un valor, ejecutarás la carrera con dos bloquesblocksdistintos.ShouldReturn:logic := race: block: block: - En el primer bloque, se llama a
Sleep()durante la cantidad de tiempo deReturnTime; luego, se devuelvetrue. En el segundo bloque, se ejecutaAwait()paraCaptureItemSpawner.ItemPickedUpEventy se devuelve false. La variableShouldReturnahora se inicializará en cualquiera de estos que se complete primero.ShouldReturn:logic := race: block: Sleep(ReturnTime) true block: CaptureItemSpawner.ItemPickedUpEvent.Await() false - Si
ShouldReturnes verdadero, es necesario que devuelvas los indicadores. Llama aReturnIndicators()siShouldReturnse evalúa entrue. El códigoWaitForReturn()completado ahora debería verse de la siguiente forma:# Espera la cantidad de tiempo de ReturnTime, luego devuelve los indicadores. WaitForReturn()<suspends>:void= Logger.Print("Esperando a que regresen los indicadores…") # Devuelve los indicadores de CaptureItem y de mapa si el elemento de captura # no se recoge antes de que se agote el tiempo. ShouldReturn:logic := race: block: Sleep(ReturnTime) true block: CaptureItemSpawner.ItemPickedUpEvent.Await() false if(ShouldReturn?): ReturnIndicators() - Ahora en
OnBegin(), suscribeItemPickedUpEventdeCaptureItemSpawneraOnItemPickedUp(),ItemCapturedEventaOnItemCaptured()yItemDroppedEventaOnItemDropped().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. Para ello, llama aMoveTo()enCaptureItemIndicatoryMapIndicator. El códigoOnBegin()debería ser similar al siguiente:OnBegin<override>()<suspends>:void= CaptureItemSpawner.ItemPickedUpEvent.Subscribe(OnItemPickedUp) CaptureItemSpawner.ItemCapturedEvent.Subscribe(OnItemCaptured) CaptureItemSpawner.ItemDroppedEvent.Subscribe(OnItemDropped) SpawnerTransform := CaptureItemSpawner.GetTransform() # Vuelve a teletransportar al generador y oculta CaptureItemIndicator debajo del mapa fuera del sitio. 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 vuelta en el editor, guarda la secuencia de comandos, compílala y arrastra el dispositivo al nivel. Elige una utilería apropiada que quieras que sirva como
CaptureItemIndicatoren tu nivel. Puede ser cualquier cosa, basta con que sea lo suficientemente visible. En este ejemplo, se utilizará un diamante. En el panel de detalles, asigna CaptureItemSpawner a InfiltratorCaptureSpawner y CaptureItemIndicator a la utilería que elegiste. También asigna MapIndicator al indicador de mapa del infiltrado, ItemGrabbedMessageDevice al dispositivo de mensajes del HUD del infiltrado y ScoreManagerDevice al administrador de puntaje del infiltrado. Establece ReturnTime en un número negativo, ya que el elemento de captura del infiltrado no se devuelve.También tienes que configurar una instancia de
item_capture_managerpara los atacantes. Recuerda cambiar CaptureItemIndicator a una utilería que sea diferente de la utilería del infiltrado para evitar confusión visual en los equipos, y asegúrate de asignar todos los demás dispositivos. Establece ReturnTime en un número positivo, ya que el elemento de captura del atacante se devuelve después de un tiempo establecido. - Haz clic en Comenzar sesión en la barra de herramientas de UEFN para realizar una prueba de juego del nivel. Cuando pruebes tu nivel, un jugador deberá tener una utilería sobre su cabeza al capturar un objetivo. La utilería debe moverse con el jugador y, cuando éste deje caer o capture el objetivo, la utilería debe teletransportarse al dispositivo de aparición de objetos de captura.

Próximo paso
En el siguiente paso de este tutorial, aprenderás a decirles con rapidez a los jugadores lo que deben hacer en un juego y en qué centrarte para mejorar la experiencia del jugador.