El personaje en este ejemplo usa una definición de personaje del tipo personalizado, ya que solo necesita moverse y no necesita acceder a la API de la vida silvestre o a la guardia. El comportamiento del personaje se rige por un comportamiento de Verse personalizado llamado verse_commander_character.
Los guardias son personajes no jugadores (PNJ) que pueden moverse a lo largo de una ruta designada y pueden volverse hostiles a los jugadores enemigos de ataque. Los animales salvajes son animales, como las gallinas y los jabalíes, que también pueden moverse por la ruta y atacar a los jugadores enemigos.
Para comenzar a crear el PNJ personalizado, crea un nuevo comportamiento de PNJ denominado vese_commander_character con el explorador de Verse. Para obtener más información sobre cómo crear tus propios comportamientos personalizados de PNJ, consulta Cómo crear comportamientos personalizados de PNJ.
El personaje necesita conocer y gestionar las siguientes propiedades:
CommandWaitTime: cuánto esperar entre cada comando.
FocusTime: cuánto tiempo forzar el foco en un objetivo. Para poder girar el personaje a la derecha o a la izquierda, se debe usar el
focus_interfacedel personaje para forzarlo a enfrentar un punto en particular a la derecha o a la izquierda. Ya que enfocarse en un objetivo no se completa a menos que se interrumpa, esto se establece en un número muy bajo, el tiempo suficiente para que un personaje gire hacia una dirección.ReachRadius: esto muestra qué tan cerca un personaje debe estar para que su objetivo de navegación se considere “alcanzado”.
VerseCommanderMinigame: esta es una referencia al VerseCommanderMinigame en el nivel y le permite al personaje escuchar los comandos que provienen de allí.
VFX y referencias de flechas: estas hacen referencia a los diferentes VFX de aparición o desaparición al teletransportarse, así como la flecha de avance, que hace más fácil ver la orientación del personaje.
Verse# A Verse-authored NPC Behavior that can be used within an NPC Definition or a Character Spawner device's Behavior Script Override. verse_commander_character<public> := class(npc_behavior): # The VFX that play when the NPC teleports out. @editable CharacterTeleportOutVFX:vfx_spawner_device = vfx_spawner_device{} # The VFX that play when the NPC teleports in. @editable CharacterTeleportInVFX:vfx_spawner_device = vfx_spawner_device{}Ahora que se definieron las características de los personajes, vamos a definir los comportamientos y las funciones que los controlan.
Movimiento de personaje
El personaje en este juego tiene los siguientes comportamientos:
Mover hacia adelante: el comando hacia adelante mueve al personaje 1 mosaico hacia adelante en el tablero de juego.
Girar a la derecha o Girar a la izquierda: los comandos Girar a la derecha y Girar a la izquierda hacen que el personaje gire 90 grados hacia su derecha o izquierda, respectivamente. Esto también debe suceder sin mover el personaje del cuadro en el que se encuentra.
Restablecer: cuando se ejecuta el comando Restablecer, el personaje se teletransporta a la posición inicial en el tablero de juego.
Comandos de espera: ya que el movimiento del personaje no puede controlarse directamente, necesita escuchar los comandos que provienen del dispositivo VerseCommanderMinigame en el nivel. Después de ejecutar todos sus comandos, se quedará inmóvil y esperará nuevos comandos.
EL PNJ en esta plantilla solamente tiene algunas opciones de movimiento, y puede avanzar un cuadro en la dirección en la que se encuentra, girar a la izquierda o a la derecha. Cada una de estas se hace a través de la función GetNavTarget(), que crea un nuevo objetivo de navegación a una TileDistance para que el personaje lo use. Este objetivo está a la izquierda, derecha o adelante del personaje, en función de si el comando es adelante, derecha o izquierda.
# Gets a new navigation target for the NPC based on the current transform and the given command.
GetNavTarget(CurrentTransform:transform, Command:command, TileDistance:vector3):transform=
# Based on the command, get the character's local forward, right, or left (negative right).
Direction :=
if (Command = Commands.Forward):
CurrentTransform.Rotation.GetLocalForward()
else if (Command = Commands.TurnRight):
CurrentTransform.Rotation.GetLocalRight()
else if (Command = Commands.TurnLeft):
-CurrentTransform.Rotation.GetLocalRight()
Cuando el PNJ recibe la señal Ejecutar, itera a través de la lista de comandos que recibe y envía cada uno a la función ExecuteCommand(). Primero, recibe la interfaz focus_interface y navigatable para el personaje; luego, realiza distintas acciones en función del comando. Para cada comando hacia adelante, derecha e izquierda, llama a GetNavTarget() para encontrar la nueva transformación que el PNJ debe usar. Luego, se mueve hacia adelante a la nueva transformación con NavigateTo(), en la interfaz navigatable o usa el focus_interface para hacer foco en el objetivo hacia la derecha o la izquierda.
# Executes the given command, either moving the NPC forward one tile or turning them left
# or right.
ExecuteCommand(Command:command, TileSize:vector3)<suspends>:void=
if:
# Get the Agent (the NPC).
Agent := GetAgent[]
# Gets the Fortnite Character interface, which gets you access to its gameplay data
# including its AI module for navigation and focus.
Character := Agent.GetFortCharacter[]
VFX del personaje
Cuando el personaje se mueve por el tablero de juego, una flecha muestra su posición y orientación para hacer que se visualice mejor el personaje desde la cámara descendiente. Esta flecha debe seguir al personaje y actualizarse a medida que el personaje gira y se mueve. La función MoveArrow() actualiza la posición de la flecha para que coincida con la del personaje, ya que copia su posición y orientación. La función CreateArrow() genera la flecha y realiza una llamada inicial a MoveArrow() para poder ver dónde está el personaje desde el comienzo.
# Creates an arrow prop at the NPC's position that visually shows the orientation of the NPC.
CreateArrow(Agent:agent):void=
if :
Character := Agent.GetFortCharacter[]
then:
var Transform:transform = Character.GetTransform()
# Spawn the arrow prop, then set the mesh and material for the prop.
SpawnPropResult := SpawnProp(ForwardArrowAsset, Transform)
if:
SpawnedProp := SpawnPropResult(0)?
Cuando se genera el personaje en el tablero, se mueve a un nuevo tablero o se restablece al comienzo del tablero a través del comando Restablecer, se reproduce una animación de teletransportación tanto para aparecer como para desaparecer. Para crear un efecto de teletransportación, primero llamamos a Hide() en el personaje y en la flecha; luego, reproduce TeleportOutVFX moviendo el generador de VFX a donde está el personaje y habilitándolo. Una vez que finalizan los VFX de desaparición al teletransportarse, debemos teletransportar al personaje a su nueva posición y reproducir TeleportInVFX en esa ubicación. Cuando todo eso está hecho, podemos llamar a Show() en el personaje y la flecha para mostrar al personaje en la nueva posición.
# Hides the NPC and the arrow prop, then teleports both to a new position,
# playing VFX for teleporting in and teleporting out.
PlayVFXAndMoveCharacter(StartPosition:transform)<suspends>:void=
if:
Agent := GetAgent[]
FortCharacter := Agent.GetFortCharacter[]
then:
# Hide the NPC and the arrow.
FortCharacter.Hide()
ForwardArrow.Hide()
La teletransportación se realiza con una función de ayuda MoveToTile(), que usa la transformación para mover al personaje y lo teletransporta allí. Se añade una pequeña compensación al valor Z de transformación para evitar que el personaje se fije al piso.
# Teleports the NPC to the given transform.
MoveToTile(Transform:transform)<transacts><decides>:void=
# Get the Agent (the NPC).
Agent := GetAgent[]
# Gets the Fortnite Character interface, which gets you access to its gameplay data
# including its AI module for navigation and focus.
Character := Agent.GetFortCharacter[]
var NewTransform:transform = Transform
Cómo procesar comandos
Cuando el personaje está en espera en el tablero, necesita sentarse y escuchar la señal Ejecutar para saber qué hacer a continuación. Esto sucede en la función AwaitCommands(). Esta función tiene el especificador suspends para que pueda ejecutarse de manera asincrónica, ya que el personaje necesita Await() al ExecuteCommandsEvent. Ya que los comandos vienen como una tupla que contiene una matriz de comandos y el TileSize usado para esos comandos, ellos necesitan procesarse en un bucle for al llamar a un ExecuteCommand(). A medida que cada comando se ejecuta, escondemos la flecha de avanzar, y solo se muestra nuevamente cuando el comando termina de ejecutarse. Una vez que todos los comandos terminan de ejecutarse, le avisamos con una señal al minijuego Verse Commander que ya terminamos de usar los comandos y estamos listos para más.
# Waits for commands to be sent from the verse_commander_minigame, then
# executes each command.
AwaitCommands()<suspends>:void=
if:
Agent := GetAgent[]
then:
# Wait for commands to be sent from the verse commander minigame.
ExecuteResult := VerseCommanderMinigame.ExecuteCommandsEvent.Await()
# For each execute result tuple, execute the command and pass the tile size from the tuple.
En lugar de procesar los nuevos comandos, el personaje también puede restablecerse al comienzo del tablero de juego actual con el botón Restablecer. Ya que el restablecimiento es inmediato y no usa el comando de colocar en la cola, el personaje necesita esperar eso por separado de la señal Ejecutar. Esto sucede en la función de AwaitReset(), que espera por BoardResetEvent para señalar del minijuego del comandante en Verse. Cuando lo hace, llama a PlayVFXAndMoveCharacter() para mover al personaje de vuelta a la posición inicial del tablero.
# Waits for the current board to be reset, then moves the
# NPC back to the starting position of the board along with VFX.
AwaitReset()<suspends>:void=
# Wait for the current board to be reset.
# The event payload is the starting position for the board.
StartPosition := VerseCommanderMinigame.BoardResetEvent.Await()
spawn{PlayVFXAndMoveCharacter(StartPosition)}Cómo ejecutar el bucle de juego del personaje
Ahora que las diferentes funciones que procesan comandos se configuraron, es tiempo de crear el bucle de juego central del jugador. El personaje necesita escuchar continuamente la señal Ejecutar para procesar una lista de comandos, o la señal Restablecer para restablecer de vuelta al comienzo del tablero. Ya que se debe esperar que la señal de ejecución y de restablecimiento ocurran de manera asincrónica, y que puede ocurrir varias veces por tablero, necesitas una función de ayudante independiente que se ocupe de ese bucle a través de los dos. La función CharacterCommandLoop() se ocupa de eso y ejecuta el bucle principal de juego para el personaje. En una expresión de competencia, compite entre la función AwaitReset() y un bucle que continuamente llama a AwaitCommands() para garantizar que el personaje siempre esté escuchando los comandos.
# Race between resetting the character to start of the board and awaiting commands for that character.
CharacterCommandLoop()<suspends>:void=
race:
AwaitReset()
loop:
AwaitCommands()Cuando el juego comienza, el personaje no estará presente en el nivel hasta que se genere mediante el generador de PNJ. Esto significa que cuando se genera, necesita encontrar el minijuego Verse Commander en el nivel, ya que no tiene una referencia a eso. Haz esto con GetCreativeObjectsWithTag() para encontrar el objeto con la etiqueta de jugabilidad verse_commander_minigame_tag, y configurar eso como el VerseCommanderMinigame. Al crear tu propia experiencia de minijuego, asegúrate de configurar correctamente tus etiquetas, de manera que los personajes en el nivel puedan encontrar los objetos con los que necesitan comunicarse.
Luego de encontrar el minijuego Verse Commander, el personaje necesita generar la flecha de avanzar que lo sigue alrededor con CreateArrow(). Para ejecutar el bucle del juego, la función CharacterCommandLoop() necesita estar en constante bucle para restablecerlo si aparece una señal Restablecer. Esto también debe suceder en una expresión race contra el GameEndedEvent del minijuego Verse Commander, ya que si el juego termina, el personaje debería dejar de hacer inmediatamente lo que está haciendo.
# This function runs when the NPC is spawned in the world and ready to follow a behavior.
OnBegin<override>()<suspends>:void=
# Get the Verse Commander Minigame Device.
# Assumption is that there is only one device in the level.
CreativeObjects := GetCreativeObjectsWithTag(verse_commander_minigame_tag{})
if:
CreativeObject := CreativeObjects[0]
MinigameManager := verse_commander_minigame[CreativeObject]
then:
Próximo paso
Definimos un PNJ personalizado que toma información de comandos de un dispositivo de Verse y la utiliza para moverse por del tablero de juego. Puedes encontrar la lista completa de código para crear el personaje personalizado en el paso final 7. Resultado final.
En el próximo paso, aprenderás a crear un tablero para el personaje, a fin de que se mueva y resuelva su rompecabezas.