Los médicos son un arquetipo de personaje habitual en muchos juegos. Su trabajo consiste en curar a los personajes cercanos y ayudar a sus compañeros a recuperarse tras recibir daño. Los médicos desempeñan distintas funciones según el juego, por ejemplo, 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 una serie de reglas lógicas.
- En espera:
- Comenzar a curar agentes
- Bucle de curación
- Navegar hasta el agente
El médico comienza en espera y vigila hasta que un agente entra en la zona de curación. Se añade ese agente a la cola de curación del médico. El médico debe buscar al siguiente agente que debe curar, por lo que una cola ofrece una estructura de datos útil para este fin, ya que consiste en una estructura de datos en la que el primero que entra es el primero que sale. Esto significa que el personaje que entre primero en la zona de curación será el primero al que se curará.
Una vez que el médico recibe el agente que necesita curar, primero comprueba si la vida del agente está por debajo del umbral de curación. Si es así, comienza a curarlo a un ritmo específico hasta que la vida del agente alcanza el umbral o el agente sale de la zona de curación. Mientras cura, el médico intentará mantenerse cerca del agente desplazándose continuamente hacia él. Una vez que la vida del agente alcanza el umbral, el médico busca al siguiente agente que debe curar y comienza el proceso de nuevo. Si no hay agentes que curar, el médico vuelve a estar en espera.
Puedes visualizar la lógica del NPJ médico en la siguiente máquina de estado finito. Para obtener más información sobre máquinas de estado finito (FSM), consulta Cómo entender el comportamiento de PNJ.
Al completar esta guía, aprenderás a crear un personaje médico personalizado que utilice la secuencia de comandos de comportamiento de PNJ que cura a otros personajes cercanos cuando su vida está por debajo de un umbral determinado. Al final de esta guía, se incluye la secuencia de comandos completa como referencia.
Cómo crear una nueva secuencia de comandos de comportamiento de PNJ
Para empezar a crear tu propio PNJ médico, crea una nueva secuencia de comandos de comportamiento de PNJ llamada medic_example. Para obtener más información sobre cómo crear tu propia secuencia de comandos de comportamiento de PNJ, consulta Crea 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 a fin de generar un personaje médico que cure a los jugadores cercanos.
Cómo implementar la cola de curación
La secuencia de comandos de comportamiento del PNJ comienza con varios valores que se utilizan para el movimiento del personaje y la visualización de depuración. No los necesitarás todos en esta secuencia de comandos, por lo que ahora eliminarás el código innecesario.
-
En la parte superior de la definición de la clase
medic_example, elimina los valores anteriores aOnBegin(). Tu personaje médico no esperará para desplazarse a los personajes; en cambio, los seguirá cuando los cure. No necesitas los valores de depuración para este ejemplo. Utilizarás otros objetos para visualizar cuando tu médico cura a los personajes. -
Después de obtener las interfaces del personaje en el primer enunciado
if, elimina el código dentro del enunciadothenenOnBegin(). Tu personaje médico no necesita hacer un bucle entre puntos después de generarse, por lo que vigilará alrededor de su punto de aparición y esperará a que aparezcan personajes para curar. -
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 empezar a construir tu personaje médico.
-
En la parte superior de la definición de la clase
medic_example, añade los siguientes valores:-
float editable
HealingThreshold. Este es el umbral de vida que los personajes deben tener para recibir una curación.# El umbral de vida que un personaje debe tener antes de que lo curen. @editable HealingThreshold:float = 50.0 -
Añade un float editable
HealingDelay. El tiempo que hay que esperar entre cada instancia de curación mientras se cura a los personajes. Cambia esto en función de si quieres que tu médico cure más lento o más rápido.# El umbral de vida que un personaje debe tener antes de que lo curen. @editable HealingThreshold:float = 50.0 # Cuánto tiempo se debe esperar antes de curar a los personajes @editable HealingDelay:float = 1.5 -
Un float editable
HealingAmount. La dosis de vida con la que se curará a los personajes por instancia de curación. Cuando tu PNJ médico cura a un personaje, lo curará con unaHealingAmountcadaHealingDelaysegundos.# Cuánto tiempo se debe esperar antes de curar a los personajes @editable HealingDelay:float = 1.5 # Cuánto se curará a los personajes por instancia de curación. @editable HealingAmount:float = 5.0 -
El
HealVolumede una zona de mutación editable. Este es el volumen con el que los personajes entran para curarse. En este ejemplo, utilizarás una zona de mutación porque la zona de mutación tiene unAgentEntersEvental que tu médico se puede suscribir y comprobar si hay personajes que necesiten curación.# Cuánto se curará a los personajes por instancia de curación. @editable HealingAmount:float = 5.0 # El volumen con el que los personajes entran para curarse. @editable HealVolume:mutator_zone_device = mutator_zone_device{} -
Un generador de VFX editable
VFXSpawner. La retroalimentación visual es importante para saber que tu código funciona, por lo que utilizarás un generador de VFX para generar efectos cuando se cure a un personaje.# El volumen con el que los personajes entran para curarse. @editable HealVolume:mutator_zone_device = mutator_zone_device{} # El generador de VFX para reproducir VFX mientras se curan los personajes. @editable VFXSpawner:vfx_spawner_device = vfx_spawner_device {} -
Una variable opcional
agentllamadaAgentToFollow. Esto almacena una referencia del personaje al que el médico debe seguir mientras lo cura.# El generador de VFX para reproducir VFX mientras se curan los personajes. @editable VFXSpawner:vfx_spawner_device = vfx_spawner_device {} # El agente al que se debe seguir mientras se cura var AgentToFollow:?agent = false -
Una cola variable de agentes llamada
AgentsToHeal. Si varios personajes necesitan curación, tu médico curará a los personajes según el orden en el que entraron en elHealVolume. En el próximo paso, configurarás el código de cola. Para obtener más información sobre la estructura de datos de la cola, consulta Pilas y colas en verse.# El agente al que se debe seguir mientras se cura var AgentToFollow:?agent = false # La cola de agentes para curar en el caso de que varios agentes entren en el volumen de curación. var AgentsToHeal<public>:queue(agent) = queue(agent){} -
Un float variable
UpdateRateSeconds. El tiempo que hay que esperar entre la actualización de la posición deHealVolumeyVFXSpawner.# La cola de agentes para curar en el caso de que varios agentes entren en el volumen de curación. var AgentsToHeal<public>:queue(agent) = queue(agent){} # Se utiliza para especificar la rapidez con la que se actualiza la posición del HealVolume y el VFXSpawner UpdateRateSeconds<private>:float = 0.1
-
-
Para implementar la cola
AgentsToHeal, deberás utilizar el código que se facilita al final de este paso.- De vuelta en el explorador de Verse, haz clic derecho en el nombre de tu proyecto y elige 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 seleccionarlo como secuencia de comandos.
-
Dale un nombre a tu clase de Verse cambiando el texto del campo Nombre de la clase por
queue. -
Haz clic en Crear para crear el archivo de Verse.
-
En el explorador de Verse, haz doble clic en el nombre del archivo de Verse para abrirlo en Visual Studio Code.
-
Reemplaza el código de tu archivo
queuecon el siguiente código. Este código implementa una cola genérica de tipotypemediante una estructura de datos de lista. Este es un ejemplo de tipo paramétrico, ya que la implementación de la cola funcionará sin importar el 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, así como brindar formas de hacer referencia con facilidad a los archivos de uso común. Por ejemplo, en este proyecto, crearás una carpeta para almacenar los comportamientos de los PNJ. En Visual Studio Code, pulsa el botón Nueva carpeta para crear una nueva carpeta en tu proyecto de UEFN. Nombra la carpeta
npc_behaviors. Luego, arrastra tu archivomedic_examplede Verse en la nueva carpeta.
Ahora, tu código en medic_example debería compilar correctamente.
Cómo curar a los personajes del volumen
Cuando entra un personaje herido en el HealVolume, tu personaje médico debe empezar a curarlo si su vida está por debajo del HealingThreshold. Cuando la vida del personaje supere el HealingThreshold, el médico dejará de curarlo y se dirigirá al siguiente personaje que necesite curación. En caso de que existan varios personajes, el médico deberá curarlos en el orden en el que entraron en el HealVolume. Sigue estos pasos para curar a los personajes cuando entren en el HealVolume.
-
De vuelta en tu archivo
medic_example, enOnBegin()después del enunciadothen, inicia unloop. Dentro delloop, obtén el resultado de la funciónDequeue()de la colaAgentsToHealy guárdalo en la variableDequeueResult.then: loop: # Obtén el siguiente agente en la cola para curarlo. Si hay un agente que curar, llama a AgentToHeal y cúralo. # Si no hay agentes para curar, espera hasta que un agente entre en el HealVolume. if: DequeueResult := AgentsToHeal.Dequeue[] -
La variable
DequeueResultes unatupleque devuelve tanto una copia de la colaAgentsToHealcon el primer elemento eliminado como el agente al frente de la cola. ActualizaAgentsToHealajustándolo al 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 que hay que curar, debes empezar a curarlo mientras esté en el
HealVolume. Debes definir una nueva función llamadaHealCharacter()para controlarlo. Añade una nueva función llamadaHealCharacter()a la definición de la 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 debe realizar varias tareas asíncronas al curar a un personaje.# Cura al personaje y espera HealingDelayAmount. # Termina cuando la vida del personaje alcanza el HealingThreshold # o el personaje abandona el HealVolume. HealCharacter(AgentToHeal:agent, Navigatable:navigatable, Focusable:focus_interface)<suspends>:void= -
En
HealCharacter, comprueba si elAgentToHealestá en el volumen mediante la llamadaIsInVolume[], y pasaAgentToHealcomo argumento. Si el agente está en el volumen, puedes empezar 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[] -
Cuando tengas un personaje listo para curar, tienes que asegurarte de que tu médico se mantenga cerca del personaje que va a curar. Crea un
navigation_targeta partir deAgentToHealconMakeNavigationTargety guárdalo en una variableNavigationTarget. Luego, en un enunciadobranch, llama a la funciónNavigateTo()mediante la interfaznavigatabledel PNJ para que tu médico navegue hasta elAgentToHeal. También en la funciónbranch, llama a la funciónMaintainFocus()para asegurarte de que tu médico se centre en elAgentToHeal. Mediante el uso de un enunciadobranchen este contexto, puedes ejecutar tantoNavigateTo()comoMaintainFocus()de forma asíncrona al mismo tiempo, y ejecutar cualquier código después de tubranchinmediatamente. Para obtener más información sobre las expresiones de derivación, consulta la página derivación en Verse.# Solo cura al personaje si está dentro del HealVolume if: HealVolume.IsInVolume[AgentToHeal] CharacterToHeal := AgentToHeal.GetFortCharacter[] then: Print("El personaje está en el volumen, comienza la curación") NavigationTarget := MakeNavigationTarget(AgentToHeal) branch: Navigatable.NavigateTo(NavigationTarget) Focusable.MaintainFocus(AgentToHeal) -
Habilita el
VFXSpawnerpara reproducir VFX mientras tu médico cura a un personaje. A continuación, en una expresióndefer, deshabilita elVFXSpawner. Como el código para deshabilitar elVFXSpawnerestá en una expresióndefer, no se ejecutará hasta que se salga del ámbito actual. En esta situación, significa que el código solo se ejecutará cuando la función termine, por lo que se garantiza que será lo último que ocurra en la función. Para obtener más información sobre las expresiones diferidas, consulta la página de Diferir.branch: Navigatable.NavigateTo(NavigationTarget) Focusable.MaintainFocus(AgentToHeal) VFXSpawner.Enable() defer: VFXSpawner.Disable() -
Al curar al
CharacterToHeal, la curación debe detenerse cuando se da una de estas dos condiciones. O bien la vida del personaje se cura más allá delHealingThreshold, o el personaje sale delHealVolume. Para lograrlo, utilizarás una expresiónrace. Establece una expresiónraceentre unloopy unAwait()en elHealVolume.AgentExitsEvent.branch: Navigatable.NavigateTo(NavigationTarget) Focusable.MaintainFocus(AgentToHeal) VFXSpawner.Enable() defer: VFXSpawner.Disable() race: loop: HealVolume.AgentExitsEvent.Await() -
Dentro del
loop, obtén la vida actual del personaje medianteGetHealth()y guárdalo en el valorCurrentHealth. Luego, en un enunciadoif, comprueba si laCurrentHealthmás laHealingAmountes mayor que elHealingThreshold. Si es así, tu médico debería dejar de curar y salir del bucle. Sin embargo, si la vida actual del personaje es solo un poco menor que el umbral de curación, lo ideal sería curarlo hasta el umbral de curación. Añade un segundo enunciadoifdentro del primero que compruebe siCurrentHealthes menor que elHealingThreshold. Si es así, configura la vida del personaje según elHealingThreshold.race: loop: CurrentHealth := CharacterToHeal.GetHealth() if(CurrentHealth + HealingAmount > HealingThreshold): if (CurrentHealth < HealingThreshold): CharacterToHeal.SetHealth(HealingThreshold) PrintNPCB("El personaje alcanzó el umbral de curación, se detiene la curación") break HealVolume.AgentExitsEvent.Await() -
En caso contrario, si la
CurrentHealthmás laHealingAmountes menor que elHealingThreshold, configura la vida del personaje según laCurrentHealthmás laHealingAmount.if(CurrentHealth + HealingAmount > HealingThreshold): if (CurrentHealth < HealingThreshold): CharacterToHeal.SetHealth(HealingThreshold) PrintNPCB("El personaje alcanzó el umbral de curación, se detiene la curación") break else: CharacterToHeal.SetHealth(CurrentHealth + HealingAmount) -
Al final del
loop, espera unHealingDelayde tiempo. Sin este tiempo de espera, se curará a los personajes cada vez que se actualice la simulación, por lo que elHealingDelayevitará que se curen de forma instantánea. El código completo deHealCharacter()debería verse de la siguiente manera.# Cura al personaje y espera HealingDelayAmount. # Termina cuando la vida del personaje alcanza el HealingThreshold # 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á en el 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 alcanzó el umbral de curación, se detiene la curación") break else: CharacterToHeal.SetHealth(CurrentHealth + HealingAmount) Sleep(HealingDelay) HealVolume.AgentExitsEvent.Await() -
De vuelta en
OnBegin(), en la expresiónthendentro de tuloop, llama aHealCharacter()al pasar elAgentToHeal, la interfazNavigabley la interfazFocusable.if: DequeueResult := AgentsToHeal.Dequeue[] set AgentsToHeal = DequeueResult(0) AgentToHeal := DequeueResult(1) then: Print("Se quitó de la cola, siguiente agente para curar") HealCharacter(AgentToHeal, Navigatable, Focusable) -
Tu médico no siempre tendrá un personaje al que curar cerca, y la función
Dequeue[]fallará si no hay agentes en la colaAgentsToHeal. Para solucionar esto, añade un enunciadoelseal final delloop. Dentro de este enunciadoif, llama aSleep()durante un tiempoHealingDelayy, luego,Await()alHealVolume.AgentEntersEvent. De esta forma, tu personaje médico no llamará sin cesar aDequeue[]en la colaAgentsToHeal, sino que esperará a que un nuevo personaje entre en elHealVolumeantes de reiniciar el bucle. El bucle debería verse de la siguiente manera.loop: # Obtén el siguiente agente en la cola para curarlo. Si hay un agente que curar, llama a AgentToHeal y cúralo. # Si no hay agentes para curar, espera hasta que un agente entre en el HealVolume. if: DequeueResult := AgentsToHeal.Dequeue[] set AgentsToHeal = DequeueResult(0) AgentToHeal := DequeueResult(1) then: Print("Se quitó de la cola, siguiente agente para curar") HealCharacter(AgentToHeal, Navigatable, Focusable) else: Print("¡AgentsToHeal está vacío!") Sleep(HealingDelay) HealVolume.AgentEntersEvent.Await()
Cómo seguir cuando los personajes están en el volumen de curación
Para saber cuándo los personajes entran o salen del HealVolume, deberás suscribir los AgentEntersEvent y AgentExitsEvent del HealVolume a nuevas funciones.
-
Añade una nueva función llamada
OnAgentEnters()a la definición de la clasemedic_example. Esta función toma el agente que acaba de entrar en elHealVolumey lo coloca en la colaAgentsToHeal.OnAgentEnters(EnteredAgent:agent):void= Print("El agente entró en el volumen de curación") -
En
OnAgentEnters(), comprueba que el agente en el volumen no sea el personaje médico. Si es así, configura la colaAgentsToHealcon el resultado de llamar aEnqueue[]con elEnteredAgent. La función completaOnAgentEnters()debería verse de la siguiente manera:OnAgentEnters(EnteredAgent:agent):void= Print("El agente entró en el 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 deOnBegin()ya llama aDequeue[]en un bucle. Sin embargo, puede que quieras ejecutar código cuando un agente salga del volumen en tus ejemplos, así que ahora configurarás una función para esto. Añade una nueva función llamadaOnAgentExits()a la definición de la clasemedic_example.OnAgentExits(ExitAgent:agent):void= Print("El agente salió del volumen de curación") -
En
OnBegin(), suscribe losAgentEntersEventyAgentExitsEventdeHealVolumeaOnAgentEntersyOnAgentExits, respectivamente. Dado que debe comenzar deshabilitado, este es 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 necesita moverse con él para coincidir con su posición actual. Lo mismo es verdadero para los VFXSpawner. Para ello, utilizarás una nueva función DeviceFollowCharacter().
-
Añade una nueva función llamada
DeviceFollowCharacter()a la definición de la clasemedic_example. Esta función necesita ejecutarse de forma asíncrona para actualizar continuamente las posiciones de los dispositivos, así que añádele el modificador<suspends>.DeviceFollowCharacter()<suspends>:void= -
Dentro de la función
DeviceFollowCharacter(), obtén elfort_characterdel médico mediante la obtención del agente conGetAgent[]y, luego, llamando aGetFortCharacter[].DeviceFollowCharacter()<suspends>:void= if: # Obtén el agente (personaje de IA) al que se asocia este comportamiento. Agent := GetAgent[] # Obtén la interfaz fort_character del agente para acceder a los comportamientos, eventos, funciones e interfaces específicos del personaje de Fortnite. Character := Agent.GetFortCharacter[] -
Ahora necesitas mover continuamente el
HealVolumey elVFXSpawnera la posición delCharacter. Lo harás mediante un bucleMoveTo()en ambos dispositivos. Inicia unloop, obtén la transformación delCharactery guárdala en la variableCharacterTransform.if: # Obtén el agente (personaje de IA) al que se asocia este comportamiento. Agent := GetAgent[] # Obtén la interfaz fort_character del agente para acceder a los comportamientos, eventos, funciones e interfaces específicos del personaje de Fortnite. Character := Agent.GetFortCharacter[] then: loop: CharacterTransform := Character.GetTransform() -
Llama a
MoveTo()tanto en elVFXSpawnercomo en elHealVolume, moviéndolos alCharacterTransform.TranslationyCharacterTransform.Rotation. Configura la duración aUpdateRateSecondssegundos. Finalmente, llama aSleep()durante un tiempoUpdateRateSecondspara evitar que los dispositivos actualicen su posición en cada actualización de la simulación. Actualizar la posición de los dispositivos cada vez que se actualiza la simulación puede provocar movimientos irregulares en los dispositivos. El código completo deDeviceFollowCharacter()debería verse de la siguiente manera.DeviceFollowCharacter()<suspends>:void= if: # Obtén el agente (personaje de IA) al que se asocia este comportamiento. Agent := GetAgent[] # Obtén la interfaz fort_character del agente para acceder a los comportamientos, eventos, funciones e interfaces específicos del personaje 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 del enunciadoifdonde guardas tus interfaces de personaje pero antes del bucle, genera una instancia deDeviceFollowCharacter().
Cómo añadir tu personaje al nivel
-
Crea una nueva definición de PNJ llamado 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, establece el tipo en Guardia. La interfaz de guardia te permite acceder a funcionalidades específicas del personaje de guardia, como eventos para cuando se alerta o se sospecha del guardia, y te permite contratar guardias para usarlos como aliados. Los guardias también pueden portar armas, mientras que los personajes de los tipos personalizado y salvaje actualmente no pueden. También puedes cambiar el nombre de tu personaje en la pestaña Nombre.
-
En Comportamiento del PNJ, establece el comportamiento en Comportamiento de Verse. Luego, establece la secuencia de comandos de conducta del PNJ en
medic_example. Tu personaje aún tendrá acceso a la funcionalidad de la interfaz de guardia, pero utilizará tu secuencia de comandos de Verse para decidir qué hacer duranteOnBeginyOnEnd. -
En la pestaña Modificadores, en Modificador de aparición de guardias, haz clic en la pestaña Estética para cambiar la apariencia estética de tu personaje. Puedes elegir entre una estética preexistente o activar Redestinación estética del personaje para utilizar un modelo personalizado. Ten en cuenta que solo los guardias y los personajes de tipo personalizado pueden utilizar la redestinación estética del personaje, mientras que los animales salvajes no pueden. Para obtener más información sobre los modificadores de personajes y cuáles se aplican a los distintos tipos de personajes, consulta la página Definición del personaje.
-
-
Guarda tu definición de PNJ. En el explorador de contenido, arrastra tu definición de PNJ al nivel. Esto creará, de forma automática, un nuevo generador de personajes y le asignará tu definición de PNJ.
-
Arrastra una zona de mutación y un generador de VFX al nivel.
-
Selecciona tu generador de personajes. En el esquematizador, en Opciones de usuario, haz lo siguiente:
-
Configura Anulación de la secuencia de comandos AIBehavior en tu secuencia de comandos
medic_example. La anulación delAIBehavior Scripten el esquematizador te permite hacer referencia a dispositivos en el nivel, y necesitarás esta función para asignar tu HealVolume y VFXSpawner. -
Configura HealVolume en la zona de mutación y VFXSpawner en el generador de VFX que colocaste en el nivel.
-
-
Selecciona tu zona de mutación. En el esquematizador, en Opciones de usuario, configura Zona visible durante el juego como Verdadero. Esto te ayudará a visualizar dónde está el
HealVolumey cómo se mueve con el personaje médico. -
Selecciona tu generador de VFX. En el esquematizador, en Opciones de usuario, elige un efecto para configurar Efecto visual. Este ejemplo utiliza el efecto burbujas para transmitir la curación, pero es posible que quieras utilizar algo diferente, como fuegos artificiales o chispas. Cambia el efecto visual para adaptarlo a las necesidades de tu personaje.
-
Haz clic en Comenzar sesión en la barra de herramientas de UEFN para hacer una prueba de juego de tu nivel. Cuando hagas la prueba, tu personaje deberá curar a los personajes heridos que entren en la zona de mutación. Al curar a un personaje, se deben reproducir los VFX, y el médico debe seguir y centrarse en el personaje que cura.
Secuencia de comandos completa
El siguiente es una secuencia de comandos completa para un PNJ que cura a los personajes cuya vida está por debajo de un umbral determinado.
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 }
# Un comportamiento de PNJ diseñado en Verse que se puede utilizar dentro de una definición de PNJ o una anulación de secuencia de comandos de comportamiento de un dispositivo generador de personajes.
medic_example<public> := class(npc_behavior):
# El umbral de vida que un personaje debe tener antes de que lo curen.
@editable
HealingThreshold:float = 50.0
# Cuánto tiempo se debe esperar antes de curar a los personajes
@editable
HealingDelay:float = 1.5
# Cuánto se curará a los personajes por instancia de curación.
@editable
HealingAmount:float = 5.0
# El volumen con el que los personajes entran para curarse.
@editable
HealVolume:mutator_zone_device = mutator_zone_device{}
# El generador de VFX para reproducir VFX mientras se curan los personajes.
@editable
VFXSpawner:vfx_spawner_device = vfx_spawner_device {}
# El agente al que se debe seguir mientras se cura
var AgentToFollow:?agent = false
# La cola de agentes para curar en el caso de que varios agentes entren en el volumen de curación.
var AgentsToHeal<public>:queue(agent) = queue(agent){}
# Se utiliza para especificar la rapidez con la que se actualiza la posición del HealVolume y el 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 se asocia este comportamiento.
Agent := GetAgent[]
# Obtén la interfaz fort_character del agente para acceder a los comportamientos, eventos, funciones e interfaces específicos del personaje de Fortnite.
Character := Agent.GetFortCharacter[]
# Obtén la interfaz navegable del personaje para establecer objetivos específicos a los que el personaje pueda dirigirse.
Navigatable := Character.GetNavigatable[]
# Obtén la focus_interface del personaje para establecer objetivos específicos en los que centrarte después de desplazarte hasta su posición.
Focusable := Character.GetFocusInterface[]
then:
# Configura el HealVolume y el VFXSpawner para que sigan de forma continua al PNJ.
spawn{DeviceFollowCharacter()}
loop:
# Obtén el siguiente agente en la cola para curarlo. Si hay un agente que curar, llama a AgentToHeal y cúralo.
# Si no hay agentes para curar, espera hasta que un agente entre en el HealVolume.
if:
DequeueResult := AgentsToHeal.Dequeue[]
set AgentsToHeal = DequeueResult(0)
AgentToHeal := DequeueResult(1)
then:
PrintNPCB("Se quitó de la cola, siguiente agente para curar")
HealCharacter(AgentToHeal, Navigatable, Focusable)
else:
PrintNPCB("¡AgentsToHeal está vacío!")
Sleep(HealingDelay)
HealVolume.AgentEntersEvent.Await()
else:
# Si el código falla aquí algo falló al reunir el agente y sus interfaces
PrintNPCB("Se produjo un error en el guion de comportamiento del PNJ en la configuración del PNJ")
?Duration := 6.0,
?TextColor := NamedColors.Red )
# Cura al personaje y espera HealingDelayAmount.
# Termina cuando la vida del personaje alcanza el HealingThreshold
# 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á en el 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 alcanzó el umbral de curación, se detiene la curación")
break
else:
CharacterToHeal.SetHealth(CurrentHealth + HealingAmount)
Sleep(HealingDelay)
HealVolume.AgentExitsEvent.Await()
# Configura el HealVolume y el VFXSpawner para que sigan continuamente al personaje mediante el bucle
# MoveTo sobre la posición del personaje.
DeviceFollowCharacter()<suspends>:void=
if:
# Obtén el agente (personaje de IA) al que se asocia este comportamiento.
Agent := GetAgent[]
# Obtén la interfaz fort_character del agente para acceder a los comportamientos, eventos, funciones e interfaces específicos del personaje de Fortnite.
Character := Agent.GetFortCharacter[]
then:
# Haz un bucle MoveTo entre el HealVolume y el VFXSpawner para que su posición coincida con la del
* PNJ
loop:
CharacterTransform := Character.GetTransform()
VFXSpawner.MoveTo(CharacterTransform.Translation, CharacterTransform.Rotation, UpdateRateSeconds)
HealVolume.MoveTo(CharacterTransform.Translation, CharacterTransform.Rotation, UpdateRateSeconds)
Sleep(UpdateRateSeconds)
# Cuando un agente entra en el HealVolume, añádelo a la
# Cola de AgentsToHeal si no es el PNJ.
OnAgentEnters(EnteredAgent:agent):void=
PrintNPCB("El agente entró en el volumen de curación")
if (EnteredAgent <> GetAgent[]):
set AgentsToHeal = AgentsToHeal.Enqueue(EnteredAgent)
# Cuando un agente sale del HealVolume, PrintNPCB al registro
OnAgentExits(ExitAgent:agent):void=
PrintNPCB("El agente salió del volumen de curación")
# Contenedor personalizado que ofrece una duración y 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 entorno.
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
Con esta guía, habrás aprendido a crear un personaje médico que cura de forma automática a los personajes cuya vida está por debajo de un umbral de valor determinado. Emplea lo que aprendiste e intenta crear tu propio personaje médico con sus propios comportamientos especiales.
-
¿Puedes crear un médico que cambie entre los volúmenes de daño y curación en función de si hay un enemigo en el volumen?
-
¿Y un médico que utilice un recurso agotable para curar a los personajes? ¿Cómo recuperaría el médico este recurso? ¿Podría recuperarlo con el tiempo o atacando a los enemigos?