Dans cette page, nous vous expliquons comment créer un nouveau composant Scene Graph nommé trigger_component. Ce composant déclenche des actions sur les entités possédant un composant Scene Graph qui implémente l'interface déclenchable. Le composant trigger_component fournit aux agents un moyen d'interagir avec Scene Graph via un appareil volume_device. Lorsqu'un agent entre ou sort du volume_device, les événements l'AgentEnteredEvent et l'AgentExitedEvent correspondants sont signalés, et les rappels correspondants sont appelés pour exécuter des actions sur les composants et entités Scene Graph.
Dans l'image suivante, le socle blanc posé sur le sol est une entité Scene Graph avec le composant trigger_component et un appareil volume_device invisible autour du socle.
Lorsque le joueur marche sur le socle, le composant trigger_component déclenche les deux lumières les plus à droite.
Lorsque le joueur descend du socle et quitte l'appareil volume_device, les lumières restent allumées.
Pour en savoir plus sur les fonctionnalités du langage Verse utilisées sur cette page, consultez les rubriques suivantes :
Définir le composant de déclenchement
Accédez à l'explorateur Verse, faites un clic droit sur le nom du projet et choisissez Ajouter un nouveau fichier Verse au projet.
Choisissez le modèle Composant Scene Graph et remplacez le nom du composant par trigger_component.
Définissez la classe
trigger_componentet ajoutez des champs qui référencent levolume_deviceassocié, que ce composant déclenche uniquement les enfants ou tous les descendants déclenchables, et une matrice référençant tous les agents interagissant avec ce composant.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 = falseAjoutez des fonctions nommées
OnAgentEntersVolumeetOnAgentExitsVolumequi définissent ce qui se passe lorsqu'un agent entre et sort de l'appareilvolume_deviceassocié à ce composant. Lorsqu'un agent entre dans le volume, enregistrez l'agent en interaction et recherchez les entités descendantes possédant un composant qui implémente l'interfacedéclenchable, puis déclenchez le composant sur ces entités. Lorsqu'un agent entre dans le volume, supprimez l'agent en interaction de la liste des agents interagissant avec ce 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()Connectez les fonctions
OnAgentEntersVolumeetOnAgentExitsVolumeà l'appareilvolume_deviceen les enregistrant comme fonctions de rappel pourAgentEntersEventetAgentExitsEventdans la fonctionOnSimulatede ce composant.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.
Définir les composants déclenchables
Ensuite, définissez les composants qui implémentent l'interface déclenchable précédemment créée. Il s'agit de composants ajoutés aux entités Scene Graph qui sont les descendants d'une entité avec un composant puzzle_component et qui sont déclenchés par une entité ancêtre avec un composant trigger_component. Dans ce tutoriel, trois composants déclenchables différents sont définis :
triggerable_mesh_component: active/désactive la visibilité du composantmesh_componentde l'entité.triggerable_light_component: active/désactive le composantsphere_light_componentde l'entité et échange le composantmesh_componentde l'entité contre un composant avec ou sans couleur émissive, selon que la lumière est allumée ou éteinte.triggerable_movement_component: déclenche une transformation du composantmesh_componentde l'entité à l'aide du composantkeyframed_movement_component.
Ces trois composants différents partagent un grand nombre de fonctionnalités, et de nombreuses fonctions sont définies de la même manière. Pour commencer, créez un nouveau fichier Verse vide nommé TriggerableComponents.verse.
Incluez les modules suivants :
/Verse.org/SceneGraph, car ce fichier utilise des composants Scene Graph et des événements de scène.
/Verse.org/SceneGraph/KeyframedMovement, car ce fichier utilise keyframed_movement_delta.
/Verse.org/Simulation, car ce fichier utilise l'attribut @editable.
/Verse.org/SpatialMath, car ce fichier utilise les transformations Verse.
Verseusing { /Verse.org/SceneGraph } using { /Verse.org/SceneGraph/KeyframedMovement } using { /Verse.org/Simulation } using { /Verse.org/SpatialMath }Définissez les composants
triggerable_mesh_component,triggerable_light_componentettriggerable_movement_component. Tous ces composants héritent de la classe decomposantde base et implémentent l'interface déclenchable.Les trois composants implémentent les trois mêmes événements :
OnReceive: appelé lorsque ce composant reçoit un événement de scène.OnBeginSimulation: appelé lorsque le composant doit commencer la simulation.OnSimulate: appelé lorsque le composant démarre la simulation.
Ajoutez les implémentations suivantes aux trois composants.
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 beforeLes trois composants implémentent également l'interface
déclenchablePostTriggerde la même manière en envoyant un événementtriggered_eventsi le composantdéclenchableest une clé de l'énigme. Vous ne pouvez pas effectuer cette action au sein de l'interfacedéclenchableproprement dite, car Verse doit savoir quelleentitéest déclenchée, et le champEntitéfait partie de la classecomposantet n'est pas disponible pour l'interfacedéclenchablesans la dépendance supplémentaire à la classecomposant.VersePostTrigger<override>():void = if (PuzzlePiece?): Event := triggered_event: Triggered := Triggered TriggeredEntity := option{Entity} Entity.SendUp(Event)
Composant de maillage déclenchable
Le composant triggerable_mesh_component active/désactive la visibilité d'un composant mesh_component sur une entité. Il est pour cela nécessaire de fournir des remplacements pour les fonctions d'interface déclenchable suivantes :
SetInitialTriggeredStatePerformActionPerformReverseAction
L'état déclenché initial est déterminé en vérifiant si le maillage commence ou non comme étant visible dans le monde du jeu, tel que défini dans le panneau Détails du composant de maillage.
L'action du composant
triggerable_mesh_componentest de rendre le maillagemesh_componentvisible. Pour ce faire, récupérez lemesh_componentpour l'entité correspondante, définissez le maillage sur Visible, puis définissez le composanttriggerable_mesh_componentsur l'état déclenché.Verse# Determine the initial triggered state of this component SetInitialTriggeredState<override>():void= if (MeshComponent := Entity.GetComponent[mesh_component], MeshComponent.Visible?): set Triggered = trueL'action inverse du composant
triggerable_mesh_componentest de rendre le maillagemesh_componentinvisible. Pour ce faire, récupérez lemesh_componentpour l'entité correspondante, définissez le maillage sur Non visible, puis définissez le composanttriggerable_mesh_componentsur l'état non déclenché.VersePerformReverseAction<override>():void = if (MeshComponent := Entity.GetComponent[mesh_component]): if (MeshComponent.Visible?): set MeshComponent.Visible = false set Triggered = false
Composant de mouvement déclenchable
Le composant triggerable_movement_component déclenche le déplacement d'une entité d'une position vers une série d'autres positions en séquence à l'aide du composant keyframed_movement_component. Il est pour cela nécessaire de fournir des remplacements pour les fonctions d'interface déclenchable suivantes :
SetInitialTriggeredStatePerformActionPerformReverseAction
De plus, ce composant utilise certaines fonctions d'assistance :
GetMovementStates: récupère les transformations des entités enfants en définissant la série de transformations pour cette entité.MakeDeltaTransform: crée une transformation delta entre deux transformations d'entrée.ConstructKeyframeDeltas: crée une matrice d'objetskeyframed_movement_deltapour l'entrée du composantkeyframed_movement_component.SetAndPlayAnimation: attribue les images clés et lit l'animation de mouvement.
Ajoutez un float modifiable à cette classe qui détermine la durée de l'animation par images clés.
Verse@editable Duration:float = 2.0Étant donné que cette classe implémente l'interface
déclenchable, des remplacements doivent être fournis pour les fonctionsPerformActionetPerformReverseAction, car celles-ci n'ont pas d'implémentations par défaut. Dans la mesure où il n'y a pas d'état déclenché initial et où l'action est un mouvement entre des emplacements, l'état déclenché initial par défaut est défini sur false. Cette action étant effectuée par l'implémentation de base dans l'interfacedéclenchable, cette fonction ne nécessite pas de remplacement dans cette classe de composant.L'action du composant
triggerable_movement_componentconsiste à déplacer l'entité le long de la série de transformations définies par les entités enfants.VersePerformAction<override>():void = MovementStates := GetMovementStates() AnimationFrames:[]keyframed_movement_delta = ConstructKeyframeDeltas(MovementStates) SetAndPlayAnimation(AnimationFrames)L'action inverse du composant
triggerable_movement_componentconsiste à déplacer l'entité le long de la série de transformations définies par les entités enfants, dans l'ordre inverse. Cette fonction est similaire àPerformAction, hormis le fait que la matrice de transformation est dans l'ordre inverse.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)Définissez les fonctions d'assistance utilisées par ce composant. Commencez par créer une fonction nommée
GetMovementStatespour récupérer les transformations vers lesquelles ce mouvement se déplace.VerseGetMovementStates():[]transform= for (ChildEntity : Entity.FindDescendantEntities(entity), Entity = ChildEntity.GetParent[]): ChildEntity.GetGlobalTransform()Définissez une fonction d'assistance nommée
MakeDeltaTransformqui construit une transformation delta entre deux transformations. Une transformation delta, D, de la transformation A à la transformation B est la transformation de sorte que, lorsque la transformation D est appliquée à la transformation A, le résultat est la transformation B.Pour approfondir, supposons que vous ayez une entité Scene Graph avec la transformation actuelle A, mais que vous souhaitiez changer l'échelle, faire pivoter et translater votre entité pour obtenir la transformation B. La transformation delta D est la transformation dont vous avez besoin pour qu'un
keyframed_movement_deltaanime le mouvement de votre entité de la transformation A à la transformation 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.UpDéfinissez une classe d'assistance nommée
ConstructKeyframeDeltaqui crée une matrice d'objetskeyframed_movement_deltapour l'entrée dans l'animationkeyframed_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):Créez une fonction nommée
SetAndPlayAnimationqui attribue la matricekeyframed_movement_deltaà l'animationkeyframed_movement_componentet la lit.VerseSetAndPlayAnimation<private>(Frames:[]keyframed_movement_delta):void = if (KeyframedMovementComponent := Entity.GetComponent[keyframed_movement_component]): KeyframedMovementComponent.SetKeyframes(Frames, oneshot_keyframed_movement_playback_mode{}) KeyframedMovementComponent.Play()
Composant d'éclairage déclenchable
Le composant triggerable_light_component allume et éteint une lumière. Il est pour cela nécessaire de fournir des remplacements pour les fonctions d'interface déclenchable suivantes :
SetInitialTriggeredStatePerformActionPerformReverseAction
L'état déclenché initial de la lumière est déterminé par le fait que la lumière est allumée ou non ; ainsi,
SetInitialTriggeredStatevérifie si la lumière est déjà allumée et, si c'est le cas, la définit comme déclenchée initialement.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:L'action effectuée par le composant
triggerable_light_componentconsiste à allumer la lumière et à passer à un maillage indiquant que la lumière est allumée.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 = trueL'action effectuée par le composant
triggerable_light_componentconsiste à éteindre la lumière et à définir lemesh_componentnon émissif comme visible.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
Étapes suivantes
Maintenant que tout le code a été écrit, créez votre code Verse. Ensuite, construisez des préfabriqués avec des entités et des composants de base que vous pouvez réutiliser dans l'UEFN pour créer votre expérience de jeu d'énigme.
Code 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 #>