O próximo passo são objetos que se movem, giram e escalam simultaneamente. No entanto, existem alguns desafios importantes a considerar ao construir animações para adereços que se movem de várias formas ao mesmo tempo.
Como o controlador de animação só pode reproduzir uma animação por vez, você não pode mover, girar e escalar em animações diferentes. Essas animações também precisam de vários keyframes, pois você pode querer girar um adereço várias vezes por animação. Como você precisa criar todos os keyframes antecipadamente, também precisa calcular a posição, rotação e escala de cada ponto na jornada do adereço. O que acontece se o seu adereço não realiza um número inteiro de rotações? Como lidar com uma meia rotação?
Há muitos cálculos envolvidos nesta seção, mas ao final, você será capaz de mover, girar e escalar adereços até diversos pontos, e de criar desafios de plataforma complexos, dinâmicos e (o mais importante!) divertidos para criar a pista de Fall Guys dos seus sonhos.
Como criar animações que se movem, giram e são dimensionadas
Siga os passos abaixo para começar a preparação:
Crie uma nova classe Verse chamada
animating_propque herda demovable_propusando o Explorador do Verse. Adicione o especificador<concrete>a essa classe para expor suas propriedades ao UEFN.Verse# A prop that translates, rotates, and scales to a destination using animation. animating_prop<public> := class<concrete>(movable_prop):Adicione as declarações
using { /Fortnite.com/Devices/CreativeAnimation }eusing { /UnrealEngine.com/Temporary/SpatialMath }à parte superior do arquivo para importar esses módulos. Você precisará delas para animar seu adereço. Todas as dicas usadas nesta seção estão inclusas abaixo.Verseusing { /Fortnite.com/Devices } using { /Fortnite.com/Devices/CreativeAnimation } using { /Verse.org/Simulation } using { /UnrealEngine.com/Temporary/SpatialMath } RotationRateTip<localizes>:message := "The time it takes to make one AdditionalRotation in seconds." UseEasePerKeyframeTip<localizes>:message := "Whether this prop should use the MoveEaseType for each keyframe. False will use the Linear ease type on each frame." # A prop that translates, rotates, and scales to a destination using animation. animating_prop<public> := class<concrete>(movable_prop):No parte superior da definição da classe
animating_prop, adicione os seguintes campos:Uma
rotaçãoeditável chamadaAdditionalRotation. Esta é a rotação a ser aplicada aoRootProppor keyframe.Verse# The additional rotation to apply to the RootProp per keyframe. @editable {ToolTip := AdditionalRotationTip} AdditionalRotation:rotation = rotation{}Um
floateditável chamadoRotationRate. Este é o tempo necessário para realizar umaAdditionalRotation, em segundos.Verse# The time it takes to make one AdditionalRotation in seconds. @editable {ToolTip := RotationRateTip} var RotationRate:float = 1.0Uma
lógicaeditável chamadaUseEasePerKeyFrame. Determina se cada keyframe usa oMoveEaseTypepara interpolação. Neste exemplo, definir esta opção comofalseutilizará o tipo padrão de interpolação, a linear, para cada quadro.Verse# Whether this prop should use the MoveEaseType per each frame of animation. # Setting this to false will use the linear MoveEaseType on each frame. @editable UseEasePerKeyframe:logic = trueUma matriz editável de
creative_propchamadaMoveTargets. Estes são os diferentes adereços de Modo Criativo para os quais o seu adereço raiz se deslocará.Verse# The Creative prop target for the RootProp to move toward. @editable {ToolTip := MoveTargetsTip} var MoveTargets:[]creative_prop = array{}Uma variável
transformchamadaTargetTransform. Este é o transformar para o qual o seu adereço raiz está se deslocando.Verse# The transform the prop is currently targeting. var TargetTransform:transform = transform{}
Sua definição de classe deve ficar assim:
Verseusing { /Fortnite.com/Devices } using { /Fortnite.com/Devices/CreativeAnimation } using { /Verse.org/Simulation } using { /UnrealEngine.com/Temporary/SpatialMath } RotationRateTip<localizes>:message := "The time it takes to make one AdditionalRotation in seconds." UseEasePerKeyframeTip<localizes>:message := "Whether this prop should use the MoveEaseType for each keyframe. False will use the Linear ease type on each frame." # A prop that translates, rotates, and scales to a destination using animation. animating_prop<public> := class<concrete>(movable_prop):Substitua a função
Move()na classeanimating_prop.Em seguida, em uma expressãofor, itere em cadaMoveTargetna matriz deMoveTargets. Verifique se cadaMoveTargeté válido e, se for, definaTargetTransformpara a transformação deMoveTarget.Verse# Move and rotate the RootProp toward the MoveTarget, or MoveTransform if one is set. Move<override>()<suspends>:void= # Move to each target in the MoveTargets array. for: MoveTarget:MoveTargets do: # Set the TargetTransformto the MoveTarget if the # MoveTarget is set. Otherwise set it to the MoveTransform.De volta ao arquivo
movement_behaviors, adicione um novo método chamadoBuildMovingAnimationKeyframes(). Essa função criará e retornará uma matriz de keyframes que animam um adereço, movimentando e girando-o até um transformar-alvo. Essa função recebe diversos parâmetros deanimating_prop:MoveDuration,RotationRate,AdditionalRotation,OriginalTransform(a transformação inicial do adereço),TargetTransform,MoveEaseTypee um novo valor delogicchamadoUseEasePerKeyframe. Este último determina se você usaMoveEaseTypepara cada keyframe. A assinatura da sua função deve ficar assim:Verse# Builds an array of keyframes that animate movement and rotation from the OriginalTransform to the TargetTransform. BuildMovingAnimationKeyframes(MoveDuration:float, RotationRate:float, AdditionalRotation:rotation, OriginalTransform:transform, TargetTransform:transform,MoveEaseType:move_to_ease_type, UseEasePerKeyframe:logic):[]keyframe_delta=Em
BuildMovingAnimationKeyframes(), inicialize as seguintes variáveis:Uma matriz de variáveis de
keyframe_deltachamadaKeyframes. Esta é a matriz que você retornará ao final.Verse# The array of keyframes to return. var KeyFrames:[]keyframe_delta = array{}Um
floatde variável denominadoTotalTime. Este é o total de tempo gasto na animação até o momento.Verse# The total amount of time spent animating. var TotalTime:float = 0.0Duas variáveis
transformchamadasStartTransformeEndTransform. Estes são os transformares inicial e final do adereço no início e fim de cada keyframe. Inicialize as duas paraOriginalTransform.Verse# The starting transform for building keyframes. This is the # transform of the RootProp at the start of each keyframe. var StartTransform:transform = OriginalTransform # The ending transform for building keyframes. This is the # transform of the RootProp at the end of each keyframe. var EndTransform:transform = OriginalTransformUma variável
rotationchamadaRotationToApply, inicializada como aAdditionalRotation. Esta é a rotação real a ser aplicada ao adereço para cada keyframe. Geralmente, seráAdditionalRotation, mas se você precisar realizar uma rotação fracionada, poderá alterar esse valor.Verse# The actual rotation to apply to the RootProp. Usually this is the # AdditionalRotation, but will change in cases with fractional rotations. var RotationToApply:rotation = AdditionalRotationUma variável
floatchamadaAnimationTime. Esta é a quantidade de tempo, em segundos, que cada keyframe dura. Inicialize ela para1.0 / RotationRate, pois RootProp precisa realizar um número deRotationRaterotações por segundo.Verse# The time it takes for each keyframe of animation to complete. # This is initialized to 1.0/Rotation rate since the RootProp needs to make a # RotationRate number of rotations per second. var AnimationTime:float = 1.0 / RotationRateUm valor de
floatchamadoTotalRotations. Esse é o número total de rotações a serem feitas em toda a animação e é inicializado emMoveDuration * RotationRate. O motivo para esse ser umfloate não uminté lidar com situações em que você não precisa fazer uma rotação completa, como ao final de uma animação.Verse# The total number of rotations to make. TotalRotations:float = MoveDuration * RotationRateUm valor de
floatchamadoTimePerRotation. Esta é a quantidade de tempo, em segundos, que leva para uma rotação ser concluída. Sua função agora deve ficar assim:Verse# Builds an array of keyframes that animate movement and rotation from the OriginalTransform to the TargetTransform. BuildMovingAnimationKeyframes(MoveDuration:float, RotationRate:float, AdditionalRotation:rotation, OriginalTransform:transform, TargetTransform:transform,MoveEaseType:move_to_ease_type, UseEasePerKeyframe:logic):[]keyframe_delta= # The array of keyframes to return. var KeyFrames:[]keyframe_delta = array{} # The total amount of time spent animating. var TotalTime:float = 0.0 # The starting transform for building keyframes. This is the
Como são muitos os valores que precisamos acompanhar, vamos fazer um cálculo de exemplo usando 2.5 como RotationRate e 5.0 como MoveDuration.
Rotation Rate = 2.5 rotations/second
Move Duration = 5.0 seconds
Animation Time =
1.0 seconds/Rotation Rate =
1.0/2.5 = 0.4 seconds
Total Rotations =
Move Duration /Rotation Rate =
Com RotationRate de 2.5 e MoveDuration de 5.0, você fará 12.5 rotações no total, com cada rotação levando 0.4 segundo. Isso significa que você precisará realizar uma meia rotação extra ao final da animação. Você também pode ter notado que o tempo da animação e o tempo por rotação são os mesmos. Isso é quase sempre o caso, exceto quando você não precisa realizar uma rotação completa. Apesar de eles inicialmente terem o mesmo valor, você precisará acompanhar ambas as variáveis para realizar alguns cálculos mais tarde.
Como criar keyframes em um loop
É hora de colocar a mão da massa! Siga os passos abaixo para configurar o loop que cria seus keyframes.
Adicione uma expressão de
loopaBuildMovingAnimationKeyframes(). Em cada iteração do loop, você criará um novo keyframe e o adicionará à matriz de keyframes. No início do loop, atualizeTotalTimecomTimePerRotation.Verse# Build each keyframe of animation and add it to the Keyframes array. # The loop breaks when the TotalTime goes past the MoveDuration. loop: # Add the TimePerRotation to the TotalTime. set TotalTime += TimePerRotationCrie
EndTransform, que é onde o adereço deve estar no final desse keyframe. DefinaEndTransformpara uma nova transformação com os seguintes parâmetros:Defina
Translationcomo o resultado da chamada deLerp()entreOriginalTransformeTargetTransform.A funçãoLerp()assume dois valores e uma proporção de interpolação linear entre0.0e1.0. Em seguida, gera um novo valor entre os dois com base na razão Lerp. Quanto mais próxima de 1.0 for a razão da interpolação linear, mais próxima deTargetTransforma transformação estará, e vice-versa.Verse# Build the ending transform for the RootProp to move to. set EndTransform = transform: # Use Lerp() to find how far between the StartingTransform and the TargetTransform the RootProp should translate. # Do the same for scale, and rotate the starting transform by the RotationToApply. # The Lerp Parameter is based on the total number of rotations since the RootProp should guarantee that it makes # at least that many rotations over the whole animation. Translation := Lerp(OriginalTransform.Translation, TargetTransform.Translation, (TotalTime * RotationRate) / (TotalRotations))Defina a
Rotationno resultado deMakeShortestRotationBetween(), transmitindo a rotação da transformação original e a transformação original girada porRotationToApply.VerseTranslation := Lerp(OriginalTransform.Translation, TargetTransform.Translation, (TotalTime * RotationRate) / (TotalRotations)) Rotation := MakeShortestRotationBetween(OriginalTransform.Rotation, OriginalTransform.Rotation.RotateBy(RotationToApply))~~~Defina
Scalecomo o resultado da camada deLerp()entreOriginalTransform.ScaleeTargetTransform.Scale. Lembre-se de que esta é a escala que o adereço deve alcançar, não quanto ele precisa escalar. A funçãoEndTransformcompleta deve ficar assim:Verse# Build the ending transform for the RootProp to move to. set EndTransform = transform: # Use Lerp() to find how far between the StartingTransform and the TargetTransform the RootProp should translate. # Do the same for scale, and find the shortest rotation between the original transform and a rotation to apply to it. Translation := Lerp(OriginalTransform.Translation, TargetTransform.Translation, LerpParameter) Rotation := MakeShortestRotationBetween(OriginalTransform.Rotation, OriginalTransform.Rotation.RotateBy(RotationToApply)) Scale := Lerp(OriginalTransform.Scale, TargetTransform.Scale, LerpParameter)
Com o seu transformar final definido, é hora de criar um keyframe! Esse é basicamente o mesmo processo que você fez para a função
MoveToEase(). Crie uma nova variávelkeyframe_deltachamadaKeyFrame. DefinaDeltaLocationcomo a diferença entre as translações das transformações final e inicial. DefinaDeltaRotationcomo a rotação da transformação final. Como você precisa calcular a alteração na escala, definaDeltaScalecomo o resultado da divisão da escala da transformação final pela escala da transformação inicial.Timedeve serAnimationTime, eInterpolationTypedeve ser o resultado de uma expressãoif. SeUseEasePerKeyframefor verdadeiro, useMoveEaseType. Caso contrário, use o tipo linear. A expressão do seu keyframe deve ficar assim:Verse# Build the animation keyframe to animate the RootProp. Keyframe := keyframe_delta: DeltaLocation := EndTransform.Translation - StartTransform.Translation, DeltaRotation := EndTransform.Rotation, DeltaScale := EndTransform.Scale/StartTransform.Scale, Time := AnimationTime, # Use the MoveEaseType for interpolation if UseEasePerKeyframe is true, # otherwise use the Linear movement type. Interpolation := if:Com o keyframe criado, agora podemos adicioná-lo à matriz
Keyframes. Em seguida, definaStartTransformcomoEndTransformpara atualizá-lo para o próximo keyframe. Por fim, seTotalTimefor agora maior que aMoveDuration, interrompa o loop.Verse# Add the new keyframe to the KeyFrames array, and set the # StartTransform to the EndTransform. set Keyframes += array{Keyframe} set StartTransform = EndTransform # Break out of the loop if the TotalTime passes the MoveDuration. if: TotalTime >= MoveDuration then: breakHá um caso limítrofe importante a considerar: o que acontece quando você precisa fazer menos de uma rotação completa? Como você está adicionando
TimePerRotationaTotalTime, isso significa queTotalTimepode ser maior queMoveDurationno início do loop. Nessa situação, você precisa lidar com o tempo remanescente e realizar menos do que uma rotação completa, com um tempo de animação mais curto que considere essa diferença. Siga os passos abaixo para cuidar dessa situação:Voltando ao início do loop, após atualizar
TotalTime, comece uma expressãoif. Dentro dela, inicialize uma variávelLeftoverTime, e defina-a igual ao resultado da subtração deTotalTimeeMoveDuration, verificando se é maior que0.0. Essa expressão só atribuiráLeftoverTimese a comparação for verdadeira.Verseloop: # Add the TimePerRotation to the TotalTime. set TotalTime += TimePerRotation if: # If the TotalTime is greater than the MoveDuration, the final keyframe needs # to be shortened. This means making a fraction of a rotation. LeftoverTime := TotalTime - MoveDuration > 0.0Para saber que fração de uma rotação você precisa fazer, inicialize uma nova variável
RotationFraction, e defina-a como igual à diferença entreTimePerRotationeLeftoverTime, tudo dividido porTimePerRotation.Verseif: # If the TotalTime is greater than the MoveDuration, the final keyframe needs # to be shortened. This means making a fraction of a rotation. LeftoverTime := TotalTime - MoveDuration > 0.0 # The fraction of a rotation to make. RotationFraction := (TimePerRotation - LeftoverTime)/TimePerRotationPara criar uma rotação modificada a partir de
RotationFraction, você usaráSlerp[]. Esta é a versão deLerp()que lida com interpolação esférica e tem parâmetros semelhantes. Ela encontra a menor rotação entre duas diferentes rotações e retorna uma rotação baseada no parâmetro lerp. ChameSlerp[], interpolando entreIdentityRotation()eIdentityRotation()rotacionado porRotationToApply, usandoRotationFractioncomo o parâmetro de interpolação linear. Você está usandoIdentityRotation()aqui porque precisamos apenas descobrir qual rotação fracionária será aplicada, e não em qual rotação finalEndTransformdeve estar.Verseset TotalTime += TimePerRotation if: # If the TotalTime is greater than the MoveDuration, the final keyframe needs # to be shortened. This means making a fraction of a rotation. LeftoverTime := TotalTime - MoveDuration > 0.0 # The fraction of a rotation to make. RotationFraction := (TimePerRotation - LeftoverTime)/TimePerRotation # Make a modified fractional rotation by using Slerp(). The Slerp() function does spherical interpolationCom esses valores configurados, defina
RotationToApplycomoModifiedRotation, multipliqueAnimationTimeporRotationFractionpara saber quanto encurtar sua animação e, por fim, definaTotalTimecomoMoveDuration, pois não queremos que seja maior que esse valor ao calcularmosEndTransform.VerseModifiedRotation := Slerp[IdentityRotation(), IdentityRotation().RotateBy(RotationToApply), RotationFraction] then: # Set the RotationToApply to the modified rotation, and multiply the animation time by # the RotationFraction to get the modified animation time. set RotationToApply = ModifiedRotation set AnimationTime = AnimationTime * RotationFraction # Since the TotalTime should not go past the MoveDuration, # set TotalTime to MoveDuration. set TotalTime = MoveDuration
No final da função, após o loop, retorne a matriz
Keyframes. Sua funçãoBuildMovingAnimationKeyframes()concluída deve ficar assim:Verse# Builds an array of keyframes that animate movement and rotation from the OriginalTransform to the TargetTransform. BuildMovingAnimationKeyframes(MoveDuration:float, RotationRate:float, AdditionalRotation:rotation, OriginalTransform:transform, TargetTransform:transform,MoveEaseType:move_to_ease_type, UseEasePerKeyframe:logic):[]keyframe_delta= # The array of keyframes to return. var Keyframes:[]keyframe_delta = array{} # The total amount of time spent animating. var TotalTime:float = 0.0 # The starting transform for building keyframes. This is theAgora que definimos a lógica para criar os keyframes, é hora de animá-los. Você usará uma função separada para criar e chamar sua animação. Adicione uma nova função
BuildAndPlayAnimation()à classeanimating_prop. Adicione o modificador<suspends>a essa função para permitir que ela chame outras funções assíncronas.Verse# Builds an animation from an array of keyframes, then calls MoveToEase() # to animate the prop. BuildAndPlayAnimation()<suspends>:void=Em
BuildAndPlayAnimation(), inicialize uma nova matrizkeyframe_deltachamadaKeyframes. Em seguida, definaKeyframescomo o resultado da chamada deBuildMovingAnimationKeyframes(). UseRootProp.GetTransform()como a transformação inicial, pois a posição do adereço mudará entre as chamadas deMove(). Inicialize uma variávelanimation_modecomanimation_mode.OneShote chame a funçãoMoveToEase(), passando a matrizKeyframese oAnimationMode.Sua função
BuildAndPlayAnimation()completa deve ficar assim:Verse# Builds an animation from an array of keyframes, then calls MoveToEase() # to animate the prop. BuildAndPlayAnimation()<suspends>:void= var Keyframes:[]keyframe_delta = array{} # Build the animation, using the RootProp as the target transform. set Keyframes = BuildMovingAnimationKeyframes(MoveDuration, RotationRate, AdditionalRotation, RootProp.GetTransform(), TargetTransform, MoveEaseType, UseEasePerKeyframe) # Set the animation mode to OneShot. var AnimationMode:animation_mode := animation_mode.OneShotVoltando a
Move(), chameBuildAndPlayAnimation()depois de definirTargetTransformpara transformar os alvos de movimento.Verse# Move to each target in the MoveTargets array. for: MoveTarget:MoveTargets do: # Set the TargetTransform to the MoveTarget if the # MoveTarget is set. Otherwise set it to the MoveTransform. if: MoveTarget.IsValid[] then: set TargetTransform = MoveTarget.GetTransform()
Há um outro caso que deve ser considerado. O que acontece se você não definir nenhum alvo de movimento? Nessa situação, o seu adereço deve continuar girando no mesmo lugar, sem se mover para um novo destino. Para lidar com isso, adicione uma expressão if à parte superior da sua função Move(). Na expressão if, verifique se MoveTargets.Length = 0 e, caso seja, defina TargetTransform como a transformação do adereço-raiz. Em seguida, chame BuildAndPlayAnimation(). Dessa forma, o seu adereço continuará sua animação mesmo se você não definir um alvo de movimento. Sua animação Move() completa deve ficar assim:
# Move and rotate the RootProp toward the MoveTarget, or MoveTransform if one is set.
Move<override>()<suspends>:void=
# If there are no targets to move to, this prop will rotate in place.
if:
MoveTargets.Length = 0
then:
set TargetTransform = RootProp.GetTransform()
# Build and play the animation.
BuildAndPlayAnimation()
Agora, você precisa fazer referência a animating_prop na sua classe prop_animator. Em prop_animator, adicione uma matriz editável de animating_prop chamada MoveAndRotateProps. Em OnBegin(), em outra expressão for, inicialize cada adereço em MoveAndRotateProps chamando Setup(). Sua classe prop_animator completa deve ficar assim:
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
TranslatingPropsTip<localizes>:message = "The props that translate (move) using animation."
RotatingPropsTip<localizes>:message = "The props that rotate using animation."
ScalingPropsTip<localizes>:message = "The props that scale using animation."
AnimatingPropsTip<localizes>:message = "The props that both move and rotate using animation."
# Coordinates moving props through animation by calling each movable_prop's Setup() method.
Salve o código e compile-o.
Parabéns! Você acaba de finalizar todo o código. É hora de colocar tudo para funcionar em conjunto.
A classe animating_prop que você acabou de criar pode mover, girar e dimensionar adereços. No entanto, ela ainda depende da classe moveable_prop porque precisa herdar várias funções, como ManageMovement(). Dado que a classe animating_prop pode executar todos os três tipos de movimento, você pode ser útil otimizar animating_prop para incluir toda a lógica de moveable_prop, de forma que a classe possa ficar autônoma. Uma refatoração de exemplo está incluída aqui, que mescla animating_prop e moveable_prop em um único arquivo. Ele também inclui a classe de dispositivo Verse prop_animator. Você ainda precisará da funcionalidade de movement_behaviors para o código poder ser executado, mas essa refatoração reduz o número de arquivos necessários de cinco para dois. Esse código também está incluído na seção Código completo.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/CreativeAnimation }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
EasingCategory<localizes>:message := "These control the type of movement easing applied to the prop."
LogicCategory<localizes>:message := "These control different aspects of the prop's logic."
PropsCategory<localizes>:message := "These are the props that move associated with this device."
RotationCategory<localizes>:message := "These control how the prop rotates."
TimingCategory<localizes>:message := "These control the timing of parts of the prop's movmement."
Como vincular adereços a dispositivos
De volta ao editor, exclua uma seção da pista após a seção de adereços de rotação para criar um espaço vazio antes do objetivo final. Adicione outra FG01 SpinningBar Double S e outra FG01 Hover Platform M ao seu nível. Chame-as de SpinningMovingBar e TranslatingPlatform respectivamente, em seguida, adicione vários adereços FG01 Button Bulb, que serão os alvos para os quais cada adereço se moverá. Chame esses PlatformTarget. Coloque as plataformas e a barra sobre o espaço vazio e certifique-se de colocar os alvos onde quer que as plataformas cheguem. Neste exemplo, a barra giratória se move de um lado para o outro, enquanto a plataforma se move para frente e para trás.
A configuração da barra giratória e da plataforma móvel. A seta indica em quais direções cada adereço se move. Tanto a barra giratória quanto a plataforma se movem para frente e para trás, e a barra giratória gira enquanto se move.
Selecione o animador de adereços no Organizador. Adicione um elemento de matriz a AnimatingProps para a barra giratória. Defina cada valor da seguinte forma:
| Option | Valor | Explicação |
|---|---|---|
Rotação adicional | 90.0 | Esse adereço fará uma rotação de 90 graus a cada vez. |
Taxa de rotação | 1.5 | Este adereço fará uma rotação a cada |
Usar suavização por keyframe | false | Usará o tipo de suavização linear em cada keyframe para mover e girar o adereço a uma velocidade constante. |
MoveTargets | Dois elementos, atribuídos a alvos de plataforma. | Estes são os alvos para os quais você deseja que a barra se mova. |
RootProp | SpinningMovingBar | Este é o adereço que você está animando. |
Adicione outro elemento de matriz a TranslatingProps para a plataforma móvel. Atribua MoveTargets aos alvos de plataforma e RootProp à TranslatingPlatform.
Clique em Iniciar Sessão e tente percorrer toda a pista de obstáculos.
Por si só
E é isso! Agora você tem tudo o que precisa para criar sua própria pista de obstáculos de Fall Guys usando Verse!
Você pode usar o código presente aqui para animar adereços de Modo Criativo em qualquer uma das suas experiências, até mesmo em projetos que não sejam de Fall Guys!
Usando o que você aprendeu, tente o seguinte:
Crie obstáculos que giram em várias direções ou giram aleatoriamente entre keyframes.
Crie obstáculos que sejam ativados somente quando um jogador estiver em cima deles ou a uma determinada distância.
Aprenda a criar plataformas que desaparecem após uma certa duração ou movem o jogador para posições perigosas se ele ficar sobre ela por muito tempo.
Código completo
Aqui está o código completo criado nesta seção, incluindo um refatorador de exemplo para animating_prop.
movable_prop.verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
MoveDurationTip<localizes>:message = "The amount of time the prop takes to move to its destination."
MoveEaseTypeTip<localizes>:message = "The animation easing applied to the movement."
MoveEndDelayTip<localizes>:message = "The delay after the movement finishes."
MoveOnceAndStopTip<localizes>:message = "Whether the RootProp should stop in place after it finishes moving."
MoveStartDelayTip<localizes>:message = "The delay before the movement starts."
MoveTargetsTip<localizes>:message = "The array of CreativeProp to move toward. These targets can be children of the RootProp."
translating_prop.verse
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/CreativeAnimation }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
MovePositionTip<localizes>:message = "The optional position to move to World Space. Use this if you do not want to set a MoveTarget."
# A prop that moves (translates) toward either a Creative prop target
# or a position in world space.
translating_prop<public> := class<concrete>(movable_prop):
rotating_prop.verse
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/CreativeAnimation }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
AdditionalRotationTip<localizes>:message = "The rotation to apply to the RootProp."
ShouldRotateForeverTip<localizes>:message = "Whether the RootProp should rotate forever."
MatchRotationTargetTip<localizes>:message = "The optional prop whose rotation the RootProp should rotate to. Use this if you do not want to set an Additional Rotation."
# A prop that rotates by an additional rotation or rotates to match
scaling_prop.verse
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/CreativeAnimation }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
MatchScaleTargetTip<localizes>:message = "The optional position to move to World Space. Use this if you do not want to set a MoveTarget."
# A prop that scales toward either a given scale or a Creative prop's scale.
scaling_prop<public> := class<concrete>(movable_prop):
# The array of vector3 targets for the RootProp to scale to.
animating_prop.verse
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/CreativeAnimation }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
RotationRateTip<localizes>:message := "The time it takes to make one AdditionalRotation in seconds."
UseEasePerKeyframeTip<localizes>:message := "Whether this prop should use the MoveEaseType for each keyframe. False will use the Linear ease type on each frame."
# A prop that translates, rotates, and scales to a destination using animation.
animating_prop<public> := class<concrete>(movable_prop):
movement_behaviors.verse
# This file stores functions common to animating Creative props using keyframes.
# It also defines the move_to_ease_type enum to help in building animations.
using { /Fortnite.com/Devices }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Fortnite.com/Characters}
using { /Fortnite.com/Devices/CreativeAnimation }
# Represents the different movement easing types.
move_to_ease_type<public> := enum {Linear, Ease, EaseIn, EaseOut, EaseInOut}
prop_animator.verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
TranslatingPropsTip<localizes>:message = "The props that translate (move) using animation."
RotatingPropsTip<localizes>:message = "The props that rotate using animation."
ScalingPropsTip<localizes>:message = "The props that scale using animation."
MoveAndRotatePropsTip<localizes>:message = "The props that both move and rotate using animation."
# Coordinates moving props through animation by calling each moveable_prop's Setup() method.
animating_props.verse (exemplo de otimização de animating_prop)
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/CreativeAnimation }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
EasingCategory<localizes>:message := "These control the type of movement easing applied to the prop."
LogicCategory<localizes>:message := "These control different aspects of the prop's logic."
PropsCategory<localizes>:message := "These are the props that move associated with this device."
RotationCategory<localizes>:message := "These control how the prop rotates."
TimingCategory<localizes>:message := "These control the timing of parts of the prop's movmement."