Scene Graph eğitimindeki fenerlerde, birden fazla Verse ile yazılmış bileşen kullanılarak dinamik ve etkileşimli prefablar oluşturulur. Bu, hareketin ve etkileşime geçilebilirliğin Verse ile yazılmış bir bileşende programlanmasıyla mümkündür.
Basit Hareketleri Simüle Etme
Işık direği prefabında, fenerin hareket ettirilmesini simüle etmek için iki farklı bileşen kullanılır. Bunların her ikisi de feneri etrafta hareket ettirmek için bir pivot noktası sağlayan Pivot varlığına bağlıdır. Öncelikle, keyframed_movement_component, anahtar karelerden animasyonlar oluşturmana ve ardından bir varlığı animasyonlu hale getirmek için onları oynatmana olanak tanır. Ancak bu bileşen tek başına hareket edemez ve anahtar kareleri sağlamak ve animasyonu başlatmak için başka bir kod parçasına ihtiyaç duyar. simple_movement_component da burada devreye girer. Bu kod, farklı oyun objelerinin sahnede nasıl hareket ettiğini kontrol etmek için proje genelinde yeniden kullanılır.
Objeleri hareket ettirmek için animasyonları kullanma konusunda daha fazla bilgi edinmek için Nesne Hareketine Animasyon Uygulama bölümüne göz atabilirsin.
Şimdi, simple_movement_component’e daha yakından bakalım. Başlamak için Visual Studio Kodu’ndaki Verse Gezgini’nden SimpleMovementComponent.verse kodunu aç.
Animasyonlar, bir animasyon tamamlandığında onun ne yapması gerektiğini tanımlamak için farklı kayıttan oynatma modları kullanır. Bunlar movement_mode enum’unda dosyanın en üstünde tanımlanır:
Tek Çekim - Obje, animasyonu bitirdiğinde hareket etmeyi durdurur.
Döngü - Obje, sona ulaştığında animasyonu baştan yeniden başlatır.
Pinpon - Obje, animasyonu, baştan sona ileri geri giderek tersten oynatır.
movement_mode<public> := enum:
OneShot
Loop
PingPongbasic_movement_component sınıfı, animasyonlar oluşturmak için gereken değişkenleri de tanımlar. Bunların her biri, bunları anahat düzenleyicisinden düzenlemene olanak tanıyan @editable özniteliğine sahiptir:
Anahtar kareler: Animasyonu oluşturmak için kullanılankeyframed_movement_deltadizisi. Bunların her biri, bu anahtar karedeki dönüşüm değişikliğini, anahtar karenin süresini ve kullanılan hareket hız düzenleme türünü takip eder.AutoPlay: Varlık simülasyona başladığında onun animasyonlu hale gelmesi gerekip gerekmediğini belirleyen birmantıkdeğişkeni.MovementMode: Varlığın sergilediği hareket davranışı.
# A Verse-authored component that can be added to entities
basic_movement_component<public> := class<final_super>(component):
@editable
var Keyframes<public>: []keyframed_movement_delta = array{}
@editable
var AutoPlay: logic = true
OnSimulate()’teki kod, bileşen sahneye her eklendiğinde ve oyun başladığında çalışmaya başlar. Burada, kod, çalışmadan önce tüm varlıkların ve bileşenlerin doğru bir şekilde başlatıldığından emin olmak için kısa bir Sleep() çağrısı kullanır. Ardından bir if ifadesiyle varlığın bir keyframed_movement_component’e sahip olup olmadığını kontrol eder.
Varlık, bir keyframed_movement_component’e sahipse bileşeni uygun değerlerle ayarlamak için InitializeKeyFramedMovementComponent()’i çağırır. Peki ya varlık bir keyframed_movement_component’e sahip değilse ne olur? Bu durumda, çalışma zamanında dinamik olarak bir keyframed_movement_component oluşturabilir ve bunu AddComponents() fonksiyonunu kullanarak varlığa ekleyebilirsin. Böylece oyun başladığında varlığının doğru şekilde ayarlanmış olduğunu garanti edersin!
OnSimulate<override>()<suspends>:void =
Sleep (0.1)
if:
KeyframedMovementComponent := Entity.GetComponent[keyframed_movement_component]
then:
InitializeKeyframedMovementComponent(KeyframedMovementComponent)
else:
NewKeyFramedMovementComponent := keyframed_movement_component { Entity := Entity }
Entity.AddComponents of array { NewKeyFramedMovementComponent }
InitializeKeyframedMovementComponent(NewKeyFramedMovementComponent)InitializeKeyframedMovementComponent() fonksiyonu, anahtar kareli hareket bileşenini, editörde atadığın değerlere dayalı değerlerle ayarlar. Öncelikle, bu animasyon sırasında kullanılan kayıttan oynatma modunu belirlemek için yeni bir keyframed_movement_playback_mode değişkeni oluşturur. Bu, oneshot_keyframed_movement_playback_mode değeriyle başlatılır; yani, animasyon yalnızca bir kez oynatılacaktır.
InitializeKeyframedMovementComponent(InKeyframedMovementComponent:keyframed_movement_component):void =
var PlaybackMode:keyframed_movement_playback_mode = oneshot_keyframed_movement_playback_mode{}Daha sonra bir case ifadesi kullanarak PlaybackMode’u editörde ayarlanan MovementMode değerine göre ayarlar. MovementMode enum’u içindeki her değer, SceneGraph/KeyframedMovement modülünde tanımlanan farklı bir kayıttan oynatma moduna karşılık gelir.
case (MovementMode):
movement_mode.OneShot =>
set PlaybackMode = oneshot_keyframed_movement_playback_mode{}
movement_mode.Loop =>
set PlaybackMode = loop_keyframed_movement_playback_mode{}
movement_mode.PingPong =>
set PlaybackMode = pingpong_keyframed_movement_playback_mode{}Son olarak, fonksiyon, anahtar kareli hareket bileşeninde anahtar kareleri ve hareket modunu ayarlar; böylece animasyon artık oynatılmaya hazırdır. AutoPlay değişkeni true olarak ayarlanırsa animasyon, anahtar kareli hareket bileşeninin Play() fonksiyonu çağırarak hemen başlar.
InKeyframedMovementComponent.SetKeyframes(Keyframes, PlaybackMode)
if:
AutoPlay?
then:
InKeyframedMovementComponent.Play()Editörde ise simple_movement_component, Pivot varlığına eklenir ve aşağıdaki değerlerle ayarlanır. Artık oyun başladığında fener, ileri geri sallanmaya başlayacaktır!
Tam Kod
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
using { /Verse.org/SceneGraph/KeyframedMovement }
movement_mode<public> := enum:
OneShot
Loop
Fener ile Etkileşime Geçme
Fener ileri geri sallanabilir, ancak oyuncunun onunla etkileşime girebilmesi için başka bir parçaya ihtiyacın olacaktır. Bunu yapmak için Fener varlığına etkileşime geçilebilir bir bileşen, ışık direğine ise feneri açıp kapatabilmeni sağlayan özel bir Verse lantern_interaction_component’i eklemen gerekir.
Verse Gezgini’nden LanternInteractionComponent.verse kodunu aç. Bu kod öncelikle, Assets.digest.verse’te tanımlanan LightPost modülünü içe aktarır. Assets.digest.verse, ışık direğiyle ilgili prefab gibi tüm öğelerin depolandığı yerdir. Kod, ışık direğine ve fenerin materyal ve örgülerine erişmek için LightPost.Materials modülünü de içe aktarır.
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
LightPost := module:
Materials<public> := module:
lantern_interaction_component sınıfı öncelikle, LightPost.Materials.MI_Lantern_01 ile başlatılan MaterialInstance adlı bir değişken tanımlar. Bu, fenerin materyaliyle ilgili tüm değişkenleri içeren materyal örneğidir.
lantern_interaction_component<public> := class<final_super>(component):
var MaterialInstance:LightPost.Materials.MI_Lantern_01 = LightPost.Materials.MI_Lantern_01{}OnBeginSimulation()’da kod öncelikle, alt varlıklarında, bir interactable_component ekli olan her bileşeni bulur. lantern_interaction_component, ışık direğine bağlı olduğundan bu, Fener varlığının interactable_component’ini döndürecektir, çünkü o, ışık direğinin alt öğesidir.
OnBeginSimulation<override>():void =
(super:)OnBeginSimulation()
InteractabeleComponents := Entity.FindDescendantComponents(interactable_component)Ardından kod, bir for ifadesiyle, bulunan her etkileşime geçilebilir bileşende yinelenir ve bunların SucceededEvent’ini bu dosyanın sonraki bölümlerinde tanımlanacak olan OnInteractFinished() fonksiyonuna bağlar. Artık bir oyuncu fenerle etkileşimini tamamladığında OnInteractFinished() tetiklenecektir.
InteractabeleComponents := Entity.FindDescendantComponents(interactable_component)
for (InteractableComponent : InteractabeleComponents):
InteractableComponent.SucceededEvent.Subscribe(OnInteractFinished)Sonrasında OnBeginSimulation() fonksiyonu, bir LightPost.SM_Lightpost_Lantern_01 bileşeni ekli olan her varlığı bulmak için tekrar FindDescendantComponents’i çağırır. Bu, fenere ekli olan örgü bileşenidir. Ardından örgü bileşenini, daha önce tanımlanan MaterialInstance’a ayarlayarak fenerin örgüsünün doğru bir şekilde başlatılmasını sağlar.
MeshComponents := Entity.FindDescendantComponents(LightPost.SM_Lightpost_Lantern_01)
for (MeshComponent : MeshComponents):
set MeshComponent.M_Lantern = MaterialInstanceOnInteractFinished() fonksiyonu, etkileşimin başlatıcısı olarak Aracıyı veya oyuncuyu alır. Bu fonksiyon, feneri açıp kapatmak için ToggleLight() fonksiyonunu çağırır.
Fenerin açılıp kapatılmasına dair asıl işi ToggleLight() fonksiyonu üstlenir. Öncelikle, bir if ifadesiyle MaterialInstance yayıcı seviyesinin, ışığın kapalı olduğunu belirten şekilde 0,0 olup olmadığını kontrol eder. Değer 0,0 ise yayıcı seviyesini 1,0 olarak ayarlar. Ardından iki for ifadesiyle alt varlıklar üzerindeki her light_component ve particle_system_component’i bulur ve bunları, light_component için Enable()’ı, particle_system_component içinse Play()’i çağırarak açar.
ToggleLight():void =
if (MaterialInstance.Emissive_Multiply = 0.0):
set MaterialInstance.Emissive_Multiply = 1.0
for:
Light : Entity.FindDescendantComponents(light_component)
do:
Light.Enable()
for:
Işık zaten açıksa fonksiyon else ifadesinin içinde bunun tersini yapar. Materyal yayıcı seviyelerini 0,0 olarak ayarlar ve alt varlıklar üzerindeki tüm ışık ve parçacık sistemi bileşenlerini devre dışı bırakır.
else:
set MaterialInstance.Emissive_Multiply = 0.0
for:
Light : Entity.FindDescendantComponents(light_component)
do:
Light.Disable()
for:
Particle : Entity.FindDescendantComponents(particle_system_component)
Bu koddaki fonksiyonlar bir araya gelerek feneri dinamik hale getirir ve bir oyuncu fenerle etkileşime girdiğinde birden fazla bileşeni açıp kapatır. Açılan ve kapatılan fener olsa da lantern_interaction_component’i sağlayanın, onun üst ışık direği varlığı olduğunu unutma.
Birden fazla ışığı olan ve bu ışıkların her birini tek bir düğmeye basarak açıp kapattığın bir ışık direğine sahip olmak için ne yapman gerektiğini düşün. Bu kod, belirli bir bileşen türüne sahip alt varlıkları bularak çalıştığından bu işlevselliği uygulamak için fazladan bir Verse koduna ihtiyacın olmayacaktır. Her alt fener varlığının bir ışık bileşeni veya parçacık bileşeni olduğu sürece sorun yok demektir!
Tam Kod
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
LightPost := module:
Materials<public> := module: