Scene Graph ofrece varias formas de crear un juego flexible y dinámico a través de las diferentes interacciones entre las entidades y los 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 usar eventos de componentes y consultas para crear comunicación entre entidades y construir elementos de juego reutilizables.
Cómo generar y eliminar prefabricados
Por ejemplo, echa un vistazo a la plataforma interactiva del segundo pasillo. Cuando el jugador pisa la plataforma, se añade una linterna prefabricada a la escena y se elimina cuando el jugador sale 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. Luego, 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 del activador en el nivel.
SpawnPrefabDevice := class(creative_device):
@editable
TriggerVolume:volume_device = volume_device{}Cuando comienza el juego, el dispositivo define un nuevo prefabricado de postes de luz para generar, así como la posición para generarlo.
OnBegin<override>()<suspends>:void =
PrefabToSpawn:entity = LightPost.P_LightPost{}
SpawnTransform:transform = transform:
Translation := vector3:
Left := -9084.0
Up := -8.0
Forward := -919.0Luego, obtiene la entidad de simulación y crea una serie de contextos de fallo para trabajar. Primero utiliza un bucle para ejecutar el código dentro repetidamente, seguido de una carrera entre dos instrucciones de bloque.
if:
SimulationEntity := GetSimulationEntity[]
then:
loop:
race:
block:
TriggerVolume.AgentEntersEvent.Await()
SimulationEntity.AddEntities(array{ PrefabToSpawn })
PrefabToSpawn.SetGlobalTransform(SpawnTransform)
La primera declaración de bloque espera a que un agente ingrese al dispositivo de volumen. Cuando lo hace, añade el prefabricado de farol a la escena con AddEntities() y lo posiciona correctamente con SetGlobalTransform(). El segundo bloque espera a que el agente abandone el volumen y elimine el prefabricado de su base, en este caso, la entidad de simulación.
Dado que estos bloques se mueven en bucle, cada uno de ellos está siempre en funcionamiento, de modo que el jugador puede 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):
Superposiciones de entidades
La segunda sala también tiene una serie de ejemplos que muestran algunas de las diferentes formas en que las entidades pueden interactuar. Por ejemplo, se puede alertar a las entidades con un componente de malla cuando se superponen con otra entidad a través de EntityEnteredEvent y EntityExitedEvent del componente de malla. Echa un vistazo al ejemplo de ovni en la segunda sala para ver esta funcionalidad en acción.
Cuando comienza el juego, la vaca reproduce una animación para levantarse como si el ovni la secuestrara. La vaca utiliza el EntityEnteredEvent del componente malla para saber cuándo se superpone con el ovni y, luego, se define como invisible para que parezca que ha 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 para 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 administrador de rondas de Fortnite que puedes usar 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)Luego, en OnRoundStarted(), la secuencia de comandos comienza estableciendo StartTransform en la transformación global de la entidad y, luego, suscribe el EntityEnteredEvent del componente de malla a una nueva función OnEntityEntered(), que se activará cada vez que otra malla se superponga con la entidad. Luego, genera una función PlayCowAbductionAnimation() para comenzar 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 define la transformación global de la vaca en su transformación inicial y espera un breve período de tiempo. Luego, obtiene los componentes de malla y movimiento de fotograma clave de la entidad, habilita la malla para hacer visible la vaca, luego define 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()Finalmente, la función OnEntityEntered() se utiliza para ejecutar código cada vez que la vaca se superpone a otra entidad, en este caso el ovni. Cuando lo hace, obtiene de nuevo la malla y los componentes de movimiento de los 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 para que parezca que ha sido abducida. Luego, genera una nueva instancia de PlayCowAbductionAnimation() para comenzar de nuevo 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 de vaca con una malla de 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 impactos por superposición
Las entidades también pueden consultar por otras entidades mediante las consultas superpuestas. En lugar de detectar cuando una entidad entra o sale de una malla en particular, las consultas de superposición se pueden utilizar para devolver cada entidad y componente que se superponen en un área en particular.
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. Luego, devuelve una lista de overlap_hit. Cada overlap_hit te brinda información sobre el componente o volumen superpuesto por el volumen de origen, y puedes consultar estos componentes para encontrar su entidad asociada.
Por ejemplo, intenta pisar la plataforma interactiva 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 superposición. Si el volumen de colisión se superpone a 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 a simular, suscribe la función OnRoundStarted() al inicio de ronda del administrador de rondas. De manera similar, la función OnRoundStarted() solo 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á abduciendo una vaca en ese momento, se llama a la función OnTriggerEntered() para pausar cualquier movimiento que el OVNI pueda estar realizando al recuperar su keyframed_movement_component y llamar a Pause(). Luego llama a EnableAbductionBeam() y PerformOverlapCheck() para habilitar el rayo de abducción y verificar 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 verificar las superposiciones se almacena en la función PerformOverlapCheck(). Para simular un rayo de abducción, esta función genera una cápsula de colisión y define un 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 el volumen para verificar las colisiones y la CollisionTransform como el lugar desde el que simular esa colisión. Luego, itera a través de cada superposición y verifica si el componente superpuesto era un componente de malla, específicamente la malla SM_Toy_Cow de la entidad vaca. Si es así, genera una función AbductCow() que pasa 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 de vaca de manera similar al ejemplo de superposición de entidades anterior. Debido a que este código se llama desde la entidad de ovni y no desde la vaca, el código necesita obtener componentes de la entidad de vaca y, luego, pasar una animación para que se reproduzca. Comienza obteniendo los componentes de movimiento de la malla y los fotogramas clave de la vaca y, luego, establece IsAbducting en verdadero.
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 = trueDebido a que los fotogramas clave utilizados en la animación de abducción de la vaca no están definidos en el esquematizador, el código debe construirlos según 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, luego, construye un nuevo keyframed_movement_delta a partir de esos valores. A continuación, define ese fotograma clave único como una matriz en el componente de movimiento de fotogramas clave y llama a play 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 hacia el ovni cuando está siendo abducida, pero el código también debe hacer que desaparezca cuando se superpone al propio ovni. Para hacer esto, 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 comenzar a patrullar nuevamente, por lo que el código llama a la reproducción en el componente de movimiento de 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]
Finalmente, las funciones EnableAdbuctionBeam() y DisableAbductionBeam() actúan como simples ayudantes que encienden y apagan la malla del haz de abducción y los componentes de luz focal en el ovni, respectivamente, cada vez que se los 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 impactos por superposición.
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 impactos de barrido
Los impactos de barrido proporcionan otra forma importante de consultar las superposiciones entre entidades. El barrido se refiere a mover un objeto sobre una distancia definida a lo largo de un vector particular. Por ejemplo, mover un bloque a través de una plataforma para empujar a los jugadores hacia un hueco o lanzar un misil hacia adelante para destruir una pared.
La función FindSweepHits() devuelve una lista de sweep_hit. Cada sweep_hit ofrece la misma información que un overlap_hit, como el componente o volumen tocado, y el volumen o componente de origen que realiza el barrido. También proporciona información sobre la posición del contacto, la normal, la normal de la cara y la distancia a lo largo del barrido donde ocurrió el impacto.
La plantilla utiliza impactos de barrido para construir una versión más avanzada del ejemplo anterior de aciertos superpuestos. Intenta subir a la plataforma interactiva final en la segunda sala para ver este ejemplo. Cuando pisas la plataforma, el ovni genera un rayo de abducción. A continuación, realiza un barrido desde la malla del ovni hacia abajo, verificando la primera entidad con la que se superpone el barrido. Si la entidad es una vaca, el ovni la abducirá con normalidad. Sin embargo, si la vaca está protegida por una entidad globo, el barrido golpeará primero el globo y será bloqueado, lo que impedirá 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 impactos por superposición, con la misma lógica utilizada para abducir a la vaca y habilitar y deshabilitar el rayo de abducción. La principal diferencia radica en la función OnTriggerEntered(), que se ejecuta cuando el jugador pisa la plataforma interactiva frente al ejemplo.
El código para esta función comienza de manera similar al ejemplo de impactos por superposición, obteniendo el componente de movimiento con fotogramas clave de la entidad y activando el rayo 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, dado que la función utiliza barridos en lugar de superposiciones, la lógica de si la vaca está bajo el haz de abducción es un poco diferente. Comienza obteniendo el primer elemento derivado de la entidad de ovni, en este caso, la entidad de malla del ovni. A continuación, crea un vector de desplazamiento desde el que realizar 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}Luego, 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 que se va a barrer y el vector de desplazamiento con el que se va a barrer. Llama a FindSweepHits() para simular un barrido y, luego, itera a través de cada impacto de barrido devuelto en una expresión `for`. Dado que 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 impacta un componente y, en caso contrario, `false`.
# 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 de Consulta de impactos 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 }