Esta página orienta você na criação de um novo componente do Scene Graph chamado trigger_component. Esse componente aciona ações em entidades que têm um componente do Scene Graph que implementa a interface triggerable. O trigger_component oferece aos agentes uma maneira de interagir com o Scene Graph por meio de um volume_device. Quando um agente entra ou sai do volume_device, o AgentEnteredEvent e AgentExitedEvent correspondentes são sinalizados, e os retornos de chamada correspondentes são chamados para executar ações nos componentes e entidades do Scene Graph.
Na imagem a seguir, a base branca no chão é uma entidade do Scene Graph com o trigger_component e um volume_device invisível ao redor da base.
Quando o jogador pisa na base, o trigger_component aciona as duas luzes mais à direita.
Quando o jogador pisa fora da base e sai do volume_device, as luzes permanecem no estado aceso.
Para obter mais informações sobre as funcionalidades da linguagem Verse usadas nesta página, consulte:
Defina o componente de gatilho
Acesse o Explorador Verse, clique com o botão direito do mouse no nome do projeto e escolha Adicionar novo arquivo Verse ao projeto.
Escolha o modelo Componente do Scene Graph e altere o Nome do Componente para trigger_component.
Defina a classe
trigger_componente adicione campos que referenciam ovolume_deviceassociado, se esse componente aciona apenas filhos ou todos os descendentes acionáveis e uma matriz que faz referência a todos os agentes que interagem com esse 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 = falseAdicione funções chamadas
OnAgentEntersVolumeeOnAgentExitsVolumeque definem o que acontece quando um agente entra e sai dovolume_deviceassociado desse componente. Quando um agente entrar no volume, registre o agente que interage e procure as entidades descendentes que tenham um componente que implementa a interfacetriggerablee acione o componente nessas entidades. Quando um agente entrar no volume, remova o agente de interação da lista de agentes que interagem com esse volume.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()Conecte as funções
OnAgentEntersVolumeeOnAgentExitsVolumeaovolume_deviceregistrando-as como as funções de retorno de chamada paraAgentEntersEventeAgentExitsEventna funçãoOnSimulatedesse 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.
Defina os componentes acionáveis (triggerable)
Em seguida, defina os componentes que implementam a interface triggerable criada anteriormente. São os componentes adicionados às entidades do Scene Graph que são descendentes de uma entidade com um puzzle_component e são acionados por uma entidade ancestral com um trigger_component. Este tutorial define três componentes triggerable diferentes:
triggerable_mesh_component: alterna a visibilidade domesh_componentda entidade.triggerable_light_component: alterna osphere_light_componentda entidade e troca omesh_componentda entidade por um com ou sem cor emissiva, dependendo se a luz está acesa ou apagada.triggerable_movement_component: aciona uma transformação domesh_componentda entidade usando okeyframed_movement_component.
Esses três componentes diferentes compartilham um grande número de funcionalidades, e muitas das funções são definidas da mesma maneira. Para começar, crie um novo arquivo Verse vazio chamado TriggerableComponents.verse.
Inclua os seguintes módulos:
/Verse.org/SceneGraph, pois este arquivo usa componentes do Scene Graph e Eventos de Cena.
/Verse.org/SceneGraph/KeyframedMovement, pois este arquivo usa keyframed_movement_delta.
/Verse.org/Simulation, pois este arquivo usa o atributo @editable.
/Verse.org/SpatialMath, pois este arquivo usa transformações Verse (transforms).
Verseusing { /Verse.org/SceneGraph } using { /Verse.org/SceneGraph/KeyframedMovement } using { /Verse.org/Simulation } using { /Verse.org/SpatialMath }Defina os componentes
triggerable_mesh_component,triggerable_light_componentetriggerable_movement_component. Todos esses componentes herdam da classecomponentbase e implementam a interface acionável.Todos os três componentes implementam os mesmos três eventos:
OnReceive: chamado quando o componente recebe um Evento de Cena.OnBeginSimulation: chamado quando o componente deve iniciar a simulação.OnSimulate: chamado quando o componente inicia a simulação.
Adicione as seguintes implementações a todos os três 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 beforeTodos os três componentes também implementam a substituição de
PostTriggerda interfacetriggerableda mesma maneira, enviando umtriggered_eventse o componentetriggerablefor uma peça de quebra-cabeça. Não é possível fazer isso dentro da própria interfacetriggerable, porque a linguagem Verse precisa saber qualentityé acionada, e o campoEntityfaz parte da classecomponente não está disponível para a interfacetriggerablesem a dependência adicional da classecomponent.VersePostTrigger<override>():void = if (PuzzlePiece?): Event := triggered_event: Triggered := Triggered TriggeredEntity := option{Entity} Entity.SendUp(Event)
Componente de malha acionável
O triggerable_mesh_component alterna a visibilidade de um mesh_component em uma entidade. Isso requer o fornecimento de substituições para as seguintes funções de interface triggerable:
SetInitialTriggeredStatePerformActionPerformReverseAction
O estado inicial é determinado verificando se a malha começa visível ou não no mundo do jogo, conforme definido no painel de detalhes do componente de malha.
A ação para
triggerable_mesh_componenté tornar a malhamesh_componentvisível. Para fazer isso, recupere omesh_componentpara a entidade correspondente, defina a malha como visível e, em seguida, definatriggerable_mesh_componentpara o estado acionado.Verse# Determine the initial triggered state of this component SetInitialTriggeredState<override>():void= if (MeshComponent := Entity.GetComponent[mesh_component], MeshComponent.Visible?): set Triggered = trueA ação inversa para o
triggerable_mesh_componenté tornar a malha domesh_componentinvisível. Para fazer isso, recupere omesh_componentpara a entidade correspondente, defina a malha como não visível e, em seguida, definatriggerable_mesh_componentpara o estado não acionado.VersePerformReverseAction<override>():void = if (MeshComponent := Entity.GetComponent[mesh_component]): if (MeshComponent.Visible?): set MeshComponent.Visible = false set Triggered = false
Componente de movimento acionável
O triggerable_movement_component aciona uma entidade para se mover de um local para uma série de outros locais em sequência usando o keyframed_movement_component. Isso requer o fornecimento de substituições para as seguintes funções de interface triggerable:
SetInitialTriggeredStatePerformActionPerformReverseAction
Além disso, esse componente usa algumas funções auxiliares:
GetMovementStates: recupera transformações de entidades filhas definindo a série de transformações para a entidade.MakeDeltaTransform: cria uma transformação delta entre duas transformações de entrada.ConstructKeyframeDeltas: cria uma matriz de objetoskeyframed_movement_deltapara a entrada dokeyframed_movement_component.SetAndPlayAnimation: atribui os keyframes e reproduz a animação de movimento.
Adicione um float editável a essa classe que determina quanto tempo dura a animação do keyframe.
Verse@editable Duration:float = 2.0Como essa classe implementa a interface
triggerable, é necessário fornecer substituições para as funçõesPerformActionePerformReverseAction, pois elas não têm implementações padrão. Como não há estado de acionamento inicial e a ação é um movimento entre locais, o estado de acionamento inicial padrão é falso. Isso é o que a implementação base faz na interfacetriggerable, portanto, essa função não requer uma substituição nessa classe de componente.A ação para o
triggerable_movement_componenté mover a entidade ao longo da série de transformações definidas pelas entidades filhas.VersePerformAction<override>():void = MovementStates := GetMovementStates() AnimationFrames:[]keyframed_movement_delta = ConstructKeyframeDeltas(MovementStates) SetAndPlayAnimation(AnimationFrames)A ação inversa para o
triggerable_movement_componenté mover a entidade ao longo da série de transformações definidas pelas entidades filhas na ordem inversa. Essa função é semelhante àPerformAction, exceto que a matriz de transformação está na ordem inversa.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)Defina as funções auxiliares que esse componente usa. Primeiro, crie uma função chamada
GetMovementStatespara recuperar as transformações para as quais esse movimento se move.VerseGetMovementStates():[]transform= for (ChildEntity : Entity.FindDescendantEntities(entity), Entity = ChildEntity.GetParent[]): ChildEntity.GetGlobalTransform()Defina uma função auxiliar chamada
MakeDeltaTransformque cria uma transformação delta entre duas transformações. Uma transformação delta, D, da transformação A para a transformação B é a transformação tal que quando a transformação D é aplicada à transformação A, o resultado é a transformação B.Para exemplificar, suponha que você tenha uma entidade do Scene Graph com a transformação A atual, mas deseja escalar, girar e transladar sua entidade para alcançar a transformação B. A transformação delta D é a transformação necessária para um
keyframed_movement_deltaanimar o movimento da sua entidade da transformação A para a transformação 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.UpDefina um auxiliar chamado
ConstructKeyframeDeltaque cria uma matriz de objetoskeyframed_movement_deltapara a entrada da animaçãokeyframed_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):Crie uma função chamada
SetAndPlayAnimationque atribui a matrizkeyframed_movement_deltaà animaçãokeyframed_movement_componente a reproduz.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 acionável
O triggerable_light_component acende e apaga uma luz. Isso requer o fornecimento de substituições para as seguintes funções de interface triggerable:
SetInitialTriggeredStatePerformActionPerformReverseAction
O estado de acionamento inicial da luz é determinado pelo fato de a luz estar acesa ou não, portanto, o
SetInitialTriggeredStateverifica se a luz já está acesa e, se estiver, define o estado como acionado 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:A ação executada pelo
triggerable_light_componenté acender a luz e alternar para uma malha indicando que a luz está acesa.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 = trueA ação executada pelo
triggerable_light_componenté apagar a luz e definir omesh_componentnão emissivo como visível.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
Próximas etapas
Agora que todo o código Verse foi escrito, compile-o. Em seguida, construa estruturas pré-fabricadas com entidades e componentes básicos que você possa reutilizar no UEFN para criar sua própria experiência de quebra-cabeça.
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 #>