Los médicos son un arquetipo de personaje común en muchos juegos. El trabajo de un médico es curar a los personajes cercanos y ayudar a sus compañeros de equipo a recuperarse después de recibir daño. Los médicos desempeñan distintas funciones según el juego. Por ejemplo, hay médicos que atienden a pacientes en un hospital, médicos de combate que ayudan a su equipo a luchar además de curar o puestos neutrales que curan a cualquiera.
El personaje médico que crearás en este ejemplo sigue un conjunto de reglas lógicas.
- Inactivo:
- Inicio de curación de agentes
- Bucle de curación
- Desplazamiento hasta el agente
El médico comienza inactivo y patrulla hasta que un agente accede a la zona de curación. Ese agente se añade a la cola de curación del médico. El médico necesita saber cuál es el siguiente agente que tiene que curar. Para ello, una cola proporciona una estructura de datos útil, ya que las colas son estructuras de datos que funcionan por orden de llegada. Esto significa que el personaje que entre primero a la zona de curación será el primero que se cure.
Una vez que el médico obtiene el agente que necesita curar a continuación, primero comprueba si la salud del agente está por debajo del umbral de curación. Si es así, comienza a curarlo a un ritmo específico hasta que la salud del agente alcanza el umbral o el agente sale de la zona de curación. Mientras se cura, el médico intentará permanecer cerca del agente y se desplazará continuamente hacia él. Una vez que la salud del agente vuelve al umbral, el médico obtiene el siguiente agente que debe curar y comienza el proceso de nuevo. Si no hay agentes que curar, el médico vuelve a estar inactivo.
Puedes visualizar la lógica del PNJ médico mediante el autómata finito a continuación. Para obtener más información sobre los autómatas finitos, consulta Cómo comprender los comportamientos de los PNJ.
Al completar esta guía, aprenderás a crear un personaje médico personalizado con la secuencia de comandos de comportamiento de PNJ que cura a otros personajes cercanos cuando su salud está por debajo de un cierto umbral. La secuencia de comandos completa se incluye al final de esta guía como referencia.
Cómo crear una nueva secuencia de comandos de comportamiento de PNJ
Para comenzar a crear tu propio PNJ médico, crea una nueva secuencia de comandos de comportamiento de PNJ con el nombre medic_example. Para obtener más información sobre cómo crear tu propia secuencia de comandos de comportamiento de PNJ, consulta Cómo crear tu propio comportamiento de PNJ. Abre el archivo de Verse en Visual Studio Code.
Sigue estos pasos para crear una secuencia de comandos de comportamiento de PNJ en UEFN que genere un personaje médico que cure los jugadores cercanos.
Cómo implementar la cola de curación
La secuencia de comandos de comportamiento de PNJ comienza con varios valores para el movimiento del personaje y la visualización de depuración. No los necesitará todos en esta secuencia de comandos, por lo que ahora eliminarás el código que no haga falta.
-
En la parte superior de la definición de la clase
medic_example, elimina los valores previos aOnBegin(). Tu personaje médico no esperará a moverse hasta los personajes, sino que los seguirá mientras cura. No necesitas los valores de depuración para este ejemplo, sino que usarás otros objetos para visualizar cuando el médico cura a los personajes. -
En
OnBegin(), después de obtener las interfaces del personaje en la primera declaraciónif, elimina el código dentro de la declaraciónthen. Tu personaje médico no necesita recorrer los puntos después de aparecer, sino que patrullará alrededor de su punto de aparición esperando que los personajes se curen. -
Elimina las funciones
DrawDebugLocation()yDrawDebugLookAt(). No utilizarás los valores de depuración en este ejemplo, por lo que tampoco necesitas las funciones asociadas que los utilizan.
Después de eliminar el código innecesario, puedes comenzar a crear tu personaje médico.
-
En la parte superior de la definición de clase
medic_example, añade los siguientes valores:-
Float editable
HealingThreshold. Este es el umbral de salud por debajo del cual deben estar los personajes para recibir curación.# Umbral de PS que debe tener un personaje antes de curarlo. @editable HealingThreshold:float = 50.0 -
Añade un float editable denominado
HealingDelay. Esta es la cantidad de tiempo que se debe esperar entre cada instancia de curación mientras se curan los personajes. Cámbialo en función de si quieren que el médico cure más lento o más rápido.# Umbral de PS que debe tener un personaje antes de curarlo. @editable HealingThreshold:float = 50.0 # Indica cuánto tiempo hay que esperar antes de curar a los personajes. @editable HealingDelay:float = 1.5 -
Un float editable denominado
HealingAmount. Esta es la cantidad de salud para curar a los personajes por instancia de curación. Cuando tu PNJ médico cura a un personaje, lo curará con unaHealingAmountcadaHealingDelaysegundos.# Indica cuánto tiempo hay que esperar antes de curar a los personajes. @editable HealingDelay:float = 1.5 # Indica cuánto hay que curar a los personajes por instancia de curación. @editable HealingAmount:float = 5.0 -
Una zona de mutación editable denominada
HealVolume. Este es el volumen al que acceden los personajes para recibir curación. En este ejemplo usarás una zona de mutación porque esta tiene unAgentEntersEvental que tu médico puede suscribirse y verificar si hay personajes que puedan necesitar curarse.# Indica cuánto hay que curar a los personajes por instancia de curación. @editable HealingAmount:float = 5.0 # El volumen al que acceden los personajes para recibir curación. @editable HealVolume:mutator_zone_device = mutator_zone_device{} -
Un generador de efectos visuales editable denominado
VFXSpawner. La información visual es importante para saber si tu código funciona, por lo que usarás un generador de efectos visuales para generar efectos cuando un personaje se está curando.# El volumen al que acceden los personajes para recibir curación. @editable HealVolume:mutator_zone_device = mutator_zone_device{} # Generador de efectos visuales para reproducir efectos visuales cuando los personajes se estén curando. @editable VFXSpawner:vfx_spawner_device = vfx_spawner_device {} -
Un
agentopcional variable denominadoAgentToFollow. Esto almacena una referencia al personaje que el médico debe seguir mientras lo cura.# Generador de efectos visuales para reproducir efectos visuales cuando los personajes se estén curando. @editable VFXSpawner:vfx_spawner_device = vfx_spawner_device {} # Agente al que se seguirá mientras se cura. var AgentToFollow:?agent = false -
Una cola variable de agentes denominada
AgentsToHeal. Si varios personajes necesitan curación, tu médico los curará según el orden en que accedieron alHealVolume. Configurarás el código de la cola en el siguiente paso. Para obtener más información sobre la estructura de datos de la cola, consulta las pilas y colas en Verse.# Agente al que se seguirá mientras se cura. var AgentToFollow:?agent = false # Cola de agentes a los que curar en el caso de que varios agentes accedan al volumen de curación. var AgentsToHeal<public>:queue(agent) = queue(agent){} -
Un float variable denominado
UpdateRateSeconds. Esta es la cantidad de tiempo que se debe esperar entre la actualización de la posición deHealVolumeyVFXSpawner.# Cola de agentes a los que curar en el caso de que varios agentes accedan al volumen de curación. var AgentsToHeal<public>:queue(agent) = queue(agent){} # Se utiliza para especificar la velocidad con la que se actualiza la posición de HealVolume y VFXSpawner. UpdateRateSeconds<private>:float = 0.1
-
-
Para implementar la cola
AgentsToHeal, tienes que utilizar el código proporcionado al final de este paso.- En Explorador de Verse, haz clic con el botón derecho del ratón en el nombre de tu proyecto y selecciona Añadir nuevo archivo de Verse al proyecto para abrir la ventana Crear secuencia de comandos de Verse.
-
En la ventana Crear secuencia de comandos de Verse, haz clic en Clase de Verse para seleccionarla como tu secuencia de comandos.
-
Dale un nombre a tu clase de Verse al cambiar el texto en el campo Nombre de la clase a
queue. -
Haz clic en Crear para crear el archivo de Verse.
-
En el explorador de Verse, haz doble clic en el nombre de tu archivo de Verse para abrirlo en Visual Studio Code.
-
Reemplaza el código en tu archivo
queuecon el siguiente código. Este código implementa una cola genérica del tipotypecon una estructura de datos de lista. Este es un ejemplo de un tipo paramétrico, ya que la implementación de la cola funcionará independientemente del tipo a partir del cual la crees. En tu ejemplo, utilizarás una cola de personajes, por lo que tu definición de cola enmedic_exampleseráqueue(agent).list(t:type) := class: Data:t Next:?list(t) queue<public>(t:type) := class<internal>: Elements<internal>:?list(t) = false Size<public>:int = 0 Enqueue<public>(NewElement:t):queue(t) = queue(t): Elements := option: list(t): Data := NewElement Next := Elements Size := Size + 1 Dequeue<public>()<decides><transacts>:tuple(queue(t), t) = List := Elements? (queue(t){Elements := List.Next, Size := Size - 1}, List.Data) Front<public>()<decides><transacts>:t = Elements?.Data CreateQueue<public><constructor>(InData:t where t:type) := queue(t): Elements := option: list(t): Data := InData Next := false Size := 1 -
Organizar tus secuencias de comandos de Verse en carpetas distintas puede ayudar con la organización, además de proporcionar formas de hacer referencia fácilmente a archivos de uso común. Como ejemplo, crearás una carpeta para almacenar los comportamientos de tus PNJ en este proyecto. En Visual Studio Code, pulsa el botón Nueva carpeta para crear una carpeta nueva en tu proyecto de UEFN. Dale a la carpeta el nombre
npc_behaviors. A continuación, arrastra tu archivo de Versemedic_examplehasta la carpeta nueva.
Ahora tu código de medic_example debería compilarse correctamente.
Cómo curar personajes dentro de un volumen
Cuando un personaje herido alcanza el HealVolume, tu personaje médico debe comenzar a curarlo si su salud es menor que el HealingThreshold. Una vez que la salud del personaje supere el HealingThreshold, tu médico debe dejar de curar a ese personaje y pasar al siguiente personaje que necesita curación. En el caso de varios personajes, tu médico debe curar a los personajes en el orden en que accedieron al HealVolume. Sigue estos pasos para curar personajes cuando accedan al HealVolume.
-
Vuelve a tu archivo
medic_exampley, enOnBegin(), después de la declaraciónthen, inicia unloop. Dentro delloop, obtén el resultado de la funciónDequeue()de la colaAgentsToHealy guárdalo en una variableDequeueResult.then: loop: # Haz que se cure el siguiente agente de la cola. Si hay un agente al que curar, llama a AgentToHeal para hacerlo. # Si no hay agentes a los que curar, espera hasta que un agente acceda al HealVolume. if: DequeueResult := AgentsToHeal.Dequeue[] -
La variable
DequeueResultes unatupleque devuelve una copia de la colaAgentsToHealcon el primer elemento eliminado y el agente al principio de la cola. Para actualizarAgentsToHeal, configúralo en el primer valor de la tupla y guarda el segundo valor comoAgentToHeal.if: DequeueResult := AgentsToHeal.Dequeue[] set AgentsToHeal = DequeueResult(0) AgentToHeal := DequeueResult(1) -
Una vez que tengas el agente al que curar, debes comenzar a curarlo mientras está en el
HealVolume. Tienes que definir una nueva función denominadaHealCharacter()para controlarlo. Añade una nueva función denominadaHealCharacter()a la definición de clasemedic_example. Esta función toma las interfacesAgentToHeal,NavigatableyFocusablede los personajes médicos como argumentos de la función. Añade el modificador<suspends>a esta función, ya que tiene que realizar varias tareas asíncronas al curar a un personaje.# Cura al personaje y espera HealingDelayAmount de tiempo. # Termina cuando la salud del personaje alcanza el umbral de curación # o el personaje abandona el HealVolume. HealCharacter(AgentToHeal:agent, Navigatable:navigatable, Focusable:focus_interface)<suspends>:void= -
En
HealCharacter, para verificar siAgentToHealestá en el volumen, llama aIsInVolume[]y pasaAgentToHealcomo argumento. Si el agente está en el volumen, puedes comenzar a curarlo. Todos los agentes curables implementan la interfazhealthful, que forma parte delfort_characterdel agente. Obtén elfort_characterdel agente y guárdalo en un valorCharacterToHeal.HealCharacter(AgentToHeal:agent, Navigatable:navigatable, Focusable:focus_interface)<suspends>:void= # Solo cura al personaje si está dentro del HealVolume. if: HealVolume.IsInVolume[AgentToHeal] CharacterToHeal := AgentToHeal.GetFortCharacter[] -
Con el personaje listo para curarse, debes asegurarte de que tu médico permanezca cerca del personaje que se está curando. Crea un
navigation_targetdesdeAgentToHealmedianteMakeNavigationTargety guárdalo en una variableNavigationTarget. En una declaraciónbranch, llama a la funciónNavigateTo()mediante la interfaznavigatabledel PNJ para que tu médico se desplace hastaAgentToHeal. También en la funciónbranch, llama a la funciónMaintainFocus()para asegurarte de que el médico se concentre enAgentToHeal. Usar una declaraciónbranchen este contexto te permite ejecutar tantoNavigateTo()comoMaintainFocus()de forma asíncrona al mismo tiempo, además de ejecutar cualquier código después de tubranchinmediatamente. Para obtener más información sobre expresionesbranch, consulta la páginabranchen Verse.# Solo cura al personaje si está dentro del HealVolume. if: HealVolume.IsInVolume[AgentToHeal] CharacterToHeal := AgentToHeal.GetFortCharacter[] then: Print("El personaje está dentro del volumen. Comienza la curación.") NavigationTarget := MakeNavigationTarget(AgentToHeal) branch: Navigatable.NavigateTo(NavigationTarget) Focusable.MaintainFocus(AgentToHeal) -
Habilita
VFXSpawnerpara reproducir efectos visuales mientras tu médico cura a un personaje. A continuación, en una expresióndefer, deshabilitaVFXSpawner. Como el código para deshabilitarVFXSpawnerestá en una expresióndefer, no se ejecutará hasta que salga del ámbito actual. En este caso, significa que el código solo se ejecutará cuando finalice la función, para así garantizar que sea lo último que suceda en la función. Para obtener más información sobre expresionesdefer, consulta la página dedefer.branch: Navigatable.NavigateTo(NavigationTarget) Focusable.MaintainFocus(AgentToHeal) VFXSpawner.Enable() defer: VFXSpawner.Disable() -
Al curar al
CharacterToHeal, la curación debe detenerse cuando ocurre una de estas dos condiciones: o la salud del personaje se cura más allá delHealingThresholdo el personaje sale delHealVolume. Para lograrlo, tienes que utilizar una expresiónrace. Configura una expresiónraceentre unloopy unAwait()enHealVolume.AgentExitsEvent.branch: Navigatable.NavigateTo(NavigationTarget) Focusable.MaintainFocus(AgentToHeal) VFXSpawner.Enable() defer: VFXSpawner.Disable() race: loop: HealVolume.AgentExitsEvent.Await() -
Dentro del
loop, obtén la salud actual del personaje medianteGetHealth()y guárdala en un valorCurrentHealth. A continuación, en una declaraciónif, verifica siCurrentHealthmásHealingAmountes mayor queHealingThreshold. Si es así, tu médico debería detener la curación y ejecutarbreakpara salir del bucle. Sin embargo, si la salud actual del personaje es un poco menor que el umbral de curación, tendrás que curarlo hasta dicho umbral. Añade una segunda declaraciónifdentro de la primera que verifique siCurrentHealthes menor queHealingThreshold. Si es así, establece la salud del personaje enHealingThreshold.race: loop: CurrentHealth := CharacterToHeal.GetHealth() if(CurrentHealth + HealingAmount > HealingThreshold): if (CurrentHealth < HealingThreshold): CharacterToHeal.SetHealth(HealingThreshold) PrintNPCB("El personaje ha alcanzado el HealingThreshold. Se detiene la curación.") break HealVolume.AgentExitsEvent.Await() -
De lo contrario, si
CurrentHealthmásHealingAmountno es mayor queHealingThreshold, establece la salud del personaje enCurrent HealthmásHealingAmount.if(CurrentHealth + HealingAmount > HealingThreshold): if (CurrentHealth < HealingThreshold): CharacterToHeal.SetHealth(HealingThreshold) PrintNPCB("El personaje ha alcanzado el HealingThreshold. Se detiene la curación.") break else: CharacterToHeal.SetHealth(CurrentHealth + HealingAmount) -
Al final del
loop, permanece inactivo durante un período de tiempo deHealingDelay. Sin esta inactividad, los personajes se curarán en cada actualización de la simulación, por lo queHealingDelayevitará que se curen instantáneamente. Tu códigoHealCharacter()completado debe ser como el siguiente.# Cura al personaje y espera HealingDelayAmount de tiempo. # Termina cuando la salud del personaje alcanza el umbral de curación # o el personaje abandona el HealVolume. HealCharacter(AgentToHeal:agent, Navigatable:navigatable, Focusable:focus_interface)<suspends>:void= # Solo cura al personaje si está dentro del HealVolume. if: HealVolume.IsInVolume[AgentToHeal] CharacterToHeal := AgentToHeal.GetFortCharacter[] then: Print("El personaje está dentro del volumen. Comienza la curación.") NavigationTarget := MakeNavigationTarget(AgentToHeal) branch: Navigatable.NavigateTo(NavigationTarget) Focusable.MaintainFocus(AgentToHeal) VFXSpawner.Enable() defer: VFXSpawner.Disable() race: loop: CurrentHealth := CharacterToHeal.GetHealth() if(CurrentHealth + HealingAmount > HealingThreshold): if (CurrentHealth < HealingThreshold): CharacterToHeal.SetHealth(HealingThreshold) PrintNPCB("El personaje ha alcanzado el HealingThreshold. Se detiene la curación.") break else: CharacterToHeal.SetHealth(CurrentHealth + HealingAmount) Sleep(HealingDelay) HealVolume.AgentExitsEvent.Await() -
En
OnBegin(), en la expresiónthendentro delloop, llama aHealCharacter()pasandoAgentToHeal, la interfazNavigabley la interfazFocusable.if: DequeueResult := AgentsToHeal.Dequeue[] set AgentsToHeal = DequeueResult(0) AgentToHeal := DequeueResult(1) then: Print("Se ha eliminado de la cola el siguiente agente al que curar.") HealCharacter(AgentToHeal, Navigatable, Focusable) -
Tu médico no siempre tendrá un personaje al que curar cerca, por lo que la función
Dequeue[]fallará si no hay agentes en la colaAgentsToHeal. Para controlarlo, añade una declaraciónelseal final delloop. Dentro de esta declaraciónif, llama aSleep()para un período de tiempoHealingDelayy, a continuación, ejecutaAwait()para elHealVolume.AgentEntersEvent. De este modo, el personaje médico no llamará infinitamente aDequeue[]en la colaAgentsToHeal, sino que esperará a que un nuevo personaje entre en elHealVolumeantes de reiniciar el bucle. Tu bucle completado debe ser como el siguiente.loop: # Haz que se cure el siguiente agente de la cola. Si hay un agente al que curar, llama a AgentToHeal para hacerlo. # Si no hay agentes a los que curar, espera hasta que un agente acceda al HealVolume. if: DequeueResult := AgentsToHeal.Dequeue[] set AgentsToHeal = DequeueResult(0) AgentToHeal := DequeueResult(1) then: Print("Se ha eliminado de la cola el siguiente agente al que curar.") HealCharacter(AgentToHeal, Navigatable, Focusable) else: Print("No queda nadie en AgentsToHeal.") Sleep(HealingDelay) HealVolume.AgentEntersEvent.Await()
Cómo realizar un seguimiento de los personajes que se encuentran en el volumen de curación
Para saber cuándo entran o salen personajes del HealVolume, tendrás que suscribir tanto el AgentEntersEvent como el AgentExitsEvent del HealVolume a nuevas funciones.
-
Añade una nueva función denominada
OnAgentEnters()a la definición de clasemedic_example. Esta función toma al agente que acaba de acceder alHealVolumey lo añade a la colaAgentsToHeal.OnAgentEnters(EnteredAgent:agent):void= Print("Un agente ha accedido al volumen de curación.") -
En
OnAgentEnters(), comprueba que el agente en el volumen no sea el personaje médico. Si es así, establece la colaAgentsToHealen el resultado de llamar aEnqueue[]con elEnteredAgent. Tu funciónOnAgentEnters()completada debe ser como la siguiente:OnAgentEnters(EnteredAgent:agent):void= Print("Un agente ha accedido al volumen de curación.") if (EnteredAgent <> GetAgent[]): set AgentsToHeal = AgentsToHeal.Enqueue(EnteredAgent) -
Cuando un agente sale del
HealVolume, no es necesario eliminarlo de la colaAgentsToHeal. Esto se debe a que el bucle enOnBegin()ya llama aDequeue[]en un bucle. Sin embargo, es posible que quieras ejecutar código cuando un agente salga del volumen en tus ejemplos, por lo que tienes que configurar una función para ello. Añade una nueva función denominadaOnAgentExits()a la definición de clasemedic_example.OnAgentExits(ExitAgent:agent):void= Print("Un agente ha salido del volumen de curación.") -
En
OnBegin(), suscribe elAgentEntersEventy elAgentExitsEventdelHealVolumeaOnAgentEntersyOnAgentExits, respectivamente. Dado que debería comenzar deshabilitado, se trata de un buen lugar para llamar aDisable()en el generador de personajes.OnBegin<override>()<suspends>:void= Print("¡Hola, IA!") VFXSpawner.Disable() HealVolume.AgentEntersEvent.Subscribe(OnAgentEnters) HealVolume.AgentExitsEvent.Subscribe(OnAgentExits)
Cómo mover el volumen de curación con el médico
Cuando el personaje médico se mueve, el HealVolume debe moverse con él para que coincida con su posición actual. Lo mismo sucede para el VFXSpawner. Para hacer esto, tendrás que utilizar una nueva función DeviceFollowCharacter().
-
Añade una nueva función denominada
DeviceFollowCharacter()a la definición de clasemedic_example. Esta función debe ejecutarse de forma asíncrona para actualizar continuamente las posiciones del dispositivo, así que añádele el modificador<suspends>.DeviceFollowCharacter()<suspends>:void= -
Dentro de la función
DeviceFollowCharacter(), consigue elfort_characterdel médico. Para ello, obtén primero al agente utilizandoGetAgent[]y, a continuación, llamando aGetFortCharater[].DeviceFollowCharacter()<suspends>:void= if: # Obtén el agente (personaje de IA) al que está asociado este comportamiento. Agent := GetAgent[] # Obtén la interfaz fort_character del agente para acceder a comportamientos, eventos, funciones e interfaces específicos de los personajes de Fortnite. Character := Agent.GetFortCharacter[] -
Ahora necesitas mover continuamente
HealVolumeyVFXSpawnera la posición deCharacter. Para ello, tienes que crear un bucle conMoveTo()en ambos dispositivos. Comienza unloop, obtén la transformación deCharactery guárdala en una variableCharacterTransform.if: # Obtén el agente (personaje de IA) al que está asociado este comportamiento. Agent := GetAgent[] # Obtén la interfaz fort_character del agente para acceder a comportamientos, eventos, funciones e interfaces específicos de los personajes de Fortnite. Character := Agent.GetFortCharacter[] then: loop: CharacterTransform := Character.GetTransform() -
Llama a
MoveTo()tanto enVFXSpawnercomo enHealVolumeal moverlos aCharacterTransform.TranslationyCharacterTransform.Rotation. Establece la duración en segundosUpdateRateSeconds. Por último, llama aSleep()durante un período de tiempo deUpdateRateSecondspara evitar que los dispositivos actualicen su posición en cada actualización de la simulación, ya que esto puede provocar inestabilidad en tus dispositivos. Tu códigoDeviceFollowCharacter()completado debe ser como el siguiente.DeviceFollowCharacter()<suspends>:void= if: # Obtén el agente (personaje de IA) al que está asociado este comportamiento. Agent := GetAgent[] # Obtén la interfaz fort_character del agente para acceder a comportamientos, eventos, funciones e interfaces específicos de los personajes de Fortnite. Character := Agent.GetFortCharacter[] then: loop: CharacterTransform := Character.GetTransform() VFXSpawner.MoveTo(CharacterTransform.Translation, CharacterTransform.Rotation, UpdateRateSeconds) HealVolume.MoveTo(CharacterTransform.Translation, CharacterTransform.Rotation, UpdateRateSeconds) Sleep(UpdateRateSeconds) -
En
OnBegin(), después de la declaraciónifdonde guardas las interfaces de tus personajes, pero antes del bucle, genera una instancia deDeviceFollowCharacter().
Cómo añadir tu personaje al nivel
-
Crea una nueva definición de personaje de PNJ con el nombre Médico. Haz clic en tu nueva definición de PNJ para abrir la pantalla Definición de PNJ.
-
En la pantalla Definición de PNJ, modifica las siguientes propiedades:
-
En Tipo de PNJ, configura el Tipo como Guardia. La interfaz de guardia te permite acceder a funciones de personajes específicas de los guardias, como eventos para cuando el guardia recibe una alerta o sospecha, y te permite contratar guardias para usarlos como aliados. Los guardias también pueden equipar armas, mientras que los personajes personalizados y de tipo animal salvaje no pueden actualmente. También puedes cambiar el nombre de tu personaje en la pestaña Nombre.
-
En Comportamiento del PNJ, configura el comportamiento como Comportamiento de Verse. A continuación, configura la secuencia de comandos de comportamiento de PNJ como
medic_example. Tu personaje seguirá teniendo acceso a la funcionalidad desde la interfaz de guardia, pero usará tu secuencia de comandos de Verse para decidir qué hacer duranteOnBeginyOnEnd. -
En la pestaña Modificadores, en Modificador de aparición de guardia, haz clic en la pestaña Estética para cambiar la estética de la aparición de tu personaje. Puedes elegir entre un cosmético preexistente o habilitar el Reposicionamiento cosmético del personaje para usar un modelo personalizado. Ten en cuenta que solo los guardias y los personajes de tipo personalizado pueden usar el reposicionamiento cosmético de los personajes, al contrario que los animales salvajes. Para obtener más información sobre los modificadores de personaje y cuáles se aplican a los distintos tipos de personaje, consulta la página Definición de personaje.
-
-
Guarda tu definición de PNJ. En el explorador de contenido, arrastra tu definición de PNJ al nivel. Esto creará automáticamente un nuevo generador de personajes y le asignará la definición de PNJ.
-
Arrastra una zona de mutación y un dispositivo generador de efectos visuales al nivel.
-
Selecciona tu generador de personajes. En el esquematizador, en Opciones de usuario:
-
Establece Anulación de la secuencia de comandos de comportamiento de la IA en tu secuencia de comandos
medic_example. Anular la secuencia de comandos de comportamiento de la IA en el esquematizador te permite hacer referencia a dispositivos en el nivel, y necesitarás esta funcionalidad para asignar tu HealVolume y VFXSpawner. -
Establece HealVolume en la zona de mutación y VFXSpawner en el generador de efectos visuales que has colocado en el nivel.
-
-
Selecciona tu zona de mutación. En el esquematizador, en Opciones de usuario, activa la opción Zona visible durante la partida. Esto te ayudará a visualizar dónde está el
HealVolumey cómo se mueve con el personaje médico. -
Selecciona tu generador de efectos visuales, VFX. En el esquematizador, en Opciones de usuario, establece Efecto visual en el efecto que prefieras. En este ejemplo se utiliza el efecto Burbujas para transmitir la curación, pero puede que quieras usar algo diferente, como fuegos artificiales o chispas. Cambia el efecto visual para adaptarlo a las necesidades de tu personaje.
-
Haz clic en Abrir sesión en la barra de herramientas de UEFN para probar tu nivel. Cuando hagas la prueba, tu personaje debería curar a los personajes heridos que acceden a la zona de mutación. Al curar a un personaje, se deben reproducir los efectos visuales y el médico debe seguir y concentrarse en el personaje que está curando.
Secuencia de comandos completa
A continuación tienes una secuencia de comandos completa para un PNJ que cura a personajes cuyos PS están por debajo de un cierto umbral.
medic_example.verse
using { /Fortnite.com/AI }
using { /Fortnite.com/Characters }
using { /Fortnite.com/Devices }
using { /Verse.org/Colors }
using { /Verse.org/Random }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
# Comportamiento de PNJ de Verse que se puede usar dentro de una definición de PNJ o una anulación de la secuencia de comandos de comportamiento de un dispositivo Generador de personajes.
medic_example<public> := class(npc_behavior):
# Umbral de PS que debe tener un personaje antes de curarlo.
@editable
HealingThreshold:float = 50.0
# Indica cuánto tiempo hay que esperar antes de curar a los personajes.
@editable
HealingDelay:float = 1.5
# Indica cuánto hay que curar a los personajes por instancia de curación.
@editable
HealingAmount:float = 5.0
# El volumen al que acceden los personajes para recibir curación.
@editable
HealVolume:mutator_zone_device = mutator_zone_device{}
# Generador de efectos visuales para reproducir efectos visuales cuando los personajes se estén curando.
@editable
VFXSpawner:vfx_spawner_device = vfx_spawner_device {}
# Agente al que se seguirá mientras se cura.
var AgentToFollow:?agent = false
# Cola de agentes a los que curar en el caso de que varios agentes accedan al volumen de curación.
var AgentsToHeal<public>:queue(agent) = queue(agent){}
# Se utiliza para especificar la velocidad con la que se actualiza la posición de HealVolume y VFXSpawner.
UpdateRateSeconds<private>:float = 0.1
OnBegin<override>()<suspends>:void=
VFXSpawner.Disable()
HealVolume.AgentEntersEvent.Subscribe(OnAgentEnters)
HealVolume.AgentExitsEvent.Subscribe(OnAgentExits)
if:
# Obtén el agente (personaje de IA) al que está asociado este comportamiento.
Agent := GetAgent[]
# Obtén la interfaz fort_character del agente para acceder a comportamientos, eventos, funciones e interfaces específicos de los personajes de Fortnite.
Character := Agent.GetFortCharacter[]
# Obtén la interfaz de desplazamiento del personaje para establecer objetivos específicos a los que viajará el personaje.
Navigatable := Character.GetNavigatable[]
# Obtén la focus_interface del personaje para establecer objetivos específicos en los que enfocarse después de viajar hacia ellos.
Focusable := Character.GetFocusInterface[]
then:
# Configura HealVolume y VFXSpawner para no seguir continuamente al PNJ.
spawn{DeviceFollowCharacter()}
loop:
# Haz que se cure el siguiente agente de la cola. Si hay un agente al que curar, llama a AgentToHeal para hacerlo.
# Si no hay agentes a los que curar, espera hasta que un agente acceda al HealVolume.
if:
DequeueResult := AgentsToHeal.Dequeue[]
set AgentsToHeal = DequeueResult(0)
AgentToHeal := DequeueResult(1)
then:
PrintNPCB("Se ha eliminado de la cola el siguiente agente al que curar.")
HealCharacter(AgentToHeal, Navigatable, Focusable)
else:
PrintNPCB("No queda nadie en AgentsToHeal.")
Sleep(HealingDelay)
HealVolume.AgentEntersEvent.Await()
else:
# Si el código falla aquí, significa se ha producido un error al recopilar el agente y sus interfaces.
PrintNPCB( "Error en la secuencia de comandos de comportamiento del PNJ al configurarlo",
?Duration := 6.0,
?TextColor := NamedColors.Red )
# Cura al personaje y espera HealingDelayAmount de tiempo.
# Termina cuando la salud del personaje alcanza el umbral de curación
# o el personaje abandona el HealVolume.
HealCharacter(AgentToHeal:agent, Navigatable:navigatable, Focusable:focus_interface)<suspends>:void=
# Solo cura al personaje si está dentro del HealVolume.
if:
HealVolume.IsInVolume[AgentToHeal]
CharacterToHeal := AgentToHeal.GetFortCharacter[]
then:
PrintNPCB("El personaje está dentro del volumen. Comienza la curación.")
NavigationTarget := MakeNavigationTarget(AgentToHeal)
branch:
Navigatable.NavigateTo(NavigationTarget)
Focusable.MaintainFocus(AgentToHeal)
VFXSpawner.Enable()
defer:
VFXSpawner.Disable()
race:
loop:
CurrentHealth := CharacterToHeal.GetHealth()
if(CurrentHealth + HealingAmount > HealingThreshold):
if (CurrentHealth < HealingThreshold):
CharacterToHeal.SetHealth(HealingThreshold)
PrintNPCB("El personaje ha alcanzado el HealingThreshold. Se detiene la curación.")
break
else:
CharacterToHeal.SetHealth(CurrentHealth + HealingAmount)
Sleep(HealingDelay)
HealVolume.AgentExitsEvent.Await()
# Configura HealVolume y VFXSpawner para seguir continuamente al personaje mediante un bucle.
# Muévete a la posición del personaje.
DeviceFollowCharacter()<suspends>:void=
if:
# Obtén el agente (personaje de IA) al que está asociado este comportamiento.
Agent := GetAgent[]
# Obtén la interfaz fort_character del agente para acceder a comportamientos, eventos, funciones e interfaces específicos de los personajes de Fortnite.
Character := Agent.GetFortCharacter[]
then:
# Crea un bucle MoveTo en HealVolume y VFXSpawner para hacer coincidir su posición con el
# PNJ.
loop:
CharacterTransform := Character.GetTransform()
VFXSpawner.MoveTo(CharacterTransform.Translation, CharacterTransform.Rotation, UpdateRateSeconds)
HealVolume.MoveTo(CharacterTransform.Translation, CharacterTransform.Rotation, UpdateRateSeconds)
Sleep(UpdateRateSeconds)
# Cuando un agente acceda al HealVolume, añádelo a la
# cola de AgentsToHeal si no es el PNJ.
OnAgentEnters(EnteredAgent:agent):void=
PrintNPCB("Un agente ha accedido al volumen de curación.")
if (EnteredAgent <> GetAgent[]):
set AgentsToHeal = AgentsToHeal.Enqueue(EnteredAgent)
# Cuando un agente salga de HealVolume, ejecuta PrintNPCB en el registro.
OnAgentExits(ExitAgent:agent):void=
PrintNPCB("Un agente ha salido del volumen de curación.")
# Envoltorio personalizado que proporciona una duración y un color predeterminados.
PrintNPCB(Msg:string,?Duration:float = 3.0, ?TextColor:color = NamedColors.Green):void =
Print("[new_npc_behavior] {Msg}", ?Color := TextColor, ?Duration := Duration)
# Esta función se ejecuta cuando el PNJ desaparece o se elimina del mundo.
OnEnd<override>():void =
if(Agent := GetAgent[]):
Print(medic_example_message_module.OnEndMessage(Agent))
else:
PrintNPCB("OnEnd")
queue.verse
list(t:type) := class:
Data:t
Next:?list(t)
queue<public>(t:type) := class<internal>:
Elements<internal>:?list(t) = false
Size<public>:int = 0
Enqueue<public>(NewElement:t):queue(t) =
queue(t):
Elements := option:
list(t):
Data := NewElement
Next := Elements
Size := Size + 1
Dequeue<public>()<decides><transacts>:tuple(queue(t), t) =
List := Elements?
(queue(t){Elements := List.Next, Size := Size - 1}, List.Data)
Front<public>()<decides><transacts>:t = Elements?.Data
CreateQueue<public><constructor>(InData:t where t:type) := queue(t):
Elements := option:
list(t):
Data := InData
Next := false
Size := 1
Por tu cuenta
Al completar esta guía, habrás aprendido a crear un personaje médico que cura automáticamente a los personajes por debajo de cierto umbral. Con lo que has aprendido, intenta crear tu propio personaje médico con sus propios comportamientos especiales.
-
¿Puedes crear un médico que cambie entre volúmenes de daño y curación en función de si hay un enemigo en el volumen?
-
¿Qué tal un médico que utiliza un recurso agotable para curar a los personajes? ¿Cómo restauraría el médico este recurso? ¿Podría restaurarlo con el tiempo o podría restaurarlo al atacar a los enemigos?