Bölge, oyuncunun eşyaları alabileceği veya teslim edebileceği bir harita alanıdır (bir cihaz ile gösterilir). Time Trial: Pizza Pursuit eğitimindeki bu adımı tamamlayarak bu alma ve teslim bölgelerini nasıl oluşturacağını ve oyuncu için nasıl etkinleştireceğini/devre dışı bırakacağını öğreneceksin.
Bir Bölge Sınıfı Oluşturmak İçin Soyutlama Kullanma
Soyutlama, kullanıcının karmaşık konuları anlamasının gerekmediği durumlarda gereksiz ayrıntıların kullanıcıdan gizlendiği bir programlama ilkesidir. Soyutlama, bir şeyin işleyişini öğretmeden o şeyin ne olduğunu açıklar. Örneğin, bir otomata para koyabilir ve teknik ayrıntıların nasıl işlediğini anlamadan güzel bir yiyecek alabilirsin.
Time Trial: Pizza Pursuit oyununda iki tür bölge vardır: Eşya çıkma yeri cihazını kullanan alma bölgeleri ve ele geçirme alanı cihazını kullanan teslim bölgeleri. Bu bölgeler farklı cihazlar olmasına rağmen aynı şekilde davranacağından (yani her ikisi de etkinleştirilebilir ve devre dışı bırakılabilir) bu davranışı belirli cihaz etkileşimlerini işleyen bir genel bölge objesine çıkarmak için bir sınıf oluşturabilirsin.
Bu davranışın bir sınıfa soyutlanması, kullandığın cihaz türünü tek bir yerden değiştirebileceğin anlamına gelir. Bu sınıfı kullanan herhangi bir kod yalnızca etkinleştirme/devre dışı bırakma işlevlerini bileceği için bu uygulama aynı zamanda diğer kodlarının hiçbirini değiştirmeden spesifik özellikleri değiştirebileceğin anlamına gelir.
Bu bölge sınıfını oluşturmak için şu adımları izle:
- pickup_delivery_zone.verse adlı yeni bir boş Verse dosyası oluştur ve Visual Studio Code ile aç.
- Verse dosyasında
public
belirleyicisi ilebase_zone
adlı yeni bir sınıf oluştur ve şunları ekle:- Bölgede kullanılan cihazı depolamak için
public
belirleyicisi ileActivatorDevice
olarak adlandırılmış bircreative_object_interface
sabiti. - Oyuncu eşya alma veya teslim etme gibi eylemlerle bu bölgeyle etkileşime geçtiğinde sinyal vermek için
public
belirleyicisine sahipZoneCompletedEvent
adlı bir olay. - Bölge için kullanılan cihazı etkinleştirmek için
void
dönüş türüne vepublic
belirleyicisine sahipActivateZone()
adlı bir işlev. - Bölge için kullanılan cihazı devre dışı bırakmak için
void
dönüş türüne vepublic
belirleyicisine sahipDeactivateZone()
adlı bir işlev.
base_zone<public> := class: ActivatorDevice<public> : creative_object_interface ZoneCompletedEvent<public> : event(base_zone) = event(base_zone){} ActivateZone<public>() : void = Print("Zone activated") DeactivateZone<public>() : void = Print("Zone deactivated")
Bir sınıf ve üyeleri
public
belirleyicisine sahip olduğunda bu sınıfa ve üyelerine diğer kodlardan evrensel olarak erişilebilir. Daha ayrıntılı bilgi için Belirleyiciler ve Öznitelikler bölümüne bakabilirsin. - Bölgede kullanılan cihazı depolamak için
ActivateZone()
işlevindeActivatorDevice
cihazını farklı türlere dönüştürerekActivatorDevice
cihazının bir Ele Geçirme Alanı cihazı mı yoksa Eşya Oluşturma Yeri cihazı mı olduğunu kontrol et ve dönüştürülen cihazdaEnable()
işlevini çağır. Aynı işlemiDeactivateZone()
işlevi için de yap ancakDisable()
işlevini çağırma.base_zone<public> := class: ActivatorDevice<public> : creative_object_interface ActivateZone<public>() : void = Print("Zone activated") if (CaptureArea := capture_area_device[ActivatorDevice]): CaptureArea.Enable() else if (ItemSpawner := item_spawner_device[ActivatorDevice]): ItemSpawner.Enable() DeactivateZone<public>() : void = Print("Zone deactivated") if (CaptureArea := capture_area_device[ActivatorDevice]): CaptureArea.Disable() else if (ItemSpawner := item_spawner_device[ActivatorDevice]): ItemSpawner.Disable()
private
belirleyicisine vesuspends
belirleyicisine sahipWaitForZoneCompleted()
adlı bir fonksiyon oluştur. Bu fonksiyon, cihaza özgü olay gerçekleştiğindeZoneCompletedEvent
sinyalini verecektir. Bu ayar sonucunda diğer kodunZoneCompletedEvent
sinyalini beklemesi ve altta yatan cihazın kullandığı olayın türünü göz ardı etmesi gerekir.WaitForZoneCompleted<private>(ZoneDeviceCompletionEventOpt : ?awaitable(agent))<suspends> : void = if (DeviceEvent := ZoneDeviceCompletionEventOpt?): DeviceEvent.Await() ZoneCompletedEvent.Signal(Self)
Bu işlevin
DeviceEvent.Await()
çağrısı yapabilmek içinsuspends
efektine sahip olması gerekir.ActivateZone()
fonksiyonunu cihazla etkileşimde bulunan oyuncu için uygun cihaz olayını kullanarakWaitForZoneCompleted()
çağrısı yapan birspawn
ifadesiyle güncelle: Ele geçirme alanı cihazı içinAgentEntersEvent
ve eşya çıkma yeri cihazı içinItemPickedUpEvent
.WaitForZoneCompleted
,awaitable(agent)
türünde biroption
(?
ile gösterilir) parametresi bekler. Böyleceawaitable
arayüzünü uygulayan herhangi bir türü, bu türünagent
değerine eşit parametrik türüyle geçirebiliriz. HemCaptureArea.AgentEntersEvent
hem deItemSpawner.ItemPickedUpEvent
bu koşulla uyumlu olduğu için bunları parametre olarak kullanabiliriz. Bu da soyutlamanın bir diğer örneğidir.ActivateZone<public>() : void = Print("Zone activated") if (CaptureArea := capture_area_device[ActivatorDevice]): CaptureArea.Enable() spawn { WaitForZoneCompleted(option{CaptureArea.AgentEntersEvent})} else if (ItemSpawner := item_spawner_device[ActivatorDevice]): ItemSpawner.Enable() spawn { WaitForZoneCompleted(option{ItemSpawner.ItemPickedUpEvent}) }
protected
belirleyicisine sahipZoneDeactivatedEvent
adlı başka bir olay ekle. Bu olay, oyuncu tamamlamadan bölge devre dışı bırakılırsaWaitForZoneCompleted()
fonksiyonunu sonlandırmak için gereklidir. Bu olayıDeactivateZone()
fonksiyonunda bildir.ZoneDeactivatedEvent<protected> : event() = event(){} DeactivateZone<public>() : void = Print("Zone deactivated") if (CaptureArea := capture_area_device[ActivatorDevice]): CaptureArea.Disable() else if (ItemSpawner := item_spawner_device[ActivatorDevice]): ItemSpawner.Disable() ZoneDeactivatedEvent.Signal()
WaitForZoneCompleted()
fonksiyonunu, oyuncunun bölgeyi tamamlamasını veya bölgenin devre dışı bırakılmasını bekleyecek şekilde birrace
ifadesiyle güncelle.race
ifadesiyleZoneDeactivatedEvent.Await()
asenkron fonksiyon çağrısı, cihaz olayı veZoneCompletedEvent
sinyali ile deblock
ifadesi aynı zamanda çalışır ancak ilk önce tamamlanmayan ifade iptal edilir.WaitForZoneCompleted<private>(ZoneDeviceCompletionEventOpt : ?awaitable(agent))<suspends> : void = if (DeviceEvent := ZoneDeviceCompletionEventOpt?): race: block: DeviceEvent.Await() ZoneCompletedEvent.Signal(Self) ZoneDeactivatedEvent.Await()
- Son olarak
base_zone
sınıfı için bir oluşturucu üreterekActivatorDevice
alanı başlat.MakeBaseZone<constructor><public>(InActivatorDevice : creative_object_interface) := base_zone: ActivatorDevice := InActivatorDevice
base_zone
sınıfı için tam kod aşağıdaki gibidir.<# Bölge, Etkinleştirilebilen/Devre Dışı Bırakılabilen ve bölge "Tamamlandı" duruma geldiğinde (bir sonraki etkinleştirmeye kadar bir daha tamamlanamaz) sinyal veren olaylar sağlayan bir harita alanıdır (bir cihaz ile gösterilir). "Tamamlandı" bölgesi, bölgenin cihaz türüne (ActivatorDevice) bağlıdır. Önerilen kullanım: ActivateZone() -> ZoneCompletedEvent.Await() -> DeactivateZone() #> base_zone<public> := class: ActivatorDevice<public> : creative_object_interface ZoneCompletedEvent<public> : event(base_zone) = event(base_zone){} GetTransform<public>() : transform = ActivatorDevice.GetTransform() <# Bölgeyi etkinleştirir. Bölge için cihazları ve her türlü görsel göstergeyi buradan etkinleştirmelisin. #> ActivateZone<public>() : void = # Temel bölge, eşya oluşturma yeri veya ele geçirme alanı olarak tanımlanan bölgeleri işleyebilir. # Hangi bölge üzerinde işlem yaptığımızı görmek için her bir türe dönüştürmeyi dene. if (CaptureArea := capture_area_device[ActivatorDevice]): CaptureArea.Enable() spawn { WaitForZoneCompleted(option{CaptureArea.AgentEntersEvent}) } else if (ItemSpawner := item_spawner_device[ActivatorDevice]): ItemSpawner.Enable() spawn { WaitForZoneCompleted(option{ItemSpawner.ItemPickedUpEvent}) } <# Bölgeyi devre dışı bırakır. Bölge için cihazları ve her türlü görsel göstergeyi buradan devre dışı bırakmalısın. #> DeactivateZone<public>() : void = if (CaptureArea := capture_area_device[ActivatorDevice]): CaptureArea.Disable() else if (ItemSpawner := item_spawner_device[ActivatorDevice]): ItemSpawner.Disable() ZoneDeactivatedEvent.Signal() <# Bölge tamamlanmadan devre dışı bırakılırsa WaitForZoneCompleted eş yordamını sonlandırmak için bu olay gereklidir. #> ZoneDeactivatedEvent<protected> : event() = event(){} WaitForZoneCompleted<private>(ZoneDeviceCompletionEventOpt : ?awaitable(agent))<suspends> : void = if (DeviceEvent := ZoneDeviceCompletionEventOpt?): race: block: DeviceEvent.Await() ZoneCompletedEvent.Signal(Self) ZoneDeactivatedEvent.Await() MakeBaseZone<constructor><public>(InActivatorDevice : creative_object_interface) := base_zone: ActivatorDevice := InActivatorDevice
Oynanış Etiketleriyle Çalışma Zamanında Bölge Bulma
Artık bölgeleri oluşturmanın ve etkinleştirmenin/devre dışı bırakmanın yolunu öğrendiğine göre bölümde etiketlediğin tüm bölgeleri başlatma ve etkinleştirilecek bir sonraki bölgeyi seçmenin bir yolunu ekleyelim.
Bu örnek, bu işlemin bölge oluşturmaktan ve etkinleştirilecek bir sonraki bölgeyi seçmekten sorumlu bir sınıfla nasıl yapılacağını gösteriyor.
Bölge oluşturmak ve seçmek üzere sınıf oluşturmak için şu adımları izle:
- pickup_delivery_zone.verse dosyasında
tagged_zone_selector
adlı yeni bir sınıf oluştur. Tüm bölgeleri bölümde depolamak için bir değişken dizisi ekle.tagged_zone_selector<public> := class: var Zones<protected> : []base_zone = array{}
- Söz konusu Oynanış Etiketiyle ilişkili tüm bölgeleri bulmak ve önbelleğe almak için
public
belirleyicisine ve birtag
parametresine sahipInitZones()
adlı bir metot ekle.InitZones<public>(ZoneTag : tag) : void = <# Bir bölge seçici oluşturulduğunda tüm kullanılabilir bölgeleri bul ve bir sonraki bölgenin seçildiği her durumda etiketli cihazları ararken zaman kaybetmemek için önbelleğe al. #> ZoneDevices := GetCreativeObjectsWithTag(ZoneTag) set Zones = for (ZoneDevice : ZoneDevices): MakeBaseZone(ZoneDevice)
- Metodun başka bir bölge bulması veya başarısız olması için
decides
vetransacts
belirleyicisine sahipSelectNext()
adlı bir metot ekle. Dizin içinGetRandomInt(0, Zones.Length - 1)
kullanarak dizideki rastgele bir dizinde bulunan bölgeyi seç.SelectNext<public>()<transacts><decides> : base_zone = Zones[GetRandomInt(0, Zones.Length - 1)]
- pickup_delivery_zone.verse dosyasının tam kodu şu anda böyle görünmelidir:
using { /Verse.org/Simulation } using { /Verse.org/Random } using { /Verse.org/Concurrency } using { /Verse.org/Simulation/Tags } using { /UnrealEngine.com/Temporary/SpatialMath } using { /Fortnite.com/Devices } <# Bölge, Etkinleştirilebilen/Devre Dışı Bırakılabilen ve bölge "Tamamlandı" duruma geldiğinde (bir sonraki etkinleştirmeye kadar bir daha tamamlanamaz) sinyal veren olaylar sağlayan bir harita alanıdır (bir cihaz ile gösterilir). "Tamamlandı" bölgesi, bölgenin cihaz türüne (ActivatorDevice) bağlıdır. Önerilen kullanım: ActivateZone() -> ZoneCompletedEvent.Await() -> DeactivateZone() #> base_zone<public> := class: ActivatorDevice<public> : creative_object_interface ZoneCompletedEvent<public> : event(base_zone) = event(base_zone){} GetTransform<public>() : transform = ActivatorDevice.GetTransform() <# Bölgeyi etkinleştirir. Bölge için cihazları ve her türlü görsel göstergeyi buradan etkinleştirmelisin. #> ActivateZone<public>() : void = # Temel bölge, eşya oluşturma yeri veya ele geçirme alanı olarak tanımlanan bölgeleri işleyebilir. # Hangi bölge üzerinde işlem yaptığımızı görmek için her bir türe dönüştürmeyi dene. if (CaptureArea := capture_area_device[ActivatorDevice]): CaptureArea.Enable() spawn { WaitForZoneCompleted(option{CaptureArea.AgentEntersEvent}) } else if (ItemSpawner := item_spawner_device[ActivatorDevice]): ItemSpawner.Enable() spawn { WaitForZoneCompleted(option{ItemSpawner.ItemPickedUpEvent}) } <# Bölgeyi devre dışı bırakır. Bölge için cihazları ve her türlü görsel göstergeyi buradan devre dışı bırakmalısın. #> DeactivateZone<public>() : void = if (CaptureArea := capture_area_device[ActivatorDevice]): CaptureArea.Disable() else if (ItemSpawner := item_spawner_device[ActivatorDevice]): ItemSpawner.Disable() ZoneDeactivatedEvent.Signal() <# Bölge tamamlanmadan devre dışı bırakılırsa WaitForZoneCompleted eş yordamını sonlandırmak için bu olay gereklidir. #> ZoneDeactivatedEvent<protected> : event() = event(){} WaitForZoneCompleted<private>(ZoneDeviceCompletionEventOpt : ?awaitable(agent))<suspends> : void = if (DeviceEvent := ZoneDeviceCompletionEventOpt?): race: block: DeviceEvent.Await() ZoneCompletedEvent.Signal(Self) ZoneDeactivatedEvent.Await() MakeBaseZone<constructor><public>(InActivatorDevice : creative_object_interface) := base_zone: ActivatorDevice := InActivatorDevice # tagged_zone_selector, InitZones’a geçirilen etiketlerin eklendiği tetikleyicilere göre bölgeler oluşturur. tagged_zone_selector<public> := class: var Zones<protected> : []base_zone = array{} InitZones<public>(ZoneTag : tag) : void = <# Bir bölge seçici oluşturulduğunda tüm kullanılabilir bölgeleri bul ve bir sonraki bölgenin seçildiği her durumda etiketli cihazları ararken zaman kaybetmemek için önbelleğe al. #> ZoneDevices := GetCreativeObjectsWithTag(ZoneTag) set Zones = for (ZoneDevice : ZoneDevices): MakeBaseZone(ZoneDevice) SelectNext<public>()<transacts><decides> : base_zone = Zones[GetRandomInt(0, Zones.Length - 1)]
Alma ve Teslim Bölgelerini Test Etme
Artık iki sınıf oluşturduğuna göre bölge seçiminin beklediğin gibi çalıştığından emin olmak için kodunu test etmende yarar var.
game_coordinator_device.verse dosyanı güncellemek için şu adımları izle:
game_coordinator_device
cihazına teslim bölgesi seçici için bir sabit ve alma bölgesi seçicileri için bir değişken dizi ekle. Oyun her pizza alımından sonra alma seviyesini yükselteceğinden oyunda istediğin her alma seviyesi için birtagged_zone_selector
ve dolayısıylaPickupZoneSelectors
dizisi gerekecektir. Her bölge seçici, belirli bir seviyenin tüm alma bölgelerini tutar. Bunun bir değişken olması gerekir çünkü ayarı,PickupZoneLevelTags
içindekipickup_zone_tag
etiketlerinin sayısına göre belirlenir.- Kodda minimum değişiklik yaparak alma seviyelerinin sayısını artırmak için bu ayarı kullan: Tek yapman gereken
PickupZoneLevelTags
fonksiyonunupickup_zone_tag
etiketinden türetilen etiketlerle güncellemek, ardından editörde cihazları etiketlemek.game_coordinator_device<public> := class<concrete>(creative_device): DeliveryZoneSelector<private> : tagged_zone_selector = tagged_zone_selector{} var PickupZoneSelectors<private> : []tagged_zone_selector = array{}
SetupZones()
adlı bir metot oluştur veOnBegin()
fonksiyonunda metodu çağır:- Yöntemi
private
belirleyicisine ve birvoid
dönüş türüne sahip olacak şekilde ayarla. - Teslim bölgesi seçiciyi
delivery_zone_tag
ile başlat. - Alma bölgesi seviye etiketlerini oluştur ve alma bölgesi seçicileri başlat.
OnBegin<override>()<suspends> : void = SetupZones() SetupZones<private>() : void = DeliveryZoneSelector.InitZones(delivery_zone_tag{}) PickupZoneLevelTags : []pickup_zone_tag = array{pickup_zone_level_1_tag{}, pickup_zone_level_2_tag{}, pickup_zone_level_3_tag{}} set PickupZoneSelectors = for(PickupZoneTag : PickupZoneLevelTags): PickupZone := tagged_zone_selector{} PickupZone.InitZones(PickupZoneTag) PickupZone
- Yöntemi
OnBegin()
içinde bir sonraki alma bölgesini seçen, etkinleştiren, oyuncunun bölgeyi tamamlamasını bekleyen ve sonra bölgeyi devre dışı bırakan bir döngü oluştur.OnBegin<override>()<suspends> : void = SetupZones() var PickupLevel : int = 0 loop: if (PickupZone : base_zone = PickupZoneSelectors[PickupLevel].SelectNext[]): PickupZone.ActivateZone() PickupZone.ZoneCompletedEvent.Await() PickupZone.DeactivateZone() else: Print("Can't find next PickupZone to select") return if (DeliveryZone := DeliveryZoneSelector.SelectNext[]): DeliveryZone.ActivateZone() DeliveryZone.ZoneCompletedEvent.Await() DeliveryZone.DeactivateZone() else: Print("Can't find next DeliveryZone to select") return
- Verse dosyalarını kaydet, kodunu derle ve bölümüne oynanış testi uygula.
Bölümüne oynanış testi uyguladığında oyunun başlangıcında Eşya Oluşturma Yeri cihazlarından biri etkinleşir. Eşya aldıktan sonra Eşya Oluşturma Yeri cihazı devre dışı kalır ve sonra bir Ele Geçirme Alanı cihazı etkinleşir. Bu döngü sen oyunu manuel olarak sonlandırana kadar devam eder.