Etiketli Işıklar Bulmacası için herhangi bir Verse kodu yazmaya başlamadan önce yapmak istediğin şeyi başarmanın en iyi yolununun ne olabileceğini düşün. Bu bölümde bir bulmaca mekaniği oluştururken nasıl bir yaklaşım benimsenmesi gerektiği gösteriliyor. Bu adımın sonunda bu bulmacayı oluşturma algoritmasını temsil eden sözde kodu elde edeceksin. Sonraki adımda bu algoritmanın Verse ve UEFN’de nasıl uygulanacağı gösterilecektir.
Hedefleri, Gereksinimleri ve Kısıtlamaları Belirle
İlk adım hedeflerini, gereksinimlerini ve kısıtlamalarını belirlemektir. Gereksinimler çoğunlukla büyük hedeflerin daha küçük kısımlara bölünmesinden doğar.
| Hedefler |
|
| Gereksinimler |
|
| Kısıtlamalar |
|
Sorunu Parçalara Ayır
Artık ne istediğini ve neyle çalıştığını anladığına göre sorunu çözümlemesi daha kolay olabilecek küçük sorunlara bölmen faydalı olacaktır. Sorular sormak büyük bir sorunu parçalarına ayırmaya yardımcı olabilir:
- Oyuncu bulmacayla nasıl etkileşime girebilir?
- Işıkları bulmak için Oynanış Etiketlerini nasıl kullanırsın?
- Editörde özelleştirilebilen başlangıç koşullarını ve çözümleri nasıl tanımlarsın?
- Bir Verse yapısında depolanmış oyun durumunu oyun içi görsellerle nasıl eşleştirirsin?
- Bir oyuncu etkileşimi belirli bir ışık kümesini nasıl güncelleyebilir?
- Bulmaca çözüldükten sonra oyuncu etkileşimini nasıl devre dışı bırakırsın?
Bundan sonra, bu küçük sorunlar arasındaki olası bağımlılıkları belirlemelisin. Bu durumda sorunlar birbirinden bağımsız görünüyor ancak şunlar üzerinde düşünmeye değer:
- Soru 1, 5 ve 6 birbiriyle hafif bağlantılı.
- Soru 1 ve 6’da oyuncunun bulmacayla nasıl etkileşime girdiği, bulmaca çözüldükten sonra etkileşimin nasıl devre dışı bırakıldığını belirleyemez.
- Soru 1 ve 5’te tek bir etkileşim, birden fazla ışığı tek seferde açıp kapatır. Bu işlem, etkileşim-ışık eşleştirmesi için kullanılacak veri yapısına ışık tutar.
- Soru 2 önemli bir tasarım konusudur. Oynanış Etiketleri API’sinin işleyiş biçimi, ışıkların kodda nasıl kontrol edildiğini etkileyebilir. Bunun soru 4 ve 5’e ilişkin sonuçları vardır çünkü oyun içi ışık durumunu değiştirmen gerekecek, bu yüzden bunu yapmanın bir orta yolunu bulmalısın.
- Soru 3 ve 4 büyük olasılıkla başlangıç durumu, geçerli durum ve çözüm durumu için altta yatan veri yapısına yönelik tek bir çözümde birleşecektir.
Potansiyel Çözümler Tasarla
Sorun artık daha küçük sorunlara ayrıldığına göre daha küçük sorunlara bağlı soruları yanıtlamaya odaklan:
1. Oyuncu bulmacayla nasıl etkileşime girebilir?
Bu sorunun birden fazla çözümü vardır. Genellikle oyuncunun etkileşime girebileceği ve Verse’ün etkileşimi algılamak için kullanabileceği herhangi bir cihazı kullanabilirsin. Kreatif araç setinde bu gereksinimleri karşılayan çok sayıda cihaz bulunur, örn. Tetikleyici cihazları, Buton cihazları, Renk Değiştiren Kare cihazları ve Algı Tetikleyicisi cihazları.
Bu örnekte Buton cihazı ve buton etkin olduğu sürece oyuncu butonla her etkileşime girdiğinde gönderilen InteractedWithEvent işlevi kullanılacaktır. Olaylar hakkında daha fazla bilgi için Cihaz Etkileşimlerinin Kodlanması bölümüne bakabilirsin.
2. Işıkları bulmak için Oynanış Etiketlerini nasıl kullanırsın?
Oynanış Etiketleri ile Verse kodunda tanımladığın özel bir etiketin atandığı aktör gruplarını alabilirsin.
Özel etiketinin atandığı tüm aktörlerden oluşan bir dizi almak için GetCreativeObjectsWithTag() işlevini kullanabilirsin. İşlevin sonucu, creative_object_interface uygulayan tüm objelerden oluşan bir dizidir. customizable_light_device bir Özelleştirilebilir Işık cihazının Verse’teki gösterimidir ve creative_object_interface uygulayan bir sınıftır.
GetCreativeObjectsWithTag() tarafından döndürülen cihaz listesi için kesin bir sıra yoktur ve özellikle bölümde çok sayıda cihaz olması durumunda işlev çağrısının tüm cihazları döndürmesi zaman alabilir. Bu yüzden ışıkları daha sonra hızlı erişim için kaydetmek iyi bir fikirdir. Bu işlem önbelleğe alma olarak adlandırılır ve çoğu zaman performansı artırır. Işıklar aynı türlerin bir koleksiyonu olduğu için onları bir arada depolamak için bir dizi kullanabilirsin.
Bu sayede şunları yapabilirsin:
puzzle_lightadlı yeni bir etiket oluştur.- Bulmacanın tüm ışıklarını
puzzle_lightetiketiyle işaretle. puzzle_lightetiketine sahip tüm aktörleri almak içinGetCreativeObjectsWithTag(puzzle_light)fonksiyonunu çağır.- Fonksiyon çağrısındaki sonuçlardan hangilerinin bir
customizable_light_deviceolduğunu belirle. customizable_light_deviceobjelerinin listesini daha sonra erişebilmek için bir dizi olarak kaydet.
3. Editörde özelleştirilebilen başlangıç koşullarını ve çözümleri nasıl tanımlarsın?
Bir ışığın yalnızca iki durumu vardır: açık veya kapalı. logic türünün değerleri yalnızca true veya false olabileceğinden Verse’te bir ışığın açık/kapalı durumunu temsil etmesi için logic türünü kullanabilirsin. Birden fazla ışık olduğundan burada tüm logic değerlerini kaydetmek için bir dizi kullanabilir ve bir ışık durumu için dizi konumunu veya dizini, ilişkili olduğu ışığın diziniyle eşleştirebilirsin.
Bu logic değerleri bulmaca ışıklarının başlangıç durumunu tanımlamak için kullanılabilir ve aynı zamanda oyun sırasında ışıkların geçerli durumunu içerebilir. Bu diziyi @editable özniteliğiyle editörde kullanıma alabilirsin. Bundan sonra oyunun başındaki ışıklar, dizide depolanmış durumla görsel olarak eşleşmesi için açılabilir veya kapatılabilir.
Bulmacanın çözümü, ışıkların geçerli durumunu kaydetmek için kullanılan türle eşleşmelidir. Böylece ikisini karşılaştırarak bulmacanın çözülüp çözülmediğini kontrol edebilirsin. Bunun anlamı, biri ışıkların geçerli durumunu, diğeri ise bulmacanın çözümünü temsil eden iki tane düzenlenebilir logic dizisine sahip olacağındır. Bunun anlamı, bulmaca ışıklarının başlangıç durumunu ve bulmacanın çözümünü editörden değiştirebileceğin ve böylece bulmacayı farklı yapılandırmalarla yeniden kullanabileceğindir.
4. Bir Verse yapısında depolanmış oyun durumunu oyun içi görsellerle nasıl eşleştirirsin?
Bir customizable_light_device cihazını oyun içinde TurnOn() ve TurnOff() işlevlerini kullanarak açabilir veya kapatabilirsin. Bu nedenle mantık dizisiyle gösterilen ışıkların geçerli durumunu her güncellediğinde oyun içi görselleri oyun durumuyla eşleştirmek için TurnOn() ve TurnOff() işlevlerini de çağırman gerekir.
5. Bir oyuncu etkileşimi belirli bir ışık kümesini nasıl güncelleyebilir?
İlk sorudan sonra oyuncunun Buton Cihazını kullanarak bulmacayla etkileşime gireceğini zaten belirledin. Bir olay işleyiciyi, oyuncu Buton Cihazı ile etkileşime girdiğinde ışıkları değiştirecek Buton InteractedWithEvent olayına abone yapabilirsin. Oyuncunun kullanabileceği birden fazla buton olduğundan burada yine bir dizi kullanarak onları bir arada tutabilirsin.
Şimdi her bir ayrı buton olayını, açıp kapatması gereken ışık kümeleriyle nasıl eşleştireceğini belirlemen gerekiyor.
customizable_light_device dizisindeki ışıkların sırası ışıkların durumunu temsil eden mantık dizisiyle aynı olacağından bir buton ile etkileyeceği ışıkların dizinleri arasında eşleştirme oluşturabilirsin. Bu eşleştirme, öğelerin sırasıyla butonların sırasının eşleştiği ve öğelerin dizin dizileri olduğu bir dizide gösterilebilir.
Editörde buton-ışık eşleştirmesini değiştirebilmek ve kodu değiştirmeden bulmacayı yeniden kullanabilmek için diziyi düzenlenebilir hale getirebilirsin.
6. Bulmaca çözüldükten sonra oyuncu etkileşimini nasıl devre dışı bırakırsın?
InteractedWithEvent ile de algılandığı gibi, oyuncunun bulmacayla Buton Cihazını kullanarak etkileşimde bulunduğunu zaten biliyorsun.
Bulmaca çözüldükten sonra oyuncunun bulmacayı daha fazla değiştirememesi için bulmaca cihazı oyuncudan girdi almayı nasıl durdurabilir?
Bunu yapmanın en az üç yolu vardır:
- Bulmaca çözüldüğünde oyun içi butonları devre dışı bırak.
tagged_lights_puzzlefonksiyonuna bulmaca çözüldüğünde değiştirilen birlogicalanı ekle. Oyun durumu her güncellendiğinde bulmacanın henüz çözülmediğinden emin olmak için öncelikle bulogicalanı kontrol edilmelidir.- Bulmaca çözüldüğünde olay işleyicilerin bir daha çağrılmaması için butonların
InteractedWithEventaboneliğinden çık.
Üçüncü çözüm en iyisidir çünkü basit ve verimli bir çözümdür. Koşullu kod yürütmeyi kontrol etmek için yeni alanlar oluşturman gerekmez. Bir cihaz olayının aboneliğinden çıkma kavramı diğer durumlarda da yeniden kullanılabilir. Genel olarak, bir olay hakkında bildirim almak istediğinde olaya abone olmak ve artık bildirime ihtiyaç duymadığında abonelikten çıkmak iyi bir uygulamadır. Abonelikten çıkma uygulamasının ayrıntıları bu eğitimin sonraki bölümlerinde açıklanacak.
Çözümleri ve Planı Sözde Kod ile Birleştir
Artık daha küçük sorunların çözümlerini elde ettiğine göre bunları birleştirip asıl sorunu çözebilirsin. Sözde kod kullanarak çözümü derleyecek algoritmayı biçimlendir.
Oyun başladığında ne olur? Işıklar ayarlanır. Butonlar InteractedWithEvent olayına abone olursun, puzzle_light etiketine sahip tüm cihazları bulursun ve önbelleğe alırsın. Ayrıca LightState durumunu başlatarak oyun içi ışıkları açabilir/kapatabilirsin.
OnBegin:
Result of GetCreativeObjectsWithTag(puzzle_light) is stored in the variable FoundDevices
for each Device in FoundDevices:
if Device is a Customizable Light Device:
Store the Light
if ShouldLightBeOn?:
Turn on Light
else:
Turn off Light
for each Button:
Subscribe to the Button InteractedWithEvent using the handler OnButtonInteractedWith
OnButtonInteractedWith işlevinin sözde kod sürümü, InteractedButtonIndex değeri oyuncunun etkileşime girdiği Buton ile eşleşen button_device dizisinin dizini olacak şekilde aşağıdaki gibi görünür. Bu bilgiyi olay işleyicinin içinde nasıl alacağını eğitimin sonraki bölümlerinde göreceksin.
OnButtonInteractedWith:
Get lights associated with the button interacted with using the ButtonsToLights array and store in the variable Lights
# Işıkları aç/kapat
for each Light in Lights:
if IsLightOn?:
Set the Light game state to off
Turn off Light
else:
Set the Light game state to on
Turn on Light
if IsPuzzleSolved():
Enable Item Spawner
for each Button:
Unsubscribe from the Button InteractedWithEvent
IsPuzzleSolved sözde kodu, ışıkların geçerli durumunun çözümle eşleşip eşleşmediğini kontrol eder. Geçerli durum çözümle eşleşmezse kontrol başarısız olur ve yukarıdaki sözde kodda yer alan if IsPuzzleSolved bloğu çalıştırılmaz. Geçerli durum çözümle eşleşirse kontrol başarılı olur ve yukarıdaki sözde kodda yer alan if IsPuzzleSolved bloğu çalıştırılır.
IsPuzzleSolved:
for each Light:
if IsLightOn is not equal to IsLightOnInSolution
fail and return
başarılı olmak
Artık algoritmanı geliştirdin!
Sonraki Adım
Bu eğitimin bir sonraki adımında bu algoritmayı Verse programlama diline çevirecek ve bu adımları uygulamada görmek için projene oynanış testi uygulayacaksın.