Ce tutoriel est une version avancée propre à Scene Graph du tutoriel Animer les mouvements des accessoires. Si vous souhaitez en savoir plus concernant le déplacement basé sur l'animation dans l'UEFN en dehors de Scene Graph, consultez ce tutoriel, puis revenez à celui-ci.
Les plateformes mobiles sont communes à la plupart des jeux de plateforme, et mettent le joueur au défi d'effectuer des sauts précis entre les cibles pour atteindre l'objectif.
Il y a plusieurs façons de déplacer des accessoires dans l'UEFN. Vous pouvez utiliser des fonctions comme TeleportTo[] ou MoveTo() pour modifier une transformation directement ou utiliser un autre appareil comme un déplaceur d'accessoire pour déplacer un accessoire sur une trajectoire prédéfinie. Cependant, il existe une autre option utile sous la forme d'animations.
Les animations présentent certains avantages par rapport à la transformation de l'accessoire. Les animations ont généralement des mouvements plus fluides que les objets déplacés avec MoveTo() ou TeleportTo(), car elles évitent la latence réseau liée à l'appel de ces fonctions à chaque tick de jeu.
Les animations ont également des collisions plus cohérentes avec les joueurs ou les autres objets, et vous avez un plus grand niveau de contrôle sur l'endroit et la manière dont un objet se déplace par rapport à l'utilisation d'un déplaceur d'accessoire. Vous pouvez jouer des animations en boucle, ou les jouer dans les deux sens avec le mode ping-pong.
Les animations vous permettent également de choisir un type d'interpolation. Le type d'interpolation détermine le type d'assouplissement, ou courbe d'animation, que suit votre animation. Par exemple, le type d'interpolation linéaire joue votre animation à une vitesse constante, tandis que le type d'interpolation progressive commence lentement, puis accélère vers la fin.
En choisissant le bon type d'interpolation pour votre animation, vous pouvez spécifier à différents moments si l'accessoire doit ralentir, accélérer ou se déplacer de manière linéaire. En appliquant un composant pour mettre en œuvre ces comportements sur les entités de votre niveau, vous pouvez créer des plateformes mobiles sur lesquelles vos joueurs peuvent se déplacer.
Tout d'abord, réfléchissez aux types de comportements que vous souhaitez que votre plateforme mobile adopte. Celle-ci doit commencer à s'animer à partir d'une position de départ donnée, puis se déplacer vers plusieurs points. Lorsqu'elle atteint la fin de son mouvement, elle doit pouvoir soit revenir à sa position de départ, soit rester en place.
Il doit effectuer ces mouvements sur une durée spécifique et pouvoir pivoter et changer d'échelle convenablement à chaque point de son déplacement. Bien que chacun de ces comportements nécessite son propre code, vous pouvez partir d'une classe simple et la développer en vue d'itérer rapidement différentes idées. Suivez ces étapes pour créer un composant de déplacement basé sur l'animation.
Créez un nouveau composant Verse nommé
animate_to_targets_componentet ouvrez-le dans Visual Studio Code. Pour en savoir plus sur la création de vos propres composants Verse, consultez la rubrique Créer votre propre composant Verse. Ajoutez des instructionsusingpour/Verse.org/SpatialMath,/Verse.org/SceneGraph/KeyframedMovement, et/UnrealEngine.com/Temporary/SpatialMath. Vous aurez besoin de leurs fonctions plus tard.Verseusing { /Verse.org } using { /Verse.org/Native } using { /Verse.org/SceneGraph } using { /Verse.org/Simulation } using { /Verse.org/SpatialMath } using { /Verse.org/SceneGraph/KeyframedMovement } using { /UnrealEngine.com/Temporary/SpatialMath } # Place this component to an entity to move between preset targets. animate_to_targets_component<public> := class<final_super>(component):Les info-bulles de l'outil utilisées dans cette section du tutoriel sont incluses ci-dessous. Vous pouvez les copier-coller au-dessus de votre définition de classe
animate_to_targets_component.Verse# Editor Tool Tips DefaultSpeedTip<localizes><public>:message = "Default speed simulation entity moves during any segment that does not specify a speed." SpeedTip<localizes><public>:message = "Speed simulation entity moves during this segment." AnimationDurationTip<localizes><public>:message = "The duration of the animation segment in seconds." EasingFunctionTip<localizes><public>:message = "Movement cubic-bezier easing function during this segment." DefaultEasingFunctionTip<localizes><public>:message = "Default movement cubic-bezier easing function during any segment that does not specify an easing function." PlaybackModeTip<localizes><public>:message = "Animation playback mode\n\tOneshot: Animation plays once.\n\tPingPong: Animation plays in order and reverse order repeating.\n\tLoop: Animation repeats in a loop. Tip: To construct an animation in a closed loop, make the last segment starting position the same as the first segment starting position." TargetsTip<localizes><public>:message = "Entities that are targets for the parent entity." RandomizeTargetsTip<localizes><public>:message = "Randomize the order of the segments.\n\tNever: Always use the order specified.\n\tOnBegin: Only randomize the order on begin simulation.\n\tEveryIteration: Randomize the order of the segments every loop iteration." PauseTip<localizes><public>:message = "Duration simulation entity pauses at the beginning of this segment."Ajoutez les champs suivants à votre définition de classe
animate_to_targets_component:Variable à float modifiable nommée
InitialPauseSeconds. Il s'agit du temps nécessaire avant que l'entité commence à s'animer. Définissez cette valeur sur10,0pour que l'entité attende dix secondes avant de commencer à s'animer.
Verse# Amount of time to pause before the animation starts. @editable_number(float): ToolTip := SpeedTip MinValue := option{0.0} var InitialPauseSeconds<public>:float = 10.0keyframed_movement_playback_modemodifiable nomméAnimationPlaybackMode. Il s'agit du mode d'animation pour l'animation de l'entité. À définir surloop_keyframed_movement_playback_mode. Cela signifie que, par défaut, lorsque l'animation est terminée, l'animation de l'entité reprend depuis le début.
Verse# The playback mode used by this animation. @editable: ToolTip := PlaybackModeTip var PlaybackMode<public>:keyframed_movement_playback_mode = loop_keyframed_movement_playback_mode{}Enregistrez votre code et compilez-le.
Diviser des animations en segments
Pour créer des animations dans le code, vous utiliserez des images clés. Les animations sont constituées d'une ou plusieurs images clés, et chaque image clé spécifie les valeurs d'un objet à des moments précis de l'animation. En créant une animation à l'aide d'images clés, vous pouvez spécifier plusieurs points de déplacement, de rotation et de changement d'échelle pour votre accessoire.
Le keyframed_movement_component utilise un keyframed_movement_delta comme type d'image clé. Ces deltas de déplacement sont dotés de trois valeurs :
Transformation: spécifie les modifications de transformation par rapport à l'image clé précédente.Durée: durée de l'image clé, en secondes.Accélération: la fonction d'accélération à utiliser à la lecture de cette image clé.
Le keyframed_movement_component prenant une matrice d'images clés avant de les lire, vous devez fournir toutes les images clés à la fois pour chaque animation que vous souhaitez lire. Il y a deux façons de procéder :
Vous pouvez créer une matrice de plusieurs images clés dans le code, puis la transmettre au composant de mouvement d'images clés et jouer une seule animation.
Vous pouvez créer plusieurs matrices contenant une seule image clé et les transmettre individuellement au composant de mouvement d'images clés pour jouer plusieurs animations en séquence.
Ces deux options présentent des avantages et des inconvénients. Les matrices d'images clés uniques vous permettent d'effectuer plus facilement des opérations entre les images clés, mais nécessitent plus de code. Créer toutes les images clés en une seule fois facilite la gestion, mais rend plus difficile l'exécution d'opérations pendant la lecture de l'animation. Le tutoriel Animer les mouvements des accessoires et le présent tutoriel couvrent tous deux la première approche, mais une implémentation de la deuxième approche sera également fournie.
Pour créer des images clés individuelles dans le code, vous allez définir une classe de segment. Chaque segment représentera une image clé utilisée par le keyframed_movement_component que vous pouvez créer à partir de l'éditeur. Vous pourrez également inclure des données supplémentaires, telles que le temps d'attente entre chaque image clé. Procédez comme suit pour créer votre classe de segment.
Ajoutez une nouvelle classe nommée
segmentà votre fichieranimate_to_targets_component.verse. Ajoutez le spécificateur<concrete>pour que cette classe puisse être utilisée comme valeur@editable.Verse# Defines a segment of animation, which includes a starting position, animation speed and duration, and easing function. # Each segment acts as a single animation, and multiple segments make up an animation sequence. segment<public> := class<concrete>:Ajoutez les champs suivants à votre définition de classe de segment :
Une option d'
entitémodifiable nomméeSegmentStartPosition. Cette entité servira de référence à la position dans le monde à partir de laquelle l'entité doit commencer l'animation.
Verse# An entity that represents the starting position of this entity during the animation segement. @editable: ToolTip := SourceTip SegmentStartPosition:?entity = falseUn
floatmodifiable nomméAnimationDuration. Il s'agit de la durée de lecture de ce segment d'animation. Définissez cette valeur sur2,0afin que la lecture de chaque segment d'animation prenne deux secondes.
Verse# The duration of the animation segment. @editable: ToolTip := AnimationDurationTip AnimationDuration:float = 2.0Une option de fonction d'accélération modifiable nommée
EasingFunction. Il s'agit de la fonction d'accélération utilisée pendant ce segment de l'animation.
Verse# The easing function to use during this segment of animation. @editable: ToolTip := EasingFunctionTip EasingFunction:?easing_function = falseChaque fonction d'adoucissement est définie par une courbe de Bézier cubique, composée de quatre nombres qui créent le type de fonction d'adoucissement utilisé par l'animation. Par exemple, les paramètres d'une courbe d'assouplissement ralentissent l'animation au début et l'accélèrent ensuite.
Les paramètres d'une courbe linéaire permettent à l'animation de se dérouler à une vitesse constante. Vous pouvez définir ces valeurs vous-même pour créer vos propres courbes d'animation personnalisées, mais vous n'en avez pas besoin dans cet exemple puisque vous utiliserez celles définies dans le module
KeyframedMovement.Une option à float modifiable nommée
PauseSeconds, correspondant au temps en secondes à attendre avant de démarrer ce segment d'animation. Vous pouvez l'envisager comme le temps de pause d'une entité avant de passer à chaque point de son chemin.
Verse# The number of seconds to pause before starting this animation segment. @editable: ToolTip := PauseTip PauseSeconds:?float = falseDe retour dans la définition de votre classe
animate_to_targets_component, ajoutez les champs suivants :Une matrice modifiable de
segmentnommée Segments. Elle référencera chaque segment d'animation qui compose l'animation globale que votre entité traverse.
Verse# Segments of the keyframed movement animation. @editable: ToolTip := SegmentsTip var Segments<private>:[]segment = array{}Une
fonction d'accélérationmodifiable nomméeDefaultEasingFunction. Celle-ci sera utilisée par défaut lorsqu'un segment d'animation ne précisera aucune fonction d'accélération. Définissez-la en tant queease_in_out_cubic_bezier_easing_function.
Verse# Movement easing function between two targets @editable: ToolTip := DefaultEasingFunctionTip var DefaultEasingFunction<public>:easing_function = ease_in_out_cubic_bezier_easing_function{}Enregistrez votre code et compilez-le. Dans l'éditeur, vous devriez voir la matrice
Segmentsapparaître sur les entités auxquelles l'animate_to_targets_component est joint.
Créer des images clés avec du code
Une fois votre classe de segment terminée, vous devez créer les images clés que vos segments définissent. Vous allez créer des images clés séparément et les ajouter à une matrice, puis transmettre la matrice à votre keyframed_movement_component. Pour cela, certaines opérations mathématiques sont nécessaires, que vous allez définir maintenant.
Étant donné que les opérations mathématiques sont utiles dans divers scénarios, il est utile de placer cette logique dans un fichier utilitaire pour y accéder à partir de n'importe lequel de vos composants Verse. Pour en savoir plus sur les pratiques recommandées par Verse lorsque vous travaillez avec des entités, consultez la rubrique Créer votre propre composant Verse. Procédez comme suit pour créer votre fichier utilitaire :
Créez un nouveau module dans votre fichier
animate_to_targets.versenomméUtilitaires. cela stockera la logique commune que vous utiliserez dans votre projet.Verse# Module containing utility functions. Utilities<public> := module:Ajoutez un nouvel alias de type
vector3nomméVectorOnesà votre module Utilitaires qui crée unvector3oùLeft,UpetForwardsont tous définis sur1,0. Vous utiliserez ce vecteur plus tard pour faciliter certains calculs, et le fait de définir un alias de type pour ce vecteur vous évite d'avoir à écrirevector3{Left := 1.0, Up := 1.0, Forward := 1.0}à plusieurs reprises. Parce que vous avez importé à la fois le module/Verse.org/SpatialMathet/UnrealEngine.com/Temporary/SpatialMathmodules, vous devrez spécifier qu'il s'agit d'un/Verse.org/SpatialMathvector3puisque les deux modules incluent une définition pour celui-ci.Verse# Utility function for the identity of component-wise vector multiplication. VectorOnes<public>()<transacts>:(/Verse.org/SpatialMath:)vector3 = (/Verse.org/SpatialMath:)vector3{Left := 1.0, Up := 1.0, Forward := 1.0}Ajoutez une fonction nommée
GetDeltaTransform()à votre moduleUtilitaires. Cette fonction calculera la différence entre deux transformations et renverra le delta. Ajoutez le modificateur<transacts>à cette fonction pour permettre son annulation. Spécifiez/Verse.org/SpatialMathcomme module pour chaquetransformerpuisque vous calculerez la différence entre les transformations d'Entité.Verse# Get the delta transform between two given transforms. GetDeltaTransform<public>(TransformOne:(/Verse.org/SpatialMath:)transform, TransformTwo:(/Verse.org/SpatialMath:)transform)<transacts>:(/Verse.org/SpatialMath:)transform=Dans
GetDeltaTransform, initialisez une nouvelletransformation/Verse.org/SpatialMath. Définissez latranslationsur la différence entre la translation de chaque transformation. Définissez larotationsur le résultat de l'appel deMakeComponentWiseDeltaRotation(). Étant donné que cette fonction se trouve dans le module/UnrealEngine.com/Temporary/SpatialMath, vous devrez la convertir des rotations/Verse.org/SpatialMathen rotations/UnrealEngine.com/Temporary/SpatialMath. Vous pouvez le faire en utilisant la fonctionFromRotation(). AppelezMakeComponentWiseDeltaRotation()en passant la rotation de chaque transformation après l'avoir convertie avecFromRotation(). Convertissez ensuite le résultat de cet appel de fonction en utilisant à nouveauFromRotation()pour le reconvertir en/Verse.org/SpatialMathrotation. Enfin, définissez l'échelle sur le résultat de l'addition deVectorOnesà la différence entre la première et la deuxième échelle divisée par la première échelle. Cela garantit la bonne adaptation de votre entité lors de l'animation. Votre fonctionGetDeltaTransform()complète devrait ressembler à ceci :Verse# Get the delta transform between two given transforms. GetDeltaTransform<public>(TransformOne:(/Verse.org/SpatialMath:)transform, TransformTwo:(/Verse.org/SpatialMath:)transform)<transacts>:(/Verse.org/SpatialMath:)transform= (/Verse.org/SpatialMath:)transform: Translation := TransformTwo.Translation - TransformOne.Translation Rotation := FromRotation(MakeComponentWiseDeltaRotation( FromRotation(TransformTwo.Rotation), FromRotation(TransformOne.Rotation))) Scale := VectorOnes() + ((TransformTwo.Scale - TransformOne.Scale) / TransformOne.Scale)Enfin, ajoutez une fonction nommée
TryGetvalueOrDefault()à votre moduleUtilitaireset ajoutez-lui le modificateur<transacts>. Cette fonction prend une valeur d'optiond'un certain type et une valeur par défaut du même type, et elle renvoie la valeur par défaut ou l'élément à l'intérieur deValues'il existe. Ceci est utile lorsque vous souhaitez vérifier si une valeur dans une classe est réellement initialisée et garantit que vous renvoyez une valeur si ce n'est pas le cas. DansTryGetValueOrDefault(), vérifiez siValuecontient une valeur et renvoyez-la. Sinon, renvoyezDefault. Votre moduleUtilitiescomplet et votre fonctionTryGetValurOrDefault()devraient ressembler à ceci :Verse# Module containing utility functions. Utilities<public> := module: # Utility function for the identity of component-wise vector multiplication. VectorOnes<public>()<transacts>:(/Verse.org/SpatialMath:)vector3 = (/Verse.org/SpatialMath:)vector3{Left := 1.0, Up := 1.0, Forward := 1.0} # Get the delta transform between two given transforms. GetDeltaTransform<public>(TransformOne:(/Verse.org/SpatialMath:)transform, TransformTwo:(/Verse.org/SpatialMath:)transform)<transacts>:(/Verse.org/SpatialMath:)transform=
Une fois vos mathématiques définies, vous pouvez désormais créer vos images clés à partir du code !
Procédez comme suit pour créer vos fonctions de création d'images clés :
Ajoutez une nouvelle fonction nommée
ConstructKeyframe()à la définition de votre classeanimate_to_targets. Cette fonction prend une Entité source, une Entité de destination, une fonction d'adoucissement facultative et une durée. Il renvoie même un tableau dekeyframed_movements_delta.Verse# Construct a single keyframe that animates between the Source and Destination entity using the given easing function over a set duration. ConstructKeyframe<private>(Source:entity, Destination:entity, Easing:?easing_function, Duration:float)<transacts><decides>:[]keyframed_movement_delta=Dans
ConstructKeyframe(), obtenez d'abord les transformations des entitésSourceetDestinationen appelantGetGlobalTransform().Verse# Construct a single keyframe which animates between the Source and Destination entity using the given easing function over a set duration. ConstructKeyframe<private>(Source:entity, Destination:entity, EasingFunction:easing_function, Duration:float)<transacts><decides>:[]keyframed_movement_delta= var SourceTransform:(/Verse.org/SpatialMath:)transform = Source.GetGlobalTransform() var DestinationTransform:(/Verse.org/SpatialMath:)transform = Destination.GetGlobalTransform()Initialisez un tableau avec un seul membre de
keyframed_movement_delta. Définissez latransformationsur le résultat de l'appel deGetDeltaTransform()en transmettant les transformations source et de destination, puis définissez laduréeet l'accélérationsur les valeurs transmises à cette fonction.Votre fonction ConstructKeyframe() complète devrait ressembler à ceci :Verse# Construct a single keyframe which animates between the Source and Destination entity using the given easing function over a set duration. ConstructKeyframe<private>(Source:entity, Destination:entity, EasingFunction:easing_function, Duration:float)<transacts><decides>:[]keyframed_movement_delta= var SourceTransform:(/Verse.org/SpatialMath:)transform = Source.GetGlobalTransform() var DestinationTransform:(/Verse.org/SpatialMath:)transform = Destination.GetGlobalTransform() array: keyframed_movement_delta: Transform := Utilities.GetDeltaTransform(SourceTransform, DestinationTransform) Duration := Duration Easing := EasingFunction
Cette fonction crée des images clés individuelles, mais vous aurez besoin de plus de logique pour créer des animations complètes.
Ajoutez une nouvelle fonction nommée
ConstructAndPlayAnimations()à votre définition de classeanimate_to_targets. Cette fonction prend une matrice de segments et le mode de lecture d'animation et les utilise pour créer et lire une animation complète. Ajoutez le modificateur<suspends>à cette fonction pour lui permettre de s'exécuter de manière asynchrone.Verse# Construct and play an animation from an array of animation segments. ConstructAndPlayAnimations<private>(InSegments:[]segment, AnimationPlayback:keyframed_movement_playback_mode)<suspends>:void=Dans
ConstructAndPlayAnimations(), définissez une nouvellevariablelogique nomméeShouldBreakOutet initialisez-la àfalse. Étant donné les trois modes de lecture de mouvements par images clés, vous devrez gérer chacun d'eux individuellement. Vous utiliserez une expression debouclepour créer en continu des animations afin de gérer les modes de boucle ping-pong, mais le mode one-shot devrait sortir de la boucle dès la première itération. Assurez-vous d'avoir défini le mode de lecture unique sur l'animation, puis définissezShouldBreakOutsur true.Verse# Construct and play an animation from an array of animation segments. ConstructAndPlayAnimations<private>(InSegments:[]segment, AnimationPlayback:keyframed_movement_playback_mode)<suspends>:void= var ShouldBreakOut:logic = false # If this is a oneshot animation, break out of loop after it plays once. if (oneshot := oneshot_keyframed_movement_playback_mode[AnimationPlayback]): set ShouldBreakOut = trueEnsuite, dans une expression
if, obtenez lekeyframed_movement_componentde l'entité dans une variableKeyframedMovementComponent. Obtenez alors la transformation de départ de l'animation dans une variable nomméeStartingTransformen obtenant le premier élément de la matriceInSegments, puis sa transformation globale.Verse# Position this entity in the correct starting position. if: KeyframedMovementComponent := Entity.GetComponent[keyframed_movement_component] StartingTransform := FirstSegment := InSegments[0].SegmentStartPosition?.GetGlobalTransform()Enfin, positionnez l'Entité à son emplacement de départ en définissant sa transformer globale sur la transformer de départ, puis dormez pendant les
InitialPauseSecondsavant que l'animation ne joue.Verse# Position this entity in the correct starting position. if: KeyframedMovementComponent := Entity.GetComponent[keyframed_movement_component] StartingTransform := FirstSegment := InSegments[0].SegmentStartPosition?.GetGlobalTransform() then: Entity.SetGlobalTransform(StartingTransform) # Sleep for initial pause. Sleep(InitialPauseSeconds)Vous pouvez maintenant créer la matrice d'images clés à partir de laquelle vous créerez l'animation. Tout d'abord, initialisez un nouveau tableau de variables de
keyframed_movement_deltanomméKeyframes. Dans une expressionfor, itérez chaque segment de la matriceInSegments, en obtenant à la fois le segment et son index dans une variable locale nomméeIndex.Verse# Build the array of keyframes to play the animation from. var Keyframes:[]keyframed_movement_delta = array{} for: Index -> Segment:InSegments SourceEntity := Segment.SegmentStartPosition? DestinationEntity := InSegments[Index + 1].SegmentStartPosition?Maintenant, récupérez la fonction d’adoucissement utilisée pour cette image clé dans une variable locale nommée
adoucissementen appelantTryGetValueOrDefault(),en passantSegment.EasingFunctionetDefaultEasingFunction. Obtenez également la durée du segment d'animation dans une variable localeDurationà partir deSegment.AnimationDuration. Avec toutes vos valeurs en place, dans une expressionif, construisez l'image clé en passant chaque valeur àConstructKeyframe[]et ajoutez le résultat au tableauKeyframes. Lorsque toutes vos images clés sont créées, définissez le tableau d'images clés sur le composant de mouvement d'images clés en appelantSetKeyframes()en passant le tableauKeyframeset lePlaybackMode.Verse# Build the array of keyframes to play the animation from. var Keyframes:[]keyframed_movement_delta = array{} for: Index -> Segment:InSegments SourceEntity := Segment.SegmentStartPosition? DestinationEntity := InSegments[Index + 1].SegmentStartPosition? do: Easing := Utilities.TryGetValueOrDefault(Segment.EasingFunction, DefaultEasingFunction) Duration := Segment.AnimationDuration # Construct each keyframe and add it to the array.Une fois votre matrice d'images clés définie, il est temps de commencer à les lire. Votre animation doit s'exécuter en boucle, mais doit s'arrêter après la première itération si le mode d'animation est défini sur un seul plan. Il doit également gérer la pause à chaque image clé si le segment comporte des
PauseSeconds. Pour gérer cela, configurez une expression deboucleavec une expressionforà l'intérieur. Dans l'expressionfor, parcourez chaque image clé de la matriceKeyframes, en obtenant également l'index de chaque image clé dans une variableKeyframeIndex.VerseKeyframedMovementComponent.SetKeyframes(Keyframes, PlaybackMode) # Loop playing the animation from the keyframed_movement_component, pausing at each # keyframe for a specified duration. Will break out of the loop if the animation mode # is set to oneshot. loop: for(KeyframeIndex -> Keyframe:Keyframes):À l'intérieur de l'expression
for, obtenez le segment associé à cette image clé en l'indexant dans le tableauInSegmentsà l'aide deKeyframeIndex. Ensuite, si le segment comporte desPauseSeconds, appelezSleep()pendant cette durée. Ensuite, appelezKeyframedMovementComponent.Play(), puis attendezKeyframeReachedEventet appelezKeyframedMovementComponent.Pause(). Ce que cela fait, c'est qu'il met l'animation en pause à chaque image clé pendant une durée dePauseSeconds, avant de jouer et d'attendre l'image clé suivante et de faire une nouvelle pause. Enfin, à la fin de l'expression deboucle, vérifiez siShouldBreakOutest true et, si c'est le cas, rompez la boucle.Verse# Loop playing the animation from the keyframed_movement_component, pausing at each # keyframe for a specified duration. Will break out of the loop if the animation mode # is set to oneshot. loop: for(KeyframeIndex -> Keyframe:Keyframes): if: SegmentReached := InSegments[KeyframeIndex] then: Sleep(SegmentReached.PauseSeconds) KeyframedMovementComponent.Play()Votre fonction
ContstructAndPlayAnimations()doit ressembler à ce qui suit une fois terminée :Verse# Construct and play an animation from an array of animation segments. ConstructAndPlayAnimations<private>(InSegments:[]segment, AnimationPlayback:keyframed_movement_playback_mode)<suspends>:void= var ShouldBreakOut:logic = false # If this is a oneshot animation, break out of loop after it plays once. if (oneshot := oneshot_keyframed_movement_playback_mode[AnimationPlayback]): set ShouldBreakOut = true # Position this entity in the correct starting position.
Dans l'étape suivante, vous allez créer un préfabriqué de votre entité d'animation et l'instancier dans le niveau.