Scene Graph proporciona múltiples formas de crear jugabilidad flexible y dinámica a través de las diferentes interacciones entre Entidades y componentes. Esta plantilla muestra algunas de las formas en que puedes manipular Entidades en tiempo de ejecución mediante la generación y eliminación de Entidades, y cómo puedes utilizar eventos de componente y consultas para crear comunicación entre Entidades y construir elementos de jugabilidad reutilizables.
Generación y eliminación de prefabricados
Por ejemplo, echa un vistazo a la plataforma interactiva del segundo pasillo. Cuando el jugador pisa la plataforma, se añade a la escena un farol prefabricado que se retira cuando el jugador baja de la plataforma.
Abre SpawnPrefabDevice.verse para ver cómo funciona este código. Se trata de un dispositivo del modo Creativo que utiliza un dispositivo de volumen para saber cuándo entra un jugador en él. A continuación, genera un Prefabricado y lo elimina cuando el jugador pisa el activador. En la parte superior de la definición de la clase SpawnPrefabDevice, un TriggerVolume editable hace referencia al volumen de activador en el nivel.
SpawnPrefabDevice := class(creative_device):
@editable
TriggerVolume:volume_device = volume_device{}Cuando comienza la partida, el dispositivo define un nuevo Prefabricado de postes de luz para generar, así como la posición en la que hacerlo.
OnBegin<override>()<suspends>:void =
PrefabToSpawn:entity = LightPost.P_LightPost{}
SpawnTransform:transform = transform:
Translation := vector3:
Left := -9084.0
Up := -8.0
Forward := -919.0A continuación, obtiene la entidad de simulación y crea una serie de contextos de fallo en los que trabajar. Primero utiliza bucle para ejecutar el código que contiene repetidamente, seguido de una carrera entre dos sentencias de bloque.
if:
SimulationEntity := GetSimulationEntity[]
then:
loop:
race:
block:
TriggerVolume.AgentEntersEvent.Await()
SimulationEntity.AddEntities(array{ PrefabToSpawn })
PrefabToSpawn.SetGlobalTransform(SpawnTransform)
La primera instrucción block espera a que un agente entre en el dispositivo de volumen. Cuando lo hace, añade el prefabricado de farol a la escena mediante AddEntities() y lo posiciona correctamente mediante SetGlobalTransform(). El segundo Bloque espera a que el agente abandone el volumen y elimine el Prefabricado de su principal, en este caso, la entidad de simulación.
Como estos Bloques compiten en bucle, cada uno de ellos está siempre en marcha para que el jugador pueda entrar y salir del volumen para reaparecer el poste de luz tantas veces como quiera.
Secuencia de comandos completa
A continuación se muestra la forma completa de añadir y eliminar una entidad de la escena.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/SceneGraph }
using { /Verse.org/SpatialMath }
using { /UnrealEngine.com/Temporary/Diagnostics }
SpawnPrefabDevice := class(creative_device):
Solapamientos de entidades
La segunda sala también tiene una serie de ejemplos que muestran algunas de las distintas formas en que pueden interactuar las entidades. Por ejemplo, las entidades con un componente de malla pueden recibir una alerta cuando se solapan con otra entidad a través de los EntityEnteredEvent y EntityExitedEvent del componente de malla. Echa un vistazo al ejemplo de OVNI de la segunda sala para ver esta función en acción.
Cuando comienza el juego, la vaca reproduce una animación para levantarse, como si el ovni la estuviera abduciendo. La vaca utiliza el EntityEnteredEvent del componente de malla para saber cuándo se solapa con el OVNI, y luego se hace invisible para parecer como si hubiera sido abducida.
El código de este ejemplo se define en EntityEnteredExampleComponent.verse. Abre este archivo desde el Explorador de Verse.
La clase entity_entered_example_component comienza definiendo una matriz de fotogramas clave editable a partir de la cual construir la animación de abducción de la vaca. También define una variable StartTransform para indicar la posición inicial de la vaca en la escena.
entity_entered_example_component<public> := class<final_super>(component):
@editable
Keyframes:[]keyframed_movement_delta = array{}
var StartTransform:transform = transform{}En OnBeginSimulation(), la secuencia de comandos comienza recuperando fort_round_manager. Esta es una interfaz para el gestor de rondas de Fortnite que puedes utilizar para suscribir eventos al inicio y al final de una ronda. En este ejemplo, las secuencias de comandos suscriben la función OnRoundStarted() al inicio de la ronda mediante SubscribeRoundStarted(), lo que significa que la función se ejecutará solo cuando comience el juego en lugar de cuando la entidad comience la simulación.
OnBeginSimulation<override>():void =
(super:)OnBeginSimulation()
if:
FortRoundManager := Entity.GetFortRoundManager[]
then:
FortRoundManager.SubscribeRoundStarted(OnRoundStarted)A continuación, en OnRoundStarted(), la secuencia de comandos empieza estableciendo StartTransform en la transformación global de la entidad y, a continuación, suscribe EntityEnteredEvent del componente de malla a una nueva función OnEntityEntered(), que se activará siempre que otra malla se solape con la entidad. A continuación, genera una función PlayCowAbductionAnimation() para empezar a levantar la vaca.
OnRoundStarted():void =
set StartTransform = Entity.GetGlobalTransform()
if:
Mesh := Entity.GetComponent[mesh_component]
then:
Mesh.EntityEnteredEvent.Subscribe(OnEntityEntered)
spawn { PlayCowAbdcutionAnimation() }La función PlayCowAbductionAnimation() simplemente establece la transformación global de la vaca en su transformación inicial y espera un breve periodo de tiempo. A continuación, obtiene los componentes de malla y movimiento de fotograma clave de la Entidad, activa la malla para que la vaca sea visible, luego establece la animación en el componente de movimiento de fotograma clave y la reproduce.
PlayCowAbdcutionAnimation()<suspends>:void =
Entity.SetGlobalTransform(StartTransform)
Sleep(2.0)
if:
Mesh := Entity.GetComponent[mesh_component]
MovementComponent := Entity.GetComponent[keyframed_movement_component]
then:
set Mesh.Visible = true
MovementComponent.SetKeyframes(Keyframes, oneshot_keyframed_movement_playback_mode{})
MovementComponent.Play()Por último, la función OnEntityEntered() se utiliza para ejecutar código siempre que la vaca se solape con otra Entidad, en este caso el OVNI. Cuando lo hace, vuelve a obtener la malla y los componentes de movimiento con fotogramas clave, pero en su lugar los utiliza para detener la reproducción de las animaciones en curso y hacer que la vaca sea invisible, como si hubiera sido abducida. A continuación, genera una nueva instancia de PlayCowAbductionAnimation() para volver a iniciar el proceso.
OnEntityEntered(OtherEntity:entity):void =
if:
Mesh := Entity.GetComponent[mesh_component]
MovementComponent := Entity.GetComponent[keyframed_movement_component]
then:
MovementComponent.Stop()
set Mesh.Visible = false
spawn { PlayCowAbdcutionAnimation() }Secuencia de comandos completa
A continuación se muestra la secuencia de comandos completa para abducir una malla Vaca con una malla OVNI.
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
using { /Verse.org/SceneGraph/KeyframedMovement }
using { /Verse.org/SpatialMath }
using { /Fortnite.com/Game }
entity_entered_example_component<public> := class<final_super>(component):
Consulta de aciertos superpuestos
Las entidades también pueden consultar otras entidades mediante consultas de superposición. En lugar de detectar cuándo una Entidad entra o sale de una malla concreta, las consultas de solape pueden utilizarse para devolver cada Entidad y componente que solapa con un área concreta.
Esta área puede ser la propia entidad, un volumen de colisión determinado, como una esfera o una caja, o una posición desde la que simular la entidad. A continuación, devuelve una lista de overlap_hit. Cada overlap_hit te proporciona información sobre el componente o volumen solapado por el volumen de origen, y puedes consultar estos componentes para encontrar su entidad asociada.
Por ejemplo, prueba a pisar el pad interactivo delante del ejemplo FindOverlapHits. Cuando interactúas con la plataforma, el OVNI genera un volumen de colisión invisible y lo utiliza para realizar una consulta de solapamiento. Si el volumen de colisión se solapa con la vaca, ¡el OVNI la abduce!
El código de este ejemplo se define en FindOverlapHitsExampleComponent.verse. Abre este archivo desde el Explorador de Verse .
La clase comienza definiendo un dispositivo de volumen editable llamado Activador para hacer referencia a la plataforma interactiva que pisa el jugador, así como una variable lógica IsAbducting para saber si la vaca está siendo abducida o no. Cuando el componente comienza la simulación, suscribe la función OnRoundStarted() al inicio de ronda del administrador de rondas. De forma similar, la función OnRoundStarted() simplemente suscribe AgentEntersEvent y AgentExitsEvent del activador a las funciones OnTriggerEntered() y OnTriggerExited() respectivamente.
find_overlaphits_example_component<public> := class<final_super>(component):
@editable
Trigger:volume_device = volume_device{}
var IsAbducting:logic = false
OnBeginSimulation<override>():void =
Cuando el jugador pisa la plataforma, si el OVNI no está secuestrando una vaca en ese momento, se llama a la función OnTriggerEntered() para pausar cualquier movimiento que pueda estar realizando el OVNI recuperando su keyframed_movement_component y llamando a Pause(). A continuación, llama a EnableAbductionBeam() y PerformOverlapCheck() para activar el haz de abducción y comprobar si la vaca está debajo del OVNI.
OnTriggerEntered(Agent:agent):void=
if:
not IsAbducting?
MovementComponent := Entity.GetComponent[keyframed_movement_component]
then:
MovementComponent.Pause()
EnableAbductionBeam()
PerformOverlapCheck()La lógica real de comprobar los solapamientos se almacena en la función PerformOverlapCheck(). Para simular un haz de abducción, esta función genera una cápsula de colisión y define una CollisionTransform que se establece justo debajo del OVNI.
PerformOverlapCheck():void =
CollisionCapsule := collision_capsule{Radius := 36.0, Length := 328.0}
var CollisionTransform:transform = Entity.GetGlobalTransform()
set CollisionTransform.Translation.Up = CollisionTransform.Translation.Up - 248.0A continuación, en una expresión for, la función llama a FindOverlapHits() para buscar y devolver cualquier componente o volumen. Pasa la CollisionCapsule como volumen en el que comprobar las colisiones y la CollisionTransform como lugar desde el que simular esa colisión. A continuación, recorre cada solapamiento y comprueba si el componente solapado era un componente de malla, concretamente la malla SM_Toy_Cow de la entidad vaca. Si lo es, genera una función AbductCow() pasando la vaca que se va a abducir.
# Perform the overlap check from the entity that contains the mesh_component
for:
Overlap : Entity.FindOverlapHits(CollisionTransform, CollisionCapsule)
# Cast to see if what was overlapped was the Cow
CowMesh := Meshes.SM_Toy_Cow[Overlap.TargetComponent]
CowPrefab := CowMesh.Entity
do:
spawn { AbductCow(CowPrefab) }Para simular la abducción de la vaca, la Entidad construye una animación y luego la reproduce en la Entidad vaca de forma similar al ejemplo de superposición de Entidades anterior. Como este código se llama desde la entidad OVNI y no desde la vaca, el código necesita obtener componentes de la entidad vaca y luego pasar una animación para reproducirse. Empieza obteniendo los componentes de movimiento de la malla y los fotogramas clave de la vaca y, a continuación, ajusta IsAbducting a true.
AbductCow(CowEntity:entity)<suspends>:void =
# Get the components on the Cow Prefab
if:
CowMesh := CowEntity.GetComponent[mesh_component]
MovementComponent := CowEntity.GetComponent[keyframed_movement_component]
then:
set IsAbducting = trueComo los fotogramas clave utilizados en la animación de abducción de la vaca no están establecidos en el esquematizador, el código debe compilarlos basándose en la diferencia de posición entre el ovni y la vaca. Para ello, obtiene la diferencia de traslación entre la vaca y el OVNI y, a continuación, construye un nuevo keyframed_movement_delta a partir de esos valores. A continuación, establece ese único fotograma clave como una matriz en el componente de movimiento de fotogramas clave y llama a reproducir para permitir que la vaca se anime entre su posición inicial y el OVNI.
# Get the delta between Cow and UFO
DeltaTransform:transform = transform:
Translation:= Entity.GetGlobalTransform().Translation - CowEntity.GetGlobalTransform().Translation
Scale := vector3{Left:= 0.0, Up:= 0.0, Forward:= 0.0}
# Create a key frame
Keyframe := keyframed_movement_delta:
Transform := DeltaTransform
Duration := 2.0
Easing := ease_in_cubic_bezier_easing_function{}
La vaca puede animarse al OVNI cuando es abducida, pero el código también necesita hacer que desaparezca cuando se solapa con el propio OVNI. Para ello, el código espera el EntityEnteredEvent del componente de malla de la vaca y luego llama a RemoveFromParent() para eliminar la entidad vaca de la escena. Como la vaca no está, el OVNI puede empezar a patrullar de nuevo, por lo que el código llama a reproducir el componente de movimiento con fotogramas clave del OVNI para que se mueva.
# Wait for Entity Entered Event
CowMesh.EntityEnteredEvent.Await()
# Remove Cow from world
CowEntity.RemoveFromParent()
# Resume UFO Patrol
set IsAbducting = false
if:
UFOMovementComponent := Entity.GetComponent[keyframed_movement_component]
Por último, las funciones EnableAdbuctionBeam() y DisableAbductionBeam() actúan como simples ayudantes que activan y desactivan los componentes de malla de haz de abducción y luz focal del OVNI, respectivamente, cada vez que se les llama.
EnableAbductionBeam():void =
for:
Mesh : Entity.FindDescendantComponents(Meshes.S_EV_SimpleLightBeam_01)
do:
Mesh.Enable()
for:
Light : Entity.FindDescendantComponents(spot_light_component)
do:
Light.Enable()
Secuencia de comandos completa
A continuación se muestra la secuencia de comandos completa para consultar los aciertos superpuestos.
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
using { /Verse.org/Colors }
using { /Verse.org/SceneGraph/KeyframedMovement }
using { /Verse.org/SpatialMath }
using { /Fortnite.com/Game }
using { /Fortnite.com/Devices }
Consulta de aciertos de barrido
Los aciertos de barrido proporcionan otra forma importante de consultar los solapamientos entre entidades. El barrido se refiere a mover un objeto a lo largo de una distancia determinada por un vector concreto. Por ejemplo, mover un bloque a través de una plataforma para empujar a los jugadores a un hueco o lanzar un misil hacia delante para destruir un muro.
La función FindSweepHits() devuelve una lista de sweep_hit. Cada sweep_hit te da la misma información que un overlap_hit, como el componente o volumen visitado, y el volumen o componente fuente que realiza el barrido. También proporciona información sobre la posición de contacto, la normal, la normal de cara y la distancia a lo largo del barrido donde se ha producido la coincidencia.
La plantilla utiliza aciertos de barrido para construir una versión más avanzada del ejemplo anterior de aciertos superpuestos. Prueba a subir a la última plataforma interactiva de la segunda sala para ver este ejemplo. Cuando pisas la plataforma, el OVNI genera un haz de abducción. A continuación, realiza un golpe de barrido desde la malla OVNI hacia abajo, comprobando la primera Entidad con la que el barrido se solapa. Si la entidad es una vaca, el OVNI la abducirá de forma normal. Sin embargo, si la vaca está protegida por una entidad globo, el barrido golpeará primero el globo y se bloqueará, evitando que el OVNI secuestre a la vaca.
Abre FindOverlapHitsExampleComponent.verse desde el explorador de Verse para examinar el código. La configuración aquí es muy similar al ejemplo anterior de aciertos que se solapan, con la misma lógica utilizada para abducir a la vaca y activar y desactivar el haz de abducción. La principal diferencia radica en la función OnTriggerEntered() que se ejecuta cuando el jugador pisa el pad interactivo frente al ejemplo.
El código de esta función comienza de forma similar al ejemplo de impactos superpuestos, recuperando el componente de movimiento del fotograma clave de la Entidad y activando el haz de abducción.
OnTriggerEntered(Agent:agent):void=
# When a cow is inside the abduction area, stop the ship moving and start the abduction beam.
if:
not IsAbducting?
MovementComponent := Entity.GetComponent[keyframed_movement_component]
then:
MovementComponent.Pause()
EnableAbductionBeam()Sin embargo, como la función utiliza barridos en lugar de solapamientos, la lógica de si la vaca está bajo el haz de abducción es un poco diferente. Comienza obteniendo el primer subordinado de la entidad OVNI, en este caso la entidad de malla del OVNI. A continuación, crea un vector de desplazamiento a partir del cual hacer el barrido, apuntando directamente hacia abajo desde el OVNI.
# Perform the sweep from the UFO Mesh
if (Child := Entity.GetEntities()[0]):
DisplacementVector := vector3{Left:=0.0, Up:=-300.0, Forward:=0.0}A continuación, utiliza este vector de desplazamiento para llamar a la función auxiliar FindFirstSweepHit(), pasando la malla del OVNI y el vector. Si el primer componente es el componente de malla de la vaca, genera la función AbductCow() para simular la abducción de la vaca.
# Perform the sweep from the UFO Mesh
if (Child := Entity.GetEntities()[0]):
DisplacementVector := vector3{Left:=0.0, Up:=-300.0, Forward:=0.0}
FirstSweepHitEntity := FindFirstSweepHit(Child, DisplacementVector)
# If the First Hit Entity is the Cow Mesh, then abduct the Cow
if (HitEntity := FirstSweepHitEntity?; HitEntity.GetComponent[Meshes.SM_Toy_Cow]):
spawn { AbductCow(HitEntity) }La función FindFirstSweepHit() toma la entidad para el barrido y el vector de desplazamiento para el barrido. Llama a FindSweepHits() para simular un barrido y, a continuación, itera por cada acierto de barrido devuelto en una expresión `for`. Como cada sweep_hit contiene un componente o un volumen, puedes consultar TargetComponent o TargetVolume para saber de qué tipo es. En este caso, el código obtiene la Entidad propietaria del TargetComponent y la devuelve como una opción, lo que significa que devolverá `true` si el barrido golpea un componente y false en caso contrario.
# Returns the first Entity hit by FindSweepHits
FindFirstSweepHit(InEntity:entity, DisplacementVector:vector3):?entity =
for (SweepHit : InEntity.FindSweepHits(DisplacementVector)):
return option{ SweepHit.TargetComponent.Entity }
return falseSecuencia de comandos completa
A continuación se muestra la secuencia de comandos completa para consultar los aciertos de barrido.
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
using { /Verse.org/Colors }
using { /Verse.org/SceneGraph/KeyframedMovement }
using { /Verse.org/SpatialMath }
using { /Fortnite.com/Game }
using { /Fortnite.com/Devices }