Bu eğitim, Animasyonlu Nesne Hareketi eğitiminin Scene Graph’e özel, gelişmiş bir sürümüdür. UEFN'de Scene Graph'ın dışında animasyon tabanlı hareket hakkında daha fazla bilgi edinmek istiyorsan öncelikle o eğitimi incele ve daha sonra bu eğitime geri dön!
Hareketli platformlar çoğu platform oyununda ortak bir özelliktir ve oyuncunun amacına ulaşmak için hedefler arasında doğru atlayışlar yapmasını gerektirir.
UEFN’de nesnelerini hareket ettirmenin birkaç yolu vardır. Bir dönüşümü doğrudan değiştirmek için TeleportTo[] veya MoveTo() gibi fonksiyonlar ya da bir nesneyi önceden ayarlanmış bir yolda hareket ettirmek için nesne yürütücü gibi başka bir cihaz kullanabilirsin. Ancak animasyon biçiminde başka bir kullanışlı seçenek daha var.
Animasyonların, nesnenin dönüşümünü hareket ettirmeyle ilgili birkaç avantajı vardır. Animasyonlar genellikle MoveTo() veya TeleportTo() ile objeleri hareket ettirmekten daha yumuşak hareketler sunar çünkü bu fonksiyonlar her oyun güncellemesinde bu fonksiyonları çağırmak zorunda kalmanın neden olduğu ağ gecikmesini önler.
Animasyonlar ayrıca oyuncularla veya diğer objelerle daha tutarlı çarpışmalar oluşturur ve Nesne Yürütücü cihazı kullanmaya kıyasla objelerin nerede ve nasıl hareket ettiği konusunda daha fazla kontrole sahip olursun. Animasyonları döngü halinde veya pinpon moduyla ileri geri oynatabilirsin.
Animasyonlar ayrıca bir interpolasyon türü seçmene de olanak tanır. İnterpolasyon türü, animasyonunun izleyeceği hız düzenleme türünü veya animasyon eğrisini belirler. Örneğin doğrusal interpolasyon türü, animasyonunu sabit bir hızda oynatırken hızlanan tür yavaş başlar ve sona doğru hızlanır.
Animasyonun için doğru interpolasyon türünü seçerek nesnenin farklı noktalarda yavaşlamasını, hızlanmasını veya doğrusal hareket etmesini belirleyebilirsin. Bu davranışları bölümündeki varlıklara eklemek için bir bileşen uygulayarak oyuncularının aralarında gezinebileceği hareketli platformlar oluşturabilirsin.
İlk olarak, hareketli bir platformun ne tür davranışlar sergileyebilmesi gerektiğini düşün. Animasyon belirli bir başlangıç konumundan başlamalı, sonra birden fazla noktaya hareket etmelidir. Hareketinin sonuna ulaştığında ya başlangıç konumuna dönebilmeli ya da yerinde durabilmelidir.
Bu hareketleri belirli bir süre boyunca gerçekleştirmeli ve yolculuğunun her noktasında uygun şekilde dönüp ölçeklenebilmelidir. Bu davranışların her birinin elde edilmesi için belirli bir kod gerekir ancak basit bir sınıftan başlayarak ve bunun üzerine inşa ederek farklı fikirleri hızlıca yineleyebilirsin. Animasyon tabanlı bir hareket bileşeni oluşturmak için şu adımları izle.
animate_to_targets_componentadlı yeni bir Verse bileşeni oluştur ve bunu Visual Studio Code’da aç. Kendi Verse bileşenlerini oluşturma hakkında daha fazla bilgi için Kendi Verse Bileşenini Oluşturma bölümüne bakabilirsin./Verse.org/SpatialMathiçinusingdeyimlerini ekle,/Verse.org/SceneGraph/KeyframedMovement, ve/UnrealEngine.com/Temporary/SpatialMathkullanır. Daha sonra bunların her birinden fonksiyonlar gerekli olacak.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):Eğitimin bu bölümünde kullanılan araç ipuçları aşağıda verilmektedir. Bunları kopyalayıp
animate_to_targets_componentsınıf tanımının üzerine yapıştırabilirsin.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."Aşağıdaki alanları
animate_to_targets_componentsınıf tanımına ekle:InitialPauseSecondsadlı düzenlenebilir bir sayı kayan değişkeni. Varlığın animasyona başlamasından önce geçen süredir. Varlığın animasyona başlamadan önce on saniye beklemesi için bunu10,0olarak ayarla.
Verse# Amount of time to pause before the animation starts. @editable_number(float): ToolTip := SpeedTip MinValue := option{0.0} var InitialPauseSeconds<public>:float = 10.0AnimationPlaybackModeadlı düzenlenebilir birkeyframed_movement_playback_mode. Varlığın animasyonu için bu animasyon modu kullanılır. Bunuloop_keyframed_movement_playback_modeolarak ayarla. Bu ayar, varsayılan olarak, animasyon tamamlandıktan sonra varlığın döngüye gireceği ve animasyonunu baştan başlatacağı anlamına gelir.
Verse# The playback mode used by this animation. @editable: ToolTip := PlaybackModeTip var PlaybackMode<public>:keyframed_movement_playback_mode = loop_keyframed_movement_playback_mode{}Kodunu kaydet ve derle.
Animasyonları Segmentlere Bölme
Kodda animasyonlar oluşturmak için anahtar kareleri kullan. Animasyonlar bir veya daha fazla anahtar kare ile yapılır ve her anahtar kare, animasyonun belirli noktalarındaki objenin değerlerini belirtir. Anahtar kareler ile bir animasyon oluşturarak, nesnenin hareket edeceği, döneceği ve ölçekleneceği birden fazla nokta belirleyebilirsin.
Keyframed_movement_component, anahtar kare türü olarak bir keyframed_movement_delta kullanır. Bu hareket deltalarının üç değeri vardır:
Transform: Önceki anahtar kareye göre dönüşümdeki değişiklikleri belirtir.Süre: Anahtar karenin saniye cinsinden süresi.Easing: Bu anahtar kareyi oynatırken kullanılacak yavaşlatma fonksiyonu.
Keyframed_movement_component bir anahtar kare dizisini alıp oynattığı için, oynatmak istediğin her animasyon için tüm anahtar kareleri aynı anda sağlaman gerekir. Bunu yapmanın iki yolu vardır:
Kodda birden fazla anahtar kareden oluşan bir dizi derleyebilir, ardından bunu anahtar kareli hareket bileşenine iletebilir ve tek bir animasyon oynatabilirsin.
Tek bir anahtar kare içeren birden fazla dizi oluşturabilir ve bunları birden fazla animasyonu sırayla oynatmak için anahtar kareli hareket bileşenine ayrı ayrı iletebilirsin.
Bu seçeneklerin her ikisinin de avantajları ve dezavantajları vardır. Tek anahtar karelerden oluşan diziler, anahtar kareler arasında işlemleri daha kolay gerçekleştirmene olanak tanır fakat bunların işlenmesi için daha fazla kod gerekir. Tüm anahtar kareleri tek seferde oluşturmak, işleri yönetmeyi kolaylaştırır ancak animasyon oynatılırken işlemleri gerçekleştirmek daha zordur. Hem Nesne Hareketine Animasyon Uygulama eğitiminde hem de bu eğitimde birinci yaklaşım ele alınmaktadır fakat ikinci yaklaşımın nasıl uygulandığı da gösterilecektir.
Kodda ayrı anahtar kareler oluşturmak için bir segment sınıfı tanımlamalısın. Her segment, editörden oluşturabileceğin keyframed_movement_component tarafından kullanılan bir anahtar kareyi temsil edecektir. Ayrıca her anahtar kare arasında beklenecek süre gibi ekstra veriler de ekleyebilirsin. Segment sınıfını oluşturmak için aşağıdaki adımları izle.
Animate_to_targets_component.versedosyanasegmentadlı yeni bir sınıf ekle. Bu sınıfın@editabledeğer olarak kullanılmasına izin vermek için<concrete>belirtecini ekle.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>:Aşağıdaki alanları segment sınıf tanımına ekle:
SegmentStartPositionadlı düzenlenebilir birvarlıkseçeneği. Bu varlık, varlığın animasyona başlayacağı dünya konumu için bir referans görevi görecektir.
Verse# An entity that represents the starting position of this entity during the animation segement. @editable: ToolTip := SourceTip SegmentStartPosition:?entity = falseAnimationDurationadlı düzenlenebilir birkayan sayı. Bu animasyon segmentinin oynatılacağı süreyi belirtir. Her animasyon segmentinin iki saniye oynatılması için bunu2,0olarak ayarla.
Verse# The duration of the animation segment. @editable: ToolTip := AnimationDurationTip AnimationDuration:float = 2.0EasingFunctionadlı düzenlenebilir bir yavaşlatma fonksiyonu. Animasyonun bu segmenti sırasında bu yavaşlatma fonksiyonu kullanılır.
Verse# The easing function to use during this segment of animation. @editable: ToolTip := EasingFunctionTip EasingFunction:?easing_function = falseHer yavaşlatma fonksiyonu, animasyonun kullandığı yavaşlatma fonksiyonunun türünü oluşturan dört sayıdan oluşan kübik bir Bézier eğrisiyle tanımlanır. Örneğin bir hızlanan eğriye ait parametreler animasyonun başlangıçta yavaşlayıp sonrasında hızlanmasını sağlar.
Doğrusal bir eğrinin parametreleri, animasyonun sabit bir hızda oynatılmasını sağlar. Bu değerleri sana özel animasyon eğrileri oluşturmak için tanımlayabilirsin ancak
KeyframedMovementmodülünde tanımlanan değerleri kullanacağın için bu örnekte tanımlamana gerek yok.PauseSecondsadlı düzenlenebilir bir kayan değer seçeneği. Bu değer, bu animasyon segmentini başlatmadan önce duraklanacak süredir (saniye cinsinden). Bunu bir varlığın yolu üzerindeki bir noktadan diğerine hareket etmeden önce durakladığı süre olarak düşünebilirsin.
Verse# The number of seconds to pause before starting this animation segment. @editable: ToolTip := PauseTip PauseSeconds:?float = falseAnimate_to_targets_componentsınıf tanımına geri dönerek aşağıdaki alanları ekle:Segmentler adlı düzenlenebilir bir
segmentdizisi. Bu, varlığın üzerinden geçtiği genel animasyonu oluşturan her bir animasyon segmentine referans verecektir.
Verse# Segments of the keyframed movement animation. @editable: ToolTip := SegmentsTip var Segments<private>:[]segment = array{}DefaultEasingFunctionadlı düzenlenebilir biryavaşlatma fonksiyonu. Bir animasyon segmenti bir hareket hızı fonksiyonu belirtmiyorsa bu varsayılan olarak kullanılacaktır. Bunusustain_in_out_cupic_bezier_asse_functionolarak ayarla.
Verse# Movement easing function between two targets @editable: ToolTip := DefaultEasingFunctionTip var DefaultEasingFunction<public>:easing_function = ease_in_out_cubic_bezier_easing_function{}Kodunu kaydet ve derle. Editörde animate_to_targets_component bileşeninin bağlı olduğu varlıklar üzerinde
segmentlerdizisini görebilirsin.
Kod ile Anahtar Kareler Oluşturma
Segment sınıfın tamamlandıktan sonra segmentlerin tanımladığı anahtar kareleri oluşturma zamanı gelir. Anahtar kareleri ayrı ayrı oluşturup bir diziye ekleyecek, ardından diziyi keyframed_movement_component bileşenine ileteceksin. Bunun için biraz matematik hesaplaması gerekir ve şimdi bunları tanımlayacaksın.
Matematik işlemleri çeşitli senaryolarda kullanışlı olduğundan bu mantığı herhangi bir Verse bileşeninden erişilebilen bir yardımcı dosyaya yerleştirmek faydalıdır. Varlıklarla çalışırken kullanabileceğin daha fazla Verse örnek uygulaması için Kendi Verse Bileşenini Oluşturma bölümünden daha fazla bilgi alabilirsin. Yardımcı dosyanı oluşturmak için şu adımları izle:
animate_to_targets.versedosyandaİşlevsellikleradlı yeni bir modül oluştur. Bu şekilde, projende kullanacağın ortak mantık depolanır.Verse# Module containing utility functions. Utilities<public> := module:Sol,Yukarıveİlerideğerlerinin tamamının1,0olarak ayarlandığı durumlarda birvector3oluşturan İşlevsellikler modülünevector3türünde,VectorOnesadlı yeni bir takma ad ekle. Bu vektörü daha sonra bazı matematiksel işlemleri kolaylaştırmak için kullanacaksın dolayısıyla bunun için türün diğer adını tanımladığında tekrar tekrarvector3{Left := 1.0, Up := 1.0, Forward := 1.0}yazmak zorunda kalmazsın. Çünkü/Verse.org/SpatialMathve/UnrealEngine.com/Temporary/SpatialMathmodüllerinin ikisini de içe aktardın. Her iki modül de tanım içerdiğinden bunun bir/Verse.org/SpatialMathvector3olduğunu belirtmen gerekir.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}UtilitiesmodülüneGetDeltaTransform()adlı yeni bir fonksiyon ekle. Bu fonksiyon iki dönüşüm arasındaki farkı hesaplar ve deltayı geri döndürür. Geri alınmasına izin vermek için bu fonksiyona<transacts>değiştiricisini ekle./Verse.org/SpatialMathbelirtinçünkü varlık dönüşümleri arasındaki farkı sen hesaplayacaksın.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=GetDeltaTransformiçinde yeni bir/Verse.org/SpatialMathdönüşümübaşlat.Yer değiştirmeyiher bir dönüşümün yer değiştirmesi arasındaki farka ayarla.Dönüşdeğerini,MakeComponentWiseDeltaRotation()çağrısının sonucuna ayarla. Bu fonksiyon/UnrealEngine.com/Temporary/SpatialMathmodülünde yer aldığından/Verse.org/SpatialMathdönüşlerinden/UnrealEngine.com/Temporary/SpatialMathdönüşlerine dönüştürmen gerekir. Bunu,fromRotation()fonksiyonunu kullanarak yapabilirsin. Her birdönüşümün fromRotation() iledönüştürüldükten sonra dönüşünü ileterekMakeComponentWiseDeltaRotation() işlevini çağır. Ardından, tekrar/Verse.org/SpatialMathdosyasına dönüştürmek içinFromRotation()öğesini kullanarak bu işlev çağrısının sonucunu dönüştür dönüş. Son olarak, ölçeği, birinci ve ikinci ölçekler arasındaki farkın ilk ölçeğe oranınaVectorOneseklendiğinde çıkan sonuca ayarla. Bunu yapmak, animasyon sırasında varlığının doğru şekilde ölçeklenmesini sağlar. TamamlanmışGetDeltaTransform()fonksiyonun şu şekilde görünmelidir: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)Son olarak,
UtilitiesmodülüneTryGetvalueOrDefault()adlı bir fonksiyon ekle, fonksiyona da<transacts>değiştiricisini ekle. Bu fonksiyon; bir türdeoptiondeğeri ve aynı türde varsayılan bir değer alır ve varsayılan değeri veya varsavalueiçindeki öğeyi döndürür. Bunu yapmak, bir sınıftaki bir değerin gerçekten başlatılıp başlatılmadığını kontrol etmek istediğinde faydalıdır ve başlatılmamışsa bir değer döndürmeni garanti eder.TriGetValueOrDefault()içinde,value'nun bir değer içerip içermediğini kontrol et ve onu döndür. Aksi takdirdedefaultdöndür. TamamlanmışUtilitiesmodülün veTriGetValurOrDefault()fonksiyonun şu şekilde görünmelidir: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=
Matematiğin tanımlanmış olduğuna göre artık anahtar karelerini koddan oluşturabilirsin!
Anahtar kare oluşturma fonksiyonlarını oluşturmak için aşağıdaki adımları izle:
Animate_to_targetssınıf tanımınaConstructKeyframe()adlı yeni bir fonksiyon ekle. Bu fonksiyon; bir kaynak varlık, bir hedef varlık, bir isteğe bağlı yavaşlatma fonksiyonu ve bir süre alır. Hatta birkeyframed_movements_deltadizisi döndürür.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=ConstructKeyframe()fonksiyonunda, ilk olarakGetGlobalTransform()fonksiyonunu çağırarakkaynakvehedefvarlıkların dönüşümlerini elde et.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()Tek bir
keyframed_movement_deltaüyesiyle bir dizi başlat.Dönüşümdeğerini, kaynak ve hedef dönüşümleri iletenGetDeltaTransform()çağrısının sonucuna ayarla veSüreveYavaşlatmadeğerlerini bu fonksiyona iletilen değerlere ayarla. TamamlanmışConstructKeyframe()fonksiyonun şu şekilde görünmelidir: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
Bu fonksiyon ayrı anahtar kareler oluşturur ancak tam animasyonlar oluşturmak için daha fazla mantığa ihtiyacın vardır.
Animate_to_targetssınıf tanımınaConstructAndPlayAnimations()adlı yeni bir fonksiyon ekle. Bu fonksiyon, bir segment dizisini ve animasyon kayıttan oynatma modunu alır ve bunları tam bir animasyon oluşturup oynatmak için kullanır. Asenkron çalışmasına izin vermek için bu fonksiyona<suspends>değiştiricisini ekle.Verse# Construct and play an animation from an array of animation segments. ConstructAndPlayAnimations<private>(InSegments:[]segment, AnimationPlayback:keyframed_movement_playback_mode)<suspends>:void=ConstructAndPlayAnimations()içindeShouldBreakOutadında yeni birmantıkdeğişkeni tanımla ve bunufalseolarak başlat. Belirtilen anahtar kareli üç hareket oynatma modunun her birini ayrı ele alman gerekecektir. Pinpon döngü modlarını işlemek üzere sürekli olarak animasyonlar oluşturmak için birloopifadesi kullanacaksın fakat tek çekim modu ilk yinelemede döngüden çıkmalıdır. Animasyon oynatma modunun tek seferlik mod olup olmadığını kontrol et ve tek seferlikseShouldBreakOutdeğerini true olarak ayarla.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 = trueDaha sonra, bir
ififadesinde,KeyframedMovementComponentdeğişkenindeki varlığınkeyframed_movement_componentdeğerini al. Daha sonra animasyonun başlangıç dönüşümünüInSegmentsdizisindeki ilk elemanı ve ardından onun genel dönüşümünü alarakStartingTransformadlı değişkende al.Verse# Position this entity in the correct starting position. if: KeyframedMovementComponent := Entity.GetComponent[keyframed_movement_component] StartingTransform := FirstSegment := InSegments[0].SegmentStartPosition?.GetGlobalTransform()Son olarak, global dönüşümü başlangıç dönüşümüne ayarlayarak varlığı başlangıç konumunda konumlandır ve animasyon oynatılmadan önce
InitialPauseSecondsiçin uykuya geçir.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)Şimdi sıra, animasyonu oluşturacağın anahtar kare dizisini oluşturmaya geldi. Öncelikle
Keyframesadlı yeni birkeyframed_movement_deltadeğişken dizisini başlat. BirforifadesindeInSegmentsdizisindeki her bir segmenti yinele veIndexadlı yerel değişkenden hem segmenti hem de dizinini al.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?Şimdi,
TryGetValueOrDefault()fonksiyonunu çağırarak,Segment.EasingFunctionveDefaultEasingFunction’ı geçirerekYavaşlatmaadlı yerel bir değişkende bu anahtar kare için kullanılan yavaşlatma fonksiyonunu al. AyrıcaSegment.AnimationDurationdeğişkenindenSüreyerel değişkenindeki animasyon segmentinin süresini al. Tüm değerlerini ayarladıktan sonra birififadesinde her bir değeriConstructKeyframe[]’e ileterek anahtar kareyi oluştur ve sonucuAnahtar Karelerdizisine ekle. Tüm anahtar karelerin oluşturulduğunda, anahtar kareli hareket bileşenindeSetKeyframes()çağırarak veAnahtar Kareler dizisinivePlaybackMode'u geçirerek anahtar kare dizisini ayarla.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.Anahtar kareler dizinin ayarlandığında bunları oynatmaya başlayabilirsin. Animasyonun bir döngü üzerinde çalışması gerekir ancak animasyon modu tek çekim olarak ayarlanmışsa ilk yinelemeden sonra durmalıdır. Ayrıca segmentte
PauseSecondsvarsa her anahtar karede duraklatmayı da işlemesi gerekir. Bu sorunu çözmek için içindeforifadesi bulunan birdöngüifadesi oluştur.forifadesinde,Anahtar Karelerdizisindeki her bir anahtar kareyi yinelerken birKeyframeIndexdeğişkenindeki her anahtar karenin dizinini al.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):forifadesinde,KeyframeIndexkullanıpInSegmentsdizisinde dizin oluşturarak bu anahtar kareyle ilişkili segmenti al. Ardından segmenttePauseSecondsvarsa bu süre içinSleep()fonksiyonunu çağır. Daha sonraKeyframedMovementComponent.Play() öğesiniçağır, ardındanKeyframeReachedEventöğesini bekleyipKeyframedMovementComponent.Pause() öğesiniçağır. Bunun yaptığı, bir sonraki anahtar kareyi oynatıp beklemeden ve tekrar duraklatmadan önce her anahtar karede animasyonuPauseSecondssüre boyunca duraklatır. Son olarak,loopifadesinin sonundaShouldBreakOutdeğerinin true olup olmadığını kontrol et ve true ise döngüden çık.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()Tamamlanan
ContstructAndPlayAnimations()fonksiyonun aşağıdaki gibi görünmelidir: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.
Bir sonraki adımda animasyonlu varlığının bir prefabını oluşturacak ve bölümde somut hale getireceksin!