Los faroles del tutorial de Scene Graph usan varios componentes creados con Verse para crear prefabricados dinámicos e interactivos. Esto es posible mediante la programación del movimiento y la interactividad en un componente creado con Verse.
Simulación de movimiento simple
El prefabricado de poste de luz utiliza dos componentes diferentes para simular el movimiento del farol. Ambos se adjuntan a la entidad Pivot, que ofrece un punto de pivote para mover el farol. Primero, el keyframed_movement_component te permite crear animaciones a partir de fotogramas clave y, luego, reproducirlos para animar una entidad. Sin embargo, este componente no puede actuar solo y necesita otro fragmento de código para proporcionar los fotogramas clave e iniciar la animación. Aquí es donde entra en juego el simple_movement_component personalizado. Esta secuencia de comandos se reutiliza en todo el proyecto para controlar cómo se mueven los diferentes objetos del juego en la escena.
Para obtener más información sobre el uso de animaciones para mover objetos, consulta Cómo animar el movimiento de utilería.
Echemos un vistazo al simple_movement_component. Abre la secuencia de comandos SimpleMovementComponent.verse desde el explorador de Verse en Visual Studio Code para empezar.
Las animaciones utilizan diferentes modos de reproducción para definir qué debe hacer la animación cuando se completa. Estos se definen en la parte superior del archivo en la enum movement_mode:
Una toma: el objeto deja de moverse cuando termina la animación.
Bucle: el objeto reinicia la animación desde el principio cuando llega al final.
Ping Pong: el objeto reproduce la animación a la inversa, yendo y viniendo desde el principio hasta el final.
movement_mode<public> := enum:
OneShot
Loop
PingPongLa clase basic_movement_component también define las variables necesarias para crear animaciones. Cada uno de estos tiene el atributo @editable para que puedas editarlos desde el esquematizador:
Fotogramas clave: la matriz dekeyframed_movement_deltautilizada para construir la animación. Cada uno rastrea el cambio en la transformación en este fotograma clave en particular, la duración del fotograma clave y el tipo de suavizado de movimiento usado.Reproducción automática: unavariable lógicaque dicta si la entidad debe animarse cuando comienza la simulación.MovementMode: el comportamiento de movimiento que exhibe la entidad.
# A Verse-authored component that can be added to entities
basic_movement_component<public> := class<final_super>(component):
@editable
var Keyframes<public>: []keyframed_movement_delta = array{}
@editable
var AutoPlay: logic = true
El código en OnSimulate() comienza a ejecutarse cada vez que se agrega el componente a la escena y cuando comienza el juego. Aquí, el código primero usa una breve llamada a Sleep() para asegurarse de que todas las entidades y componentes se inicialicen correctamente antes de continuar. Luego, en una expresión if, verifica si la entidad tiene un keyframed_movement_component.
Si es así, llama a la función InitializeKeyFramedMovementComponent() para definir el componente con los valores adecuados. ¿Qué sucede si la entidad no tiene un keyframed_movement_component? En ese caso, puedes crear uno dinámicamente durante el tiempo de ejecución y añadirlo a la entidad mediante la función AddComponents(). De esta manera, garantizarás que tu entidad esté definida correctamente cuando comience el juego.
OnSimulate<override>()<suspends>:void =
Sleep (0.1)
if:
KeyframedMovementComponent := Entity.GetComponent[keyframed_movement_component]
then:
InitializeKeyframedMovementComponent(KeyframedMovementComponent)
else:
NewKeyFramedMovementComponent := keyframed_movement_component { Entity := Entity }
Entity.AddComponents of array { NewKeyFramedMovementComponent }
InitializeKeyframedMovementComponent(NewKeyFramedMovementComponent)La función InitializeKeyframedMovementComponent() define el componente de movimiento de fotogramas clave con valores basados en los que asignas en el editor. Primero, crea una nueva variable keyframed_movement_playback_mode para determinar el modo de reproducción utilizado durante esta animación. Esto se inicializa con el valor oneshot_keyframed_movement_playback_mode, lo que significa que la animación se reproducirá solo una vez.
InitializeKeyframedMovementComponent(InKeyframedMovementComponent:keyframed_movement_component):void =
var PlaybackMode:keyframed_movement_playback_mode = oneshot_keyframed_movement_playback_mode{}Luego, utiliza una declaración de caso para establecer el PlaybackMode según el valor de MovementMode establecido en el editor. Cada valor de la enum MovementMode corresponde a un modo de reproducción diferente definido en el módulo SceneGraph/KeyframedMovement.
case (MovementMode):
movement_mode.OneShot =>
set PlaybackMode = oneshot_keyframed_movement_playback_mode{}
movement_mode.Loop =>
set PlaybackMode = loop_keyframed_movement_playback_mode{}
movement_mode.PingPong =>
set PlaybackMode = pingpong_keyframed_movement_playback_mode{}Por último, la función establece los fotogramas clave y el modo de movimiento en el componente de movimiento con fotogramas clave, y la animación ya está lista para reproducirse. Si la variable AutoPlay se establece en verdadero, la animación comienza inmediatamente al llamar a la función Play() del componente de movimiento con fotogramas clave.
InKeyframedMovementComponent.SetKeyframes(Keyframes, PlaybackMode)
if:
AutoPlay?
then:
InKeyframedMovementComponent.Play()De vuelta en el editor, el simple_movement_component se añade a la entidad Pivot y se establece con los siguientes valores. Ahora, cuando comience el juego, el farol comenzará a balancearse de un lado a otro.
Secuencia de comandos completa
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
using { /Verse.org/SceneGraph/KeyframedMovement }
movement_mode<public> := enum:
OneShot
Loop
Cómo interactuar con el farol
El farol puede balancearse hacia adelante y hacia atrás, pero necesitarás otra pieza para que tu jugador pueda interactuar con él. Esto se hace al adjuntar un Intratable component a la entidad Lantern y un lantern_interaction_component personalizado de Verse al poste de luz que te permite encender y apagar el farol.
Abre la secuencia de comandos LanternInteractionComponent.verse desde el explorador de Verse. Esta secuencia de comandos comienza con la importación del módulo LightPost definido en Assets.digest.verse. Aquí es donde se almacenan todos los recursos relacionados con el poste de luz, como el prefabricado. También importa el módulo LightPost.Materials para acceder a los materiales y mallas del poste de luz y del farol.
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
LightPost := module:
Materials<public> := module:
La clase lantern_interaction_component comienza definiendo una variable denominada MaterialInstance, que se inicializa en LightPost.Materials.MI_Lantern_01. Esta es la instancia de material que contiene todas las variables relacionadas con el material del farol.
lantern_interaction_component<public> := class<final_super>(component):
var MaterialInstance:LightPost.Materials.MI_Lantern_01 = LightPost.Materials.MI_Lantern_01{}En OnBeginSimulation(), la secuencia de comandos comienza por encontrar cada componente en sus entidades descendientes con un interactable_component adjunto. Debido a que lantern_interaction_component está adjunto al poste de luz, esto devolverá el interactable_component de la entidad Lantern, ya que es un descendiente del poste de luz.
OnBeginSimulation<override>():void =
(super:)OnBeginSimulation()
InteractabeleComponents := Entity.FindDescendantComponents(interactable_component)A continuación, en una expresión for, la secuencia de comandos itera a través de cada componente interactivo encontrado y suscribe su SucceededEvent a la función OnInteractFinished() que se define más adelante en este archivo. Ahora, cuando un jugador termine de interactuar con el farol, se activará OnInteractFinished().
InteractabeleComponents := Entity.FindDescendantComponents(interactable_component)
for (InteractableComponent : InteractabeleComponents):
InteractableComponent.SucceededEvent.Subscribe(OnInteractFinished)Luego, la función OnBeginSimulation() llama a FindDescendantComponents nuevamente para encontrar cada entidad que tenga un componente LightPost.SM_Lightpost_Lantern_01 adjunto. Este es el componente de malla adjunto al farol. Luego, define el componente de malla en la MaterialInstance definida anteriormente, lo que garantiza que la malla del farol se inicialice correctamente.
MeshComponents := Entity.FindDescendantComponents(LightPost.SM_Lightpost_Lantern_01)
for (MeshComponent : MeshComponents):
set MeshComponent.M_Lantern = MaterialInstanceLa función OnInteractFinished() toma al agente, o jugador, como el instigador de la interacción. Esta función simplemente llama a la función ToggleLight() para encender y apagar el farol.
La función ToggleLight() realiza la tarea más pesada en lo que respecta a encender y apagar el farol. Primero, en una expresión if, verifica si el nivel emisivo de MaterialInstance es 0.0, lo que indica que la luz está apagada. Si es así, establece el nivel emisivo en 1.0. Luego, en dos expresiones for, encuentra cada light_component y particle_system_component en las entidades descendientes y las activa llamando a Enable() y Play() respectivamente.
ToggleLight():void =
if (MaterialInstance.Emissive_Multiply = 0.0):
set MaterialInstance.Emissive_Multiply = 1.0
for:
Light : Entity.FindDescendantComponents(light_component)
do:
Light.Enable()
for:
Si la luz ya estaba encendida, la función hace lo contrario dentro del enunciado else. Establece los niveles emisivos del material en 0.0 y desactiva cualquier componente del sistema de luz y partículas en las entidades descendientes.
else:
set MaterialInstance.Emissive_Multiply = 0.0
for:
Light : Entity.FindDescendantComponents(light_component)
do:
Light.Disable()
for:
Particle : Entity.FindDescendantComponents(particle_system_component)
Las funciones de esta secuencia de comandos se combinan para hacer que el farol sea dinámico, ya que encienden y apagan varios componentes cuando un jugador interactúa con él. Ten en cuenta que mientras que el farol es el que se enciende y apaga, su entidad de poste de luz base es la que proporciona el lantern_interaction_component.
Piensa en lo que tendrías que hacer para tener un poste de luz con varias luces, encendiéndolas y apagándolas con solo presionar un botón. Dado que este código funciona buscando entidades descendientes con un tipo de componente concreto, no necesitarías un código Verse adicional para implementar esta funcionalidad. Siempre que cada entidad derivada de farol tenga un componente de luz o un componente de partículas, estarás listo para empezar.
Secuencia de comandos completa
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
LightPost := module:
Materials<public> := module: