Esta página te guía a través de la creación de un nuevo componente de Scene Graph denominado trigger_component. Este componente activa acciones en entidades que tienen un componente de Scene Graph que implementa la interfaz activable. El trigger_component proporciona a los agentes una forma de interactuar con Scene Graph a través de un volume_device. Cuando un agente entra o sale de volume_device, se señala el AgentEnteredEvent y el AgentExitedEvent correspondientes y se llama a las devoluciones de llamada aplicables para realizar acciones en los componentes y entidades de Scene Graph.
En la siguiente imagen, el pedestal blanco en el suelo es una entidad de Scene Graph con trigger_component y un volume_device invisible alrededor del pedestal.
Cuando el jugador pisa el pedestal, el trigger_component activa las dos luces más a la derecha.
Cuando el jugador se baja del pedestal y abandona el volume_device, las luces permanecen encendidas.
Para obtener más información sobre las funciones del lenguaje Verse utilizadas en esta página, consulta:
Cómo definir el componente de activación
Ve al Explorador de Verse, haz clic con el botón derecho en el nombre del proyecto y elige Añadir nuevo archivo de Verse al proyecto.
Elige la plantilla Componente de Scene Graph y cambia el nombre del componente a trigger_component.
Define la
clasetrigger_component y añade campos que hagan referencia alvolume_deviceasociado, independientemente de que este componente active solo los hijos o todos los descendientes activables, y una matriz que haga referencia a todos los agentes que interactúan con este componente.Versetrigger_component := class<final_super>(component): # volume_device associated with this trigger_component @editable InteractionVolume<private>:volume_device = volume_device{} # whether or not this triggers on components on child entities @editable OnlyTriggerChildren:logic = falseAñade funciones denominadas
OnAgentEntersVolumeyOnAgentExitsVolumeque definan lo que ocurre cuando un agente entra y sale delvolume_deviceasociado a este componente. Cuando un agente entre en el volumen, registra el agente que interactúa y busca entidades descendientes que tengan un componente que implemente la interfazactivabley, a continuación, activa el componente en esas entidades. Cuando un agente accede al volumen, elimina al agente que interactúa de la lista de agentes que interactúan con este volumen.Verse# Event that is triggered when an Agent enters the InteractionVolume OnAgentEntersVolume(Agent:agent):void= for: ChosenEntity : Entity.FindDescendantEntities(entity) ChosenEntityComponent : ChosenEntity.GetComponents() CastToInterface := triggerable[ChosenEntityComponent] do: if (OnlyTriggerChildren?): if (Entity = ChosenEntity.GetParent[]): CastToInterface.Trigger()Conecta las funciones
OnAgentEntersVolumeyOnAgentExitsVolumeavolume_deviceregistrándolas como funciones de devolución de llamada paraAgentEntersEventyAgentExitsEventen la funciónOnSimulatede este componente.Verse# Runs when the component should start simulating in a running game. OnBeginSimulation<override>():void = # Run OnBeginSimulation from the parent class before # running this component's OnBeginSimulation logic (super:)OnBeginSimulation() # Runs when the component should start simulating in a running game. # Can be suspended throughout the lifetime of the component. Suspensions # will be automatically cancelled when the component is disposed or the # game ends.
Cómo definir los componentes activables
A continuación, define los componentes que implementen la interfaz activable creada anteriormente. Son componentes que se añaden a entidades de Scene Graph que son descendientes de una entidad con puzzle_component y son activadas por una entidad ancestro con trigger_component. En este tutorial se definen tres componentes activables diferentes:
triggerable_mesh_component: alterna la visibilidad delmesh_componentde la entidad.triggerable_light_component: activa y desactiva elsphere_light_componentde la entidad e intercambia elmesh_componentde la entidad por uno con o sin color reflectante, dependiendo de si la luz está encendida o apagada.triggerable_movement_component: activa una transformación delmesh_componentde la entidad utilizandokeyframed_movement_component.
Estos tres componentes diferentes comparten una gran cantidad de funciones, y muchas de ellas se definen de la misma manera. Para empezar, crea un archivo de Verse nuevo y vacío llamado TriggerableComponents.verse.
Incluye los siguientes módulos:
/Verse.org/SceneGraph, ya que este archivo utiliza componentes de Scene Graph y eventos de escena.
/Verse.org/SceneGraph/KeyframedMovement, ya que este archivo utiliza keyframed_movement_delta.
/Verse.org/Simulation, ya que este archivo utiliza el atributo @editable.
/Verse.org/SpatialMath, ya que este archivo utiliza transformaciones de Verse.
Verseusing { /Verse.org/SceneGraph } using { /Verse.org/SceneGraph/KeyframedMovement } using { /Verse.org/Simulation } using { /Verse.org/SpatialMath }Define los componentes
triggerable_mesh_component,triggerable_light_componentytriggerable_movement_component. Todos estos componentes heredan de la clase delcomponentebase e implementan la interfaz activable.Los tres componentes implementan los mismos tres eventos:
OnReceive: se llama cuando este componente recibe un evento de escena.OnBeginSimulation: se llama cuando el componente debe empezar a simular.OnSimulate: se le llama cuando el componente empieza a simular.
Añade las siguientes implementaciones a los tres componentes.
Verse# Runs when this component receives a scene event OnReceive<override>(SceneEvent:scene_event):logic= if (PuzzleSolvedEvent := puzzle_solved_event[SceneEvent], not PuzzlePiece?): Trigger() true false # Runs when the component should start simulating in a running game. OnBeginSimulation<override>():void = # Run OnBeginSimulation from the parent class beforeLos tres componentes también implementan la anulación
PostTriggerde la interfazactivabledel mismo modo, enviando untrigger_eventsi el componenteactivablees una pieza del rompecabezas. No puedes hacerlo dentro de la propia interfazactivableporque Verse necesita saber quéentidadse activa, y el campoEntidadforma parte de la clase delcomponentey no está disponible para la interfazactivablesin la dependencia adicional de la clase delcomponente.VersePostTrigger<override>():void = if (PuzzlePiece?): Event := triggered_event: Triggered := Triggered TriggeredEntity := option{Entity} Entity.SendUp(Event)
Componente de malla activable
El triggerable_mesh_component activa la visibilidad de un mesh_component en una entidad. Esto requiere proporcionar anulaciones para las siguientes funciones de interfaz activables:
SetInitialTriggeredStatePerformActionPerformReverseAction
El estado activado inicial se determina comprobando si la malla comienza o no siendo visible en el mundo del juego según lo establecido en el panel de detalles del componente de la malla.
La acción de
triggerable_mesh_componentes hacer visible la mallamesh_component. Para ello, recuperamesh_componentpara la entidad correspondiente, establece la malla como visible y, a continuación, establecetriggerable_mesh_componenten el estado activado.Verse# Determine the initial triggered state of this component SetInitialTriggeredState<override>():void= if (MeshComponent := Entity.GetComponent[mesh_component], MeshComponent.Visible?): set Triggered = trueLa acción inversa para
triggerable_mesh_componentes hacer invisible la mallamesh_component. Para ello, recupera elmesh_componentde la entidad correspondiente, establece la malla como no visible y, a continuación, establecetriggerable_mesh_componenten el estado no activado.VersePerformReverseAction<override>():void = if (MeshComponent := Entity.GetComponent[mesh_component]): if (MeshComponent.Visible?): set MeshComponent.Visible = false set Triggered = false
Componente de movimiento activable
El triggerable_movement_component activa una entidad para que se mueva de una ubicación a una serie de otras ubicaciones en secuencia utilizando el keyframed_movement_component. Esto requiere proporcionar anulaciones para las siguientes funciones de interfaz activables:
SetInitialTriggeredStatePerformActionPerformReverseAction
Además, este componente utiliza algunas funciones auxiliares:
GetMovementStates: recupera las transformaciones de las entidades hijo que definen la serie de transformaciones de esta entidad.MakeDeltaTransform: crea una transformación delta entre dos transformaciones de entrada.ConstructKeyframeDeltas: crea una matriz de objetoskeyframed_movement_deltapara la entrada dekeyframed_movement_component.SetAndPlayAnimation: asigna los fotogramas clave y reproduce la animación de movimiento.
Añade un float editable a esta clase que determine la duración de la animación con fotogramas clave.
Verse@editable Duration:float = 2.0Esta clase implementa la interfaz
activable, por lo que es necesario proporcionar anulaciones para las funcionesPerformActionyPerformReverseAction, ya que no tienen implementaciones predeterminadas. Como no hay un estado inicial y la acción es un movimiento entre posiciones, el estado inicial predeterminado es falso. Esto es lo que hace la implementación base en la interfazactivable, por lo que esta función no requiere una anulación en esta clase de componente.La acción de
triggerable_movement_componentes mover la entidad a lo largo de la serie de transformaciones definidas por las entidades hijo.VersePerformAction<override>():void = MovementStates := GetMovementStates() AnimationFrames:[]keyframed_movement_delta = ConstructKeyframeDeltas(MovementStates) SetAndPlayAnimation(AnimationFrames)La acción inversa para
triggerable_movement_componentes mover la entidad a lo largo de la serie de transformaciones definidas por las entidades hijo en orden inverso. Esta función es similar aPerformAction, salvo que la matriz de transformación está en orden inverso.VersePerformReverseAction<override>():void = MovementStates := GetMovementStates() ReversedMovementStates := for: Index := 0..MovementStates.Length - 1 ReversedElement := MovementStates[MovementStates.Length - 1 - Index] do: ReversedElement AnimationFrames := ConstructKeyframeDeltas(ReversedMovementStates) SetAndPlayAnimation(AnimationFrames)Define las funciones auxiliares que utiliza este componente. Primero, crea una función nombrada
GetMovementStatespara recuperar las transformaciones a las que se mueve este movimiento.VerseGetMovementStates():[]transform= for (ChildEntity : Entity.FindDescendantEntities(entity), Entity = ChildEntity.GetParent[]): ChildEntity.GetGlobalTransform()Define una función auxiliar llamada
MakeDeltaTransformque construya una transformación delta entre dos transformaciones. Una transformación delta, D, de la transformación A a la transformación B es la transformación tal que cuando la transformación D se aplica a la transformación A, el resultado es la transformación B.Para profundizar más, supón que tienes una entidad de Scene Graph con transformación A, pero quieres escalar, rotar y trasladar tu entidad para que tenga transformación B. La transformación delta D es la transformación que necesitas para que un
keyframed_movement_deltaanime el movimiento de tu entidad desde la transformación A a la transformación B.VerseMakeDeltaTransform(InTransformOne:transform, InTransformTwo:transform):transform = transform: Translation := InTransformTwo.Translation - InTransformOne.Translation Rotation := MakeComponentWiseDeltaRotation(InTransformOne.Rotation, InTransformTwo.Rotation) Scale := vector3: Forward := InTransformTwo.Scale.Forward / InTransformOne.Scale.Forward Right := InTransformTwo.Scale.Right / InTransformOne.Scale.Right Up := InTransformTwo.Scale.Up / InTransformTwo.Scale.UpDefine un ayudante denominado
ConstructKeyframeDeltaque cree una matriz de objetoskeyframed_movement_deltapara la entrada de la animaciónkeyframed_movement_component.VerseConstructKeyframeDeltas<public>(MovementStates:[]transform):[]keyframed_movement_delta = var LastTransform:transform = Entity.GetGlobalTransform() for (EntityIndex -> CurrentTransform : MovementStates): DeltaTransform := MakeDeltaTransform(LastTransform, CurrentTransform) set LastTransform = CurrentTransform keyframed_movement_delta: Transform := DeltaTransform Duration := Duration Easing := if (MovementStates.Length > 1): if (EntityIndex = 0):Crea una función llamada
SetAndPlayAnimationque asigne la matrizkeyframed_movement_deltaa la animaciónkeyframed_movement_componenty la reproduzca.VerseSetAndPlayAnimation<private>(Frames:[]keyframed_movement_delta):void = if (KeyframedMovementComponent := Entity.GetComponent[keyframed_movement_component]): KeyframedMovementComponent.SetKeyframes(Frames, oneshot_keyframed_movement_playback_mode{}) KeyframedMovementComponent.Play()
Componente de luz activable
El triggerable_light_component enciende y apaga una luz. Esto requiere proporcionar anulaciones para las siguientes funciones de interfaz activables:
SetInitialTriggeredStatePerformActionPerformReverseAction
El estado activado inicial de la luz viene determinado por si la luz está encendida o no, por lo que
SetInitialTriggeredStatecomprueba si la luz ya está encendida y, en caso afirmativo, la establece como activada inicialmente.Verse# Determine the initial triggered state of this light SetInitialTriggeredState<override>():void= for: DescendantEntity : Entity.FindDescendantEntities(entity) Entity = DescendantEntity.GetParent[] MeshComponent := DescendantEntity.GetComponent[mesh_component] LightComponent := DescendantEntity.GetComponent[light_component] MeshComponent.IsEnabled[] LightComponent.IsEnabled[] do:La acción que realiza
triggerable_light_componentes encender la luz y cambiar a una malla que indica que la luz está encendida.VersePerformAction<override>():void= if (not IsLightOn?): for (DescendantEntity:Entity.FindDescendantEntities(entity), Entity = DescendantEntity.GetParent[]): if (MeshComponent := DescendantEntity.GetComponent[mesh_component]): if (LightComponent := DescendantEntity.GetComponent[light_component]): MeshComponent.Enable() LightComponent.Enable() else: MeshComponent.Disable() set IsLightOn = trueLa acción que realiza
triggerable_light_componentes apagar la luz y hacer visible elmesh_componentno emisor.VersePerformReverseAction<override>():void= if (IsLightOn?): for (DescendantEntity:Entity.FindDescendantEntities(entity), Entity = DescendantEntity.GetParent[]): if (MeshComponent := DescendantEntity.GetComponent[mesh_component]): if (LightComponent := DescendantEntity.GetComponent[light_component]): MeshComponent.Disable() LightComponent.Disable() else: MeshComponent.Enable() set IsLightOn = false
Siguientes pasos
Ahora que se ha escrito todo el código de Verse, vamos a compilarlo. A continuación, construye prefabricados con entidades y componentes básicos que puedas reutilizar en UEFN para crear tu experiencia de rompecabezas.
Código final
TriggerComponent.verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/SceneGraph }
using { Logging }
trigger_component<public> := class<final_super>(component):
@editable
InteractionVolume<private>:volume_device = volume_device{}
TriggerableComponents.verse
using { /Verse.org/SceneGraph }
using { /Verse.org/SceneGraph/KeyframedMovement }
using { /Verse.org/Simulation }
using { /Verse.org/SpatialMath }
EnabledToolTip<public><localizes>:message = "Whether or not this component is enabled."
triggerable_mesh_component<public> := class<final_super>(component, triggerable):
<# Triggerable interface #>