Scene Graph, varlıklar ile bileşenler arasındaki birçok farklı etkileşim aracılığıyla esnek ve dinamik bir oyun deneyimi oluşturmanın birden fazla yolunu sunar. Bu şablon, çalışma zamanında varlıkları, üreterek ve kaldırarak nasıl değiştirebileceğine dair yöntemlerden birkaçını ve varlıklar arasında iletişim kurmak ve yeniden kullanılabilir oyun öğeleri oluşturmak için nasıl bileşen olaylarını ve sorgulamayı kullanabileceğini gösterir.
Prefabları Üretme ve Kaldırma
Örneğin, ikinci holdeki etkileşimli kareye göz at. Oyuncu kareye bastığında sahneye bir prefab fener eklenir ve oyuncu kareden indiğinde kaldırılır.
Bu kodun nasıl çalıştığına göz atmak için SpawnPrefabDevice.verse’ü aç. Bu, bir oyuncunun ona ne zaman girdiğini anlamak için Bölge cihazı kullanan bir kreatif cihazıdır. Daha sonra bir prefab üretir ve oyuncu tetikleyiciden indiğinde onu kaldırır. SpawnPrefabDevice sınıf tanımının üst kısmında, düzenlenebilir bir TriggerVolume, bölümdeki tetikleyici bölgesine referans verir.
SpawnPrefabDevice := class(creative_device):
@editable
TriggerVolume:volume_device = volume_device{}Oyun başladığında cihaz, üretilecek yeni bir ışık direği prefabının yanı sıra bunun üretileceği konumu tanımlar.
OnBegin<override>()<suspends>:void =
PrefabToSpawn:entity = LightPost.P_LightPost{}
SpawnTransform:transform = transform:
Translation := vector3:
Left := -9084.0
Up := -8.0
Forward := -919.0Ardından simülasyon varlığını alır ve üzerinde çalışacağı bir dizi başarısızlık bağlamı oluşturur. Öncelikle kodu içeride tekrarlayarak çalıştırmak için döngü, ardından iki block ifadesi arasında bir race kullanır.
if:
SimulationEntity := GetSimulationEntity[]
then:
loop:
race:
block:
TriggerVolume.AgentEntersEvent.Await()
SimulationEntity.AddEntities(array{ PrefabToSpawn })
PrefabToSpawn.SetGlobalTransform(SpawnTransform)
İlk block ifadesi, bir aracının bölge cihazına girmesini bekler. Aracı, cihaza girdiğinde AddEntities()’i kullanarak fener prefabını sahneye ekler ve SetGlobalTransform()’u kullanarak prefabı doğru şekilde konumlandırır. İkinci block, aracının bölgeden ayrılıp prefabı üst varlığından, yani bu durumda simülasyon varlığından kaldırmasını bekler.
Bu block’lar bir döngü içinde birbirleriyle race halinde olduklarından her biri her zaman çalışır durumdadır; böylece oyuncu ışık direğini dilediği kadar çok defa yeniden üretmek için bölgeye girebilir ve bölgeden çıkabilir!
Tam Kod
Sahneye varlık ekleme ve sahneden varlık çıkarmaya dair kodun tamamını aşağıda görebilirsin.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/SceneGraph }
using { /Verse.org/SpatialMath }
using { /UnrealEngine.com/Temporary/Diagnostics }
SpawnPrefabDevice := class(creative_device):
Varlık Çakışmaları
İkinci holde de varlıkların etkileşimde bulunmasının farklı yollarından bazılarını gösteren bir dizi örnek bulunur. Örneğin, örgü bileşeni olan varlıklar, başka bir varlıkla çakıştıklarında örgü bileşeninin EntityEnteredEvent ve EntityExitedEvent olayları aracılığıyla uyarılabilir. Bu işlevselliği çalışır halde görmek için ikinci holdeki UFO örneğine göz atabilirsin.
Oyun başladığında inek, UFO tarafından kaçırılıyormuş gibi kendini kaldırmak için bir animasyon oynatır. İnek, UFO ile ne zaman çakıştığını anlamak için örgü bileşeninin EntityEnteredEvent’ini kullanır ve ardından kendisini kaçırılmış gibi göstermek için görünmez olarak ayarlar.
Bu örneğin kodu EntityEnteredExampleComponent.verse içinde tanımlanmıştır. Bu dosyayı Verse Gezgini’nden açabilirsin.
asset_entered_example_component sınıfı öncelikle, inek kaçırma animasyonunu oluşturmada kullanacağı düzenlenebilir bir Anahtar Kareler dizisi tanımlar. İneğin sahnedeki başlangıç pozisyonunu belirtmek için bir StartTransform değişkeni de tanımlar.
entity_entered_example_component<public> := class<final_super>(component):
@editable
Keyframes:[]keyframed_movement_delta = array{}
var StartTransform:transform = transform{}OnBeginSimulation()’da kod öncelikle fort_round_manager’ı alır. Bu, bir raundun başlangıcına ve bitişine olaylar bağlamak için kullanabileceğin bir Fortnite raunt yöneticisi arayüzüdür. Bu örnekte kodlar, OnRoundStarted() fonksiyonunu SubscribeRoundStarted()’i kullanarak raundun başlangıcına bağlar. Diğer bir deyişle fonksiyon, varlık simülasyona başladığında değil de oyun başladığında çalışacaktır.
OnBeginSimulation<override>():void =
(super:)OnBeginSimulation()
if:
FortRoundManager := Entity.GetFortRoundManager[]
then:
FortRoundManager.SubscribeRoundStarted(OnRoundStarted)Ardından OnRoundStarted()’de kod öncelikle, StartTransform’u varlığın global dönüşümüne ayarlayıp örgü bileşeninin EntityEnteredEvent’ini, başka bir örgü, varlıkla her çakıştığında tetiklenecek olan yeni bir OnEntityEntered() fonksiyonuna bağlar. Sonrasında ineği kaldırmaya başlamak için bir PlayCowAbductionAnimation() fonksiyonu üretir.
OnRoundStarted():void =
set StartTransform = Entity.GetGlobalTransform()
if:
Mesh := Entity.GetComponent[mesh_component]
then:
Mesh.EntityEnteredEvent.Subscribe(OnEntityEntered)
spawn { PlayCowAbdcutionAnimation() }PlayCowAbductionAnimation() fonksiyonu yalnızca ineğin global dönüşümünü onun başlangıç dönüşümüne ayarlar ve kısa bir süre boyunca bekler. Sonrasında varlıktan örgü ve anahtar kare hareketi bileşenlerini alır, ineği görünür hale getirmek için örgüyü etkinleştirir ve ardından anahtar kareli hareket bileşeninde animasyonu ayarlayıp oynatır.
PlayCowAbdcutionAnimation()<suspends>:void =
Entity.SetGlobalTransform(StartTransform)
Sleep(2.0)
if:
Mesh := Entity.GetComponent[mesh_component]
MovementComponent := Entity.GetComponent[keyframed_movement_component]
then:
set Mesh.Visible = true
MovementComponent.SetKeyframes(Keyframes, oneshot_keyframed_movement_playback_mode{})
MovementComponent.Play()Son olarak, inek başka bir varlıkla (bu örnekte UFO ile) her çakıştığında kod çalıştırmak için OnEntityEntered() fonksiyonu kullanılır. İnek başka bir varlıkla çakıştığında, örgü ve anahtar kareli hareket bileşenlerini tekrar alır ancak bunları devam eden tüm animasyonları oynatmayı durdurup ineği görünmez yaparak kaçırılmış gibi göstermek için kullanır. Ardından işlemi baştan başlatmak için yeni bir PlayCowAbductionAnimation() örneği üretir.
OnEntityEntered(OtherEntity:entity):void =
if:
Mesh := Entity.GetComponent[mesh_component]
MovementComponent := Entity.GetComponent[keyframed_movement_component]
then:
MovementComponent.Stop()
set Mesh.Visible = false
spawn { PlayCowAbdcutionAnimation() }Tam Kod
Bir UFO örgüsü ile bir İnek kaçırma örgüsüne dair kodun tamamını aşağıda görebilirsin.
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
using { /Verse.org/SceneGraph/KeyframedMovement }
using { /Verse.org/SpatialMath }
using { /Fortnite.com/Game }
entity_entered_example_component<public> := class<final_super>(component):
Çakışma İsabetlerini Sorgulama
Varlıklar, çakışma sorguları kullanarak başka varlıkları da sorgulayabilir. Çakışma sorguları, bir varlığın belirli bir örgüye ne zaman girdiğini veya o örgüden ne zaman çıktığını algılamak yerine belirli bir alanla çakışan her varlığı ve bileşeni döndürmek için kullanılabilir.
Bu alan; varlığın kendisi, küre veya kutu gibi belirli bir çarpışma etki aktörü veya varlığın simüle edileceği bir konum olabilir. Ardından bir overlap_hit listesi döndürür. Her overlap_hit sana, kaynak bölgenin çakıştığı bileşen veya bölge hakkında bilgi verir ve bu bileşenlerin ilişkili varlığını bulmak için onları sorgulayabilirsin.
Örneğin, FindOverlapHits örneğinin önündeki etkileşimli kareye basmayı dene. Kare ile etkileşime girdiğinde, UFO görünmez bir çarpışma bölgesi oluşturur ve bunu bir çakışma sorgusu gerçekleştirmek için kullanır. Çarpışma bölgesi inekle çakışırsa UFO onu kaçırır!
Bu örneğin kodu FindOverlapHitsExampleComponent.verse içinde tanımlanmıştır. Bu dosyayı Verse Gezgini’nden açabilirsin.
Sınıf, öncelikle, oyuncunun üzerine bastığı etkileşimli kareye referans vermek için Tetikleyici adlı düzenlenebilir bir bölge cihazının yanı sıra ineğin kaçırılmakta olup olmadığını belirlemeye yönelik olan IsAbducting mantık değişkenini tanımlar. Bileşen simülasyona başladığında, OnRoundStarted() fonksiyonunu raunt yöneticisinin raunt başlangıcına bağlar. OnRoundStarted() fonksiyonu da benzer şekilde Tetikleyici’deki AgentEntersEvent’i OnTriggerEntered()’e, AgentExitsEvent’i ise OnTriggerExited()’e bağlar.
find_overlaphits_example_component<public> := class<final_super>(component):
@editable
Trigger:volume_device = volume_device{}
var IsAbducting:logic = false
OnBeginSimulation<override>():void =
Oyuncu kareye bastığında, UFO o sırada bir inek kaçırmıyorsa UFO’nun yapıyor olabileceği herhangi bir hareketi, onun keyframed_movement_component’ini alarak ve Pause()’yi çağırarak duraklatmak için OnTriggerEntered() fonksiyonu çağrılır. Ardından, kaçırılma ışınını etkinleştirmek ve ineğin UFO’nun altında olup olmadığını kontrol etmek için EnableAbductionBeam()’ı ve PlayerOverlapCheck()’i çağırır.
OnTriggerEntered(Agent:agent):void=
if:
not IsAbducting?
MovementComponent := Entity.GetComponent[keyframed_movement_component]
then:
MovementComponent.Pause()
EnableAbductionBeam()
PerformOverlapCheck()Çakışmaları kontrol etmenin fiili mantığı, PerformOverlapCheck() fonksiyonunda depolanır. Bu fonksiyon, bir kaçırılma ışınını simüle etmek için bir çarpışma kapsülü üretir ve UFO’nun hemen altına ayarlanan bir CollisionTransform tanımlar.
PerformOverlapCheck():void =
CollisionCapsule := collision_capsule{Radius := 36.0, Length := 328.0}
var CollisionTransform:transform = Entity.GetGlobalTransform()
set CollisionTransform.Translation.Up = CollisionTransform.Translation.Up - 248.0Ardından bir for ifadesiyle, tüm bileşenleri veya bölgeleri bulup döndürmek için FindOverlapHits()’i çağırır. Çarpışma olup olmadığına dair kontrol yapılacak bölge olarak CollisionCapsule’ü, çarpışmanın simüle edilmesinde kullanılacak yer olarak ise CollisionTransform’u iletir. Sonrasında her çakışmayı yineler ve çakışan bileşenin bir örgü bileşeni, özellikle de inek varlığındaki SM_Toy_Cow örgüsü olup olmadığını kontrol eder. Eğer öyleyse kaçırılacak ineği ileten bir AbductCow() fonksiyonu üretir.
# Perform the overlap check from the entity that contains the mesh_component
for:
Overlap : Entity.FindOverlapHits(CollisionTransform, CollisionCapsule)
# Cast to see if what was overlapped was the Cow
CowMesh := Meshes.SM_Toy_Cow[Overlap.TargetComponent]
CowPrefab := CowMesh.Entity
do:
spawn { AbductCow(CowPrefab) }Varlık, ineği kaçırmayı simüle etmek için bir animasyon oluşturur ve ardından onu, yukarıdaki Varlık Çakışmaları örneğine benzer şekilde inek varlığı üzerinde oynatır. Bu kod inekten değil de UFO varlığından çağrıldığından kodun inek varlığından bileşenler alması, ardından oynatılması için bir animasyon iletmesi gerekir. Öncelikle, inekten örgüyü ve anahtar kareli hareket bileşenlerini alır, ardından da IsAbducting’i true olarak ayarlar.
AbductCow(CowEntity:entity)<suspends>:void =
# Get the components on the Cow Prefab
if:
CowMesh := CowEntity.GetComponent[mesh_component]
MovementComponent := CowEntity.GetComponent[keyframed_movement_component]
then:
set IsAbducting = trueİnek kaçırma animasyonunda kullanılan anahtar kareler, anahat düzenleyicisinde ayarlanmadığından kodun bunları UFO ile inek arasındaki konum farkına dayalı olarak oluşturması gerekir. Bunu yapmak için inek ile UFO arasındaki yer değiştirme farkını alır, sonra bu değerlerden yeni bir keyframed_movement_delta oluşturur. Ardından bu tek anahtar kareyi, anahtar kareli hareket bileşeninde bir dizi olarak ayarlar ve ineğin başlangıç konumu ile UFO arasında animasyonlu hale gelmesini sağlamak için oynatmayı çağırır.
# Get the delta between Cow and UFO
DeltaTransform:transform = transform:
Translation:= Entity.GetGlobalTransform().Translation - CowEntity.GetGlobalTransform().Translation
Scale := vector3{Left:= 0.0, Up:= 0.0, Forward:= 0.0}
# Create a key frame
Keyframe := keyframed_movement_delta:
Transform := DeltaTransform
Duration := 2.0
Easing := ease_in_cubic_bezier_easing_function{}
İnek, kaçırıldığında UFO ile animasyonlu hale gelebilir ancak kod onun, UFO’nun kendisi ile çakıştığında da kaybolmasını sağlamalıdır. Kod, bunu yapmak için inekten, örgü bileşeninin EntityEnteredEvent’ini bekler ve ardından inek varlığını sahneden kaldırmak için RemoveFromParent()’i çağırır. İnek gittiğinden UFO tekrar devriye gezmeye başlayabilir; dolayısıyla kod, UFO’yu hareket ettirmek için onun anahtar kareli hareket bileşeninde oynatmayı çağırır.
# Wait for Entity Entered Event
CowMesh.EntityEnteredEvent.Await()
# Remove Cow from world
CowEntity.RemoveFromParent()
# Resume UFO Patrol
set IsAbducting = false
if:
UFOMovementComponent := Entity.GetComponent[keyframed_movement_component]
Son olarak, EnableAdbuctionBeam() ve DisableAbductionBeam() fonksiyonları, her çağrıldıklarında UFO’daki kaçırma ışını örgüsünü açan, spot ışığı bileşenlerini ise kapatan basit yardımcılar olarak işlev görür.
EnableAbductionBeam():void =
for:
Mesh : Entity.FindDescendantComponents(Meshes.S_EV_SimpleLightBeam_01)
do:
Mesh.Enable()
for:
Light : Entity.FindDescendantComponents(spot_light_component)
do:
Light.Enable()
Tam Kod
Çakışma isabetlerini sorgulamaya yönelik kodun tamamını aşağıda görebilirsin.
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
using { /Verse.org/Colors }
using { /Verse.org/SceneGraph/KeyframedMovement }
using { /Verse.org/SpatialMath }
using { /Fortnite.com/Game }
using { /Fortnite.com/Devices }
Süpürme İsabetlerini Sorgulama
Süpürme isabetleri, varlıklar arasındaki çakışmaları sorgulamanın başka bir önemli yolunu sağlar. Süpürme, bir objeyi belirli bir vektör üzerinde belirlenmiş bir mesafe boyunca hareket ettirmeyi ifade eder. Örneğin, oyuncuları bir boşluğa itmek için bir bloku platform üzerinde hareket ettirmek veya bir duvarı yok etmek için ileriye doğru bir roket fırlatmak.
FindSweepHits() fonksiyonu, bir sweep_hit listesi döndürür. Her sweep_hit sana, bileşen veya bölge isabeti ve süpürmeyi yapan kaynak bölge veya bileşen gibi bir overlap_hit ile aynı bilgileri verir. Ayrıca temas konumu, normal, yüz normali ve süpürme üzerinde isabetin gerçekleştiği mesafe hakkında bilgiler verir.
Şablon, önceki çakışma isabetleri örneğinin daha gelişmiş bir versiyonunu oluşturmak için süpürme isabetlerini kullanır. Bu örneği kontrol etmek için ikinci holdeki son etkileşimli kare üzerine basmayı dene. Karenin üzerine bastığında UFO, bir kaçırılma ışını üretir. Ardından UFO örgüsünden aşağıya doğru bir süpürme isabeti gerçekleştirerek süpürmenin çakıştığı ilk varlığı kontrol eder. Varlık bir inek ise UFO, onu normal bir şekilde kaçırır. Ancak inek bir küre varlık tarafından korunuyorsa süpürme önce küreye isabet edecek ve bloklanacak ve böylece UFO’nun ineği kaçırması önlenecektir.
Kodu incelemek için Verse Gezgini’nden FindOverlapHitsExampleComponent.verse’ü aç. Buradaki kurulum, ineği kaçırma ve kaçırma ışınını etkinleştirme ve devre dışı bırakma için kullanılan mantığın aynısına sahip olup yukarıdaki çakışma isabetleri örneğine çok benzerdir. En büyük fark, oyuncunun, örneğin önündeki etkileşimli kareye basmasıyla çalışan OnTriggerEntered() fonksiyonunda ortaya çıkar.
Bu fonksiyonun kodu çakışma isabetleri örneğine benzer şekilde başlayarak varlıktan anahtar kareli hareket bileşenini alır ve kaçırma ışınını etkinleştirir.
OnTriggerEntered(Agent:agent):void=
# When a cow is inside the abduction area, stop the ship moving and start the abduction beam.
if:
not IsAbducting?
MovementComponent := Entity.GetComponent[keyframed_movement_component]
then:
MovementComponent.Pause()
EnableAbductionBeam()Ancak fonksiyon çakışmalar yerine süpürmeler kullandığından ineğin kaçırma ışınının altında olup olmadığına dair mantık biraz farklıdır. Öncelikle UFO varlığının ilk alt öğesini, yani bu durumda UFO’nun örgü varlığını alır. Ardından süpürmenin yapılmaya başlanacağı noktada, UFO’dan dümdüz bir şekilde aşağıya bakan bir yer değiştirme vektörü oluşturur.
# Perform the sweep from the UFO Mesh
if (Child := Entity.GetEntities()[0]):
DisplacementVector := vector3{Left:=0.0, Up:=-300.0, Forward:=0.0}Sonrasında bu yer değiştirme vektörünü kullanarak FindFirstSweepHit() yardımcı fonksiyonunu çağırır ve böylece UFO’nun örgüsünü ve vektörü iletir. İlk bileşen ineğin örgü bileşeniyse ineğin kaçırılmasını simüle etmek için AbductCow() fonksiyonunu üretir.
# Perform the sweep from the UFO Mesh
if (Child := Entity.GetEntities()[0]):
DisplacementVector := vector3{Left:=0.0, Up:=-300.0, Forward:=0.0}
FirstSweepHitEntity := FindFirstSweepHit(Child, DisplacementVector)
# If the First Hit Entity is the Cow Mesh, then abduct the Cow
if (HitEntity := FirstSweepHitEntity?; HitEntity.GetComponent[Meshes.SM_Toy_Cow]):
spawn { AbductCow(HitEntity) }FindFirstSweepHit() fonksiyonu, süpürülecek varlığı ve onu süpürmek için yer değiştirme vektörünü alır. Bir süpürmeyi simüle etmek için FindSweepHits()’i çağrıır ve sonra bir `for` ifadesiyle döndürülen her süpürme isabetini yineler. Her sweep_hit bir bileşen veya bölge içerdiğinden onun hangi türden olduğunu öğrenmek için TargetComponent’i veya TargetVolume’ü sorgulayabilirsin. Bu durumda kod, TargetComponent’in sahip olan varlığını alır ve onu bir seçenek olarak döndürür; yani, süpürme bir bileşene isabet ederse `true`, aksi takdirde ise `false` döndürecektir.
# Returns the first Entity hit by FindSweepHits
FindFirstSweepHit(InEntity:entity, DisplacementVector:vector3):?entity =
for (SweepHit : InEntity.FindSweepHits(DisplacementVector)):
return option{ SweepHit.TargetComponent.Entity }
return falseTam Kod
Süpürme isabetlerini sorgulamaya yönelik kodun tamamını aşağıda görebilirsin.
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
using { /Verse.org/Colors }
using { /Verse.org/SceneGraph/KeyframedMovement }
using { /Verse.org/SpatialMath }
using { /Fortnite.com/Game }
using { /Fortnite.com/Devices }