UEFN에서 사물을 이동할 수 있는 몇 가지 방법이 있습니다. TeleportTo[] 또는 MoveTo()와 같은 함수를 사용하여 트랜스폼을 직접 수정하거나, 사물 이동 장치와 같은 다른 장치를 사용하여 프리셋 경로에서 사물을 이동할 수 있습니다. 하지만 애니메이션 형태의 다른 유용한 옵션도 존재합니다.
각 포크리 사물에는 해당 사물의 애니메이션을 재생하는 데 사용할 수 있는 play_animation_controller가 있습니다. 애니메이션은 사물의 트랜스폼 이동과 비교해 몇 가지 장점이 있습니다. 애니메이션은 보통 MoveTo()나 TeleportTo()로 오브젝트를 이동하는 것보다 이동이 매끄러운데, 이는 게임 틱마다 이러한 함수를 호출해야 하는 네트워크 지연시간을 피할 수 있기 때문입니다. 또한 애니메이션에서는 플레이어나 다른 오브젝트와의 콜리전이 더 일관성 있게 이뤄지므로, 사물 이동 장치를 사용하는 것보다 뛰어난 수준으로 오브젝트가 어디에서 어떻게 움직일지를 제어할 수 있습니다. 루프에서 애니메이션을 재생하거나, 왕복 모드를 통해 왕복 재생할 수 있습니다.
또한 애니메이션을 통해 보간 타입을 선택할 수 있습니다. 보간 타입은 이징 타입, 즉 애니메이션이 따르는 애니메이션 커브를 결정합니다. 예를 들어, 선형 보간 타입은 일정한 속도로 애니메이션을 재생하는 반면, 이즈 인 타입은 느리게 시작하여 끝으로 갈수록 빨라집니다. 애니메이션에 맞는 적절한 보간 타입을 선택함으로써 사물이 느려지거나, 빨라지거나, 선형으로 이동해야 하는 여러 지점을 지정할 수 있습니다.
다양한 장애물 애니메이션 간에 전환함으로써 같은 사물을 사용하여 플레이어를 위한 다양한 도전 과제를 만들 수 있습니다. 이 섹션에서는 이 강력한 툴을 사용하여 나만의 애니메이션을 제작하고 사물을 이동하게 만드는 방법을 알아봅니다.
애니메이션 컨트롤 구성하기
사물의 애니메이션 컨트롤을 구성하려면 아래 단계를 따릅니다.
Verse 익스플로러(Verse Explorer)를 사용하여 새 Verse 파일
movement_behaviors를 생성합니다. 이는 사물에 애니메이션을 적용하는 데 필요한 유틸리티 함수를 저장합니다.using { /Fortnite.com/Devices },using { /Fortnite.com/Devices/CreativeAnimation }및using { /UnrealEngine.com/Temporary/SpatialMath }명령문을 파일 상단에 추가하여 해당 모듈을 임포트합니다. 이는 사물에 애니메이션을 적용하는 데 필요합니다.movement_behaviors에서 새enum을 생성하고move_to_ease_type으로 명명합니다. 이 열거형의 값은 여러 애니메이션 이징 타입에 해당합니다.InterpolationTypes모듈에서 이러한 각 이징 타입을 볼 수 있습니다.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/Devices/CreativeAnimation } # Represents the different movement easing types. move_to_ease_type<public> := enum {Linear, Ease, EaseIn, EaseOut, EaseInOut}VectorOnes로 명명한 새vector3타입 에일리어스를 추가해vector3를 만듭니다. 여기에서X,Y,Z는 모두1.0으로 설정됩니다. 나중에 이 벡터를 사용하면 몇 가지 수학 연산이 쉬워집니다. 따라서 타입 에일리어스를 정의해 두면vector3{X:=1.0, Y:=1.0, Z:=1.0}을 반복해서 쓰지 않아도 됩니다.Verse# Initializes a vector3 with all values set to 1.0. VectorOnes<public>:vector3 = vector3{X:=1.0, Y:=1.0, Z:=1.0}move_to_ease_type을 가져와cubic_bezier_parameters를 반환하는 새 메서드GetCubicBezierForEaseType()을 추가합니다.Verse# Return the cubic_bezier_parameters based on the given move_to_ease_type. GetCubicBezierForEaseType(EaseType:move_to_ease_type):cubic_bezier_parameters=큐빅 베지어(cubic bezier)는 애니메이션이 사용하는 이징 함수 타입을 정의하는 4개의 숫자로 이루어져 있습니다. 예를 들면 이즈 인 커브의 파라미터는 애니메이션이 시작할 때 속도를 늦추고 그 후에는 속도를 높입니다. 선형 커브의 파라미터는 애니메이션이 일정한 속도로 재생되도록 합니다. 이러한 값을 직접 정의하여 나만의 커스텀 애니메이션 커브를 만들 수 있지만, 이 예시에서는
InterpolationTypes모듈에 정의된 값을 사용하므로 직접 정의하지 않아도 됩니다.GetCubicBezierForEaseType()의case()표현식에서move_to_ease_type에 따라InterpolationTypes모듈의cubic_bezier_parameters를 가져옵니다. 예를 들면EaseOut은InterpolationTypes.EaseOut을 반환하고,Linear는InterpolationTypes.Linear를 반환하는 식입니다. 완성된GetCubicBezierForEaseType()함수는 다음과 같습니다.Verse# Return the cubic_bezier_parameters based on the given move_to_ease_type. GetCubicBezierForEaseType(EaseType:move_to_ease_type):cubic_bezier_parameters= case (EaseType): move_to_ease_type.Linear => InterpolationTypes.Linear move_to_ease_type.Ease => InterpolationTypes.Ease move_to_ease_type.EaseIn => InterpolationTypes.EaseIn move_to_ease_type.EaseOut => InterpolationTypes.EaseOut move_to_ease_type.EaseInOut => InterpolationTypes.EaseInOutmovable_prop클래스로 돌아가 편집 가능한 새move_to_ease_type을 추가하고MoveEaseType으로 명명합니다. 이는 사물이 애니메이션에 적용할 이징 타입입니다.Verse# The type of animation easing to apply to the RootProp's movement. The easing type # changes the speed of the animation based on its animation curve. @editable {ToolTip := MoveEaseTypeTip} MoveEaseType:move_to_ease_type = move_to_ease_type.EaseInOut
키프레임으로 애니메이션 제작하기
코드로 애니메이션을 만들기 위해 키프레임을 사용합니다. 애니메이션은 하나 이상의 키프레임으로 만들어지며, 각 키프레임은 애니메이션의 특정 지점에서 오브젝트의 값을 지정합니다. 키프레임을 사용하여 애니메이션을 제작하면 사물이 이동하거나, 회전하거나, 심지어 스케일 조절되는 여러 지점을 지정할 수 있습니다.
키프레임에는 5가지 값이 있습니다. DeltaLocation, DeltaRotation, DeltaScale은 키프레임의 시작부터 끝까지 사물에 적용할 각 값의 변화량을 지정합니다. 애니메이션에 소요되는 시간(초)인 Time이나 키프레임의 보간 모드인 Interpolation도 있습니다. 예시 키프레임은 다음과 같습니다.
# An example keyframe.
KeyFrame := keyframe_delta:
# The target position of the `creative_prop`. This is the difference between the starting and ending translation of the prop.
DeltaLocation := EndTransform.Translation - StartTransform.Translation,
# The target rotation for the `creative_prop` to rotate to.
DeltaRotation := EndTransform.Rotation,
# The target scale for the `creative_prop`. Scale is multiplicative to the starting Scale of the `creative_prop`
키프레임을 사용하여 애니메이션을 제작하려면 다음 단계를 따릅니다.
새
creative_prop익스텐션 메서드를MoveToEase()로 명명하고movement_behaviors파일에 추가합니다. 이 함수는 사물이 이동할 위치, 회전, 스케일과 애니메이션에 소요되는 지속 시간, 이동 이징 타입, 애니메이션 모드를 받습니다.Verse# Animate a creative_prop by constructing an animation from a single keyframe, and then playing that animation on the prop. # This method takes a Position, Rotation, and Scale for the prop to end at, the duration of the animation, # the type of easing to apply to the movement, and the animation mode of the animation. (CreativeProp:creative_prop).MoveToEase<public>(Position:vector3, Rotation:rotation, Scale:vector3, Duration:float, EaseType:move_to_ease_type, AnimationMode:animation_mode)<suspends>:void=MoveToEase()에서GetAnimationController[]를 사용하여 포크리 사물의 애니메이션 컨트롤러를 가져옵니다. 애니메이션 컨트롤러는 사물에서 애니메이션을 재생하도록 하고 나중에 대기할 이벤트도 노출합니다.Verse(CreativeProp:creative_prop).MoveToEase<public>(Position:vector3, Rotation:rotation, Scale:vector3, Duration:float, EaseType:move_to_ease_type, AnimationMode:animation_mode)<suspends>:void= # Get the animation controller for the CreativeProp to move. if (AnimController := CreativeProp.GetAnimationController[]):ScaleMultiplicative라는 스케일에서 사물의 변화량을 계산합니다. 이때Scale은 조금 더 복잡합니다. 스케일은 곱연산이므로 종료 트랜스폼의 스케일은 원본 트랜스폼의 목표 스케일 값이 아니라 원본 트랜스폼에 필요한 스케일 조절량이 되어야 합니다. 예를 들어 원본 트랜스폼의 스케일이1.2이고1.5로 스케일 조절하려는 경우,1.2 * 1.25 = 1.5이므로 실제로는1.25로 스케일을 조절해야 합니다. 최종 값은 새 스케일에서 기존 스케일을 뺀 값을 기존 스케일로 나누어VectorOnes와 더한 값입니다. 이 값은 애니메이션 도중에 크기를 변경한 경우 애니메이션이 계속 제대로 적용되도록 하는 데 필요합니다.Verse# Calculate the multiplicative scale for the keyframe to scale to. ScaleMultiplicative:vector3 = VectorOnes + ((Scale - CreativeProp.GetTransform().Scale) / CreativeProp.GetTransform().Scale)각 애니메이션에는 실행할 키프레임의 배열이 필요합니다. 이 함수에서는 단일 키프레임만 사용하여 배열로 형변환합니다. 이 배열에는 단일 키프레임밖에 없으므로, 하나의 사물 이동 애니메이션이 새 위치로 매끄럽게 적용될 것입니다. 또한 루프 안에서
MoveToEase()를 호출하므로, 여러 애니메이션을 연이어 지정할 필요 없이 사물에 계속 애니메이션을 적용할 수 있습니다.Keyframes로 명명한keyframe_delta의 새 배열을 정의합니다. 이 배열을 새 배열과 같게 설정하고, 해당 배열 안에서 새keyframe_delta를 생성합니다.Verse# Build the keyframe array from a single keyframe_delta of the given values. Keyframes:[]keyframe_delta = array: keyframe_delta:keyframe_delta정의 안에서 키프레임을 빌드하는 데 필요한 각 값을 초기화합니다.DeltaLocation을 새Position에서 포크리 사물의 이동을 뺀 값으로 설정합니다.DeltaRotation을Rotation으로 설정하고,DeltaScale을 앞서 계산한ScaleMultiplicative로 설정합니다.Time을Duration으로 설정하고GetCubicBezierForEaseType()을 호출하여 적절한Interpolation을 가져옵니다.Verse# Build the keyframe array from a single keyframe_delta of the given values. Keyframes:[]keyframe_delta = array: keyframe_delta: DeltaLocation := Position - CreativeProp.GetTransform().Translation, DeltaRotation := Rotation, DeltaScale := ScaleMultiplicative, Time := Duration, Interpolation := GetCubicBezierForEaseType(EaseType)Keyframes배열이 빌드된 상태에서SetAnimation()을 사용하여 애니메이션 컨트롤러의 애니메이션으로 설정하고AnimationMode를 전달합니다.Play()를 사용하여 애니메이션을 재생한 다음MovementCompletedEvent를Await()합니다. 완성된MoveToEase()익스텐션 메서드는 다음과 같습니다.Verse# Animate a creative_prop by constructing an animation from a single keyframe, and then playing that animation on the prop. # This method takes a Position, Rotation, and Scale for the prop to end at, the duration of the animation, # the type of easing to apply to the movement, and the animation mode of the animation. (CreativeProp:creative_prop).MoveToEase<public>(Position:vector3, Rotation:rotation, Scale:vector3, Duration:float, EaseType:move_to_ease_type, AnimationMode:animation_mode)<suspends>:void= # Get the animation controller for the CreativeProp to move. if (AnimController := CreativeProp.GetAnimationController[]): # Calculate the multiplicative scale for the keyframe to scale to. ScaleMultiplicative:vector3 = VectorOnes + ((Scale - CreativeProp.GetTransform().Scale) / CreativeProp.GetTransform().Scale)
함수 오버로드하기
작성한 MoveToEase() 함수가 유용하기는 하지만, 이 함수를 호출하고자 할 때마다 이처럼 많은 변수를 함수에 전달하는 것은 복잡할 수 있습니다. 이동이나 회전처럼 사물의 트랜스폼 중 한 부분만 변경하고 싶은 상황이 있을 수 있으며, 이 경우 호출할 보다 단순한 함수가 있으면 유용합니다.
이 문제를 해결하기 위해 함수 오버로드를 활용할 수 있습니다. MoveToEase() 함수를 오버로드하면 같은 이름의 여러 메서드가 다양한 입력 타입을 처리하도록 구성할 수 있습니다. 오버로드된 함수를 구성하려면 아래 단계를 따릅니다.
movement_behaviors파일에서 이름은 같지만 입력은 다른 익스텐션 메서드를 또 하나 생성하여MoveToEase()함수를 오버로드합니다. 이MoveToEase()는 사물의 이동만 업데이트하며, 회전 및 스케일은 동일하게 유지됩니다. 즉,Position,Duration,EaseType,AnimationMode실행인자만 필요합니다.Verse# An overload of MoveToEase() that changes the position of the prop while keeping the rotation and scale the same. (CreativeProp:creative_prop).MoveToEase<public>(Position:vector3, Duration:float, EaseType:move_to_ease_type, AnimationMode:animation_mode)<suspends>:void=새
MoveToEase()에서 원본MoveToEase()함수를 호출하고, 모든 입력과 함께Scale로IdentityRotation()및VectorOnes를 전달합니다.IdentityRotation()은 회전의 모든 값을0으로 반환하므로(0,0,0)이 됩니다. 애니메이션에 회전을 추가하지 않을 것이므로 지금은IdentityRotation()이 필요합니다. 오버로드된MoveToEase()함수는 다음과 같습니다.Verse# An overload of MoveToEase() that changes the position of the prop while keeping the rotation and scale the same. (CreativeProp:creative_prop).MoveToEase<public>(Position:vector3, Duration:float, EaseType:move_to_ease_type, AnimationMode:animation_mode)<suspends>:void= CreativeProp.MoveToEase(Position, IdentityRotation(), VectorOnes, Duration, EaseType, AnimationMode)이 프로세스를 반복하여 회전만 변경하고 이동 및 스케일은 동일하게 유지하는 다른 오버로드 메서드를 생성합니다. 이 새 오버로드 메서드는 다음과 같습니다.
Verse# An overload of MoveToEase() that changes the rotation of the prop while keeping the position and scale the same. (CreativeProp:creative_prop).MoveToEase<public>(Rotation:rotation, Duration:float, EaseType:move_to_ease_type, AnimationMode:animation_mode)<suspends>:void= CreativeProp.MoveToEase(CreativeProp.GetTransform().Translation, Rotation, VectorOnes, Duration, EaseType, AnimationMode)이 프로세스를 반복하여 스케일만 변경하고 이동 및 회전은 동일하게 유지하는 메서드를 생성합니다. 하지만
translation과scale모두vector3이므로 결과 함수는 이동을 위해 만든 오버로드와 동일한 시그니처를 갖게 되어, 오류를 유발합니다. 이 문제는 함수 파라미터의 순서를 변경하여 해결할 수 있습니다.Duration및Scale의 위치를 대체하여 오버로드 함수를 가져옵니다. 오버로드된 메서드는 다음과 같습니다.Verse# An overload of MoveToEase() that changes the position and scale of the prop while keeping the rotation the same. (CreativeProp:creative_prop).MoveToEase<public>(Duration:float, Scale:vector3, EaseType:move_to_ease_type, AnimationMode:animation_mode)<suspends>:void= CreativeProp.MoveToEase(CreativeProp.GetTransform().Translation, IdentityRotation(), Scale, Duration, EaseType, AnimationMode)여러 키프레임을 처리할 수 있는
MoveToEase()버전이 있으면 유용합니다. 이는 키프레임을 미리 구성하여MoveToEase()로 모두 전달하는 식으로 처리할 수 있습니다. 이렇게 하면 함수는 포크리 사물에만 애니메이션을 설정하고 재생하면 됩니다. 키프레임의 배열과 애니메이션 모드를 입력으로 받는MoveToEase()의 새 오버로드를 추가합니다.Verse# An overload of MoveToEase() that takes a pre-built array of keyframes and plays an animation. (CreativeProp:creative_prop).MoveToEase<public>(Keyframes:[]keyframe_delta, AnimationMode:animation_mode)<suspends>:void= if (AnimController := CreativeProp.GetAnimationController[]): AnimController.SetAnimation(Keyframes, ?Mode:=AnimationMode) AnimController.Play() AnimController.MovementCompleteEvent.Await()코드를 저장하고 컴파일합니다.
메서드가 구성되었으니, 이제 움직이게 만들 차례입니다. 다음 섹션에서는 사물을 이동하여 움직이는 플랫폼을 만들어 봅니다.
완성된 코드
이 섹션에서 빌드한 완성된 코드는 다음과 같습니다.
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}