Herkese mutlu günler Sevgili FounderN Okuyucuları, bu haftanın blog yazısında, “Yapay Zeka ile Etkileşimli Oyunlar Tasarlama Rehberi: Kendi Oyununuzu Tasarlamak” başlığı altında, oyun tasarımının temellerini ve yapay zekanın oyun dünyasında nasıl etkili bir şekilde kullanılabileceğinizi ele alacağız. İşinize yarayacak bazı referanslar da sunarak oyun tasarımı yolculuğunuzda size yardımcı olmayı umuyoruz. Keyifli okumalar!
Oyun Yapay Zekâsı Nedir?
Oyun AI’sı, genellikle bir varlığın mevcut koşullara göre hangi eylemleri gerçekleştirmesi gerektiğine odaklanır. Geleneksel AI literatüründe bu, “akıllı ajanları kontrol etmek” olarak adlandırılır. Ajan genellikle bir oyun karakteri olsa da, bu bir robot, bir araç veya hatta bir medeniyet bile olabilir. Ajan, çevresini algılar, karar alır ve bu kararlara göre hareket eder. Bu sücreç genellikle Hisset/Düşün/Hareket Et döngüsü olarak düşünülür:
- Duygu: Temsilci, çevresindeki öğeleri algılar (tehditler, toplanacak nesneler, vb.).
- Düşün: Ajan, ne yapacağına karar verir (savaşmak, saklanmak veya kaçmak gibi).
- Eylem: Ajan, kararını uygulamak için harekete geçer.
Bu döngü, karakterlerin eylemleri nedeniyle oyun durumu değiştiğinden sürekli tekrar eder.
Gerçek Dünyada ve Oyunlarda Yapay Zekâ Farklılıkları:
Gerçek dünyada, yapay zekânın en karmaşık kısmı genellikle “duyu” aşamasıdır. Otonom arabalar gibi sistemler, kameralar, radarlar ve LIDAR verilerini analiz ederek anlamlı bilgiler çıkarmaya çalışır. Oyunlarda ise bu daha basittir; çünküsü oyun zaten simüle edilen dünyanın iç yapısını bilir. Mesela, bir düşmanın varlığını algılamak için karmaşık görüntü tanıma algoritmalarına gerek yoktur; oyun motoru düşmanın pozisyonunu zaten bilir.
Oyun AI Geliştirmenin Kısıtlamaları
Oyun için yapay zekâ geliştirirken tasarımcıların karşılaştığı belli başlı zorluklar vardır:
- Eğitim süreci sınırlıdır: Oyunun yayınlanmadan önce oyuncu verisi olmadığından, AI’yı büyük veri setleriyle eğitmek zor olabilir.
- Eğlence dengesi: Yapay zekânın kusursuz olması değil, oyuncuya tatmin edici bir meydan okuma sunması beklenir.
- Gerçekçilik: AI, insan benzeri hatalar yaparak daha doğal gözükmelidir. Aksi halde oyuncular, AI’nın “uzaylı” gibi davrandığını hissedebilir.
- Gerçek zaman kısıtları: AI kararlarını milisaniyeler içinde vermelidir. Çoğu oyunun 16-33 ms içinde kare yenilemesi gerekir.
Bu kısıtlamalara rağmen, basit ve etkili yaklaşımlarla tatmin edici AI sistemleri tasarlanabilir.
Temel Karar Verme: Pong Örneği
Pong gibi basit bir oyunda yapay zekânın amacı, topa vurabilmek için küreği (raket) doğru konuma getirmektir. En basit yöntem, küreği her zaman topun altına yerleştirmeye çalışmaktır:
her kare/güncelleme sürerken:
eğer top küreğin solundaysa:
küreği sola hareket ettir
yoksa eğer top küreğin sağındaysa:
küreği sağa hareket ettir
Bu algoritma, topu takip etmek için yeterince hızlıysa, temel seviyede işlevsel olur. Bu durumda Hisset/Düşün/Eylem döngüsü şu şekilde işler:
- Duyu: Topun konumunu algıla.
- Düşün: Topun sağında mı solunda mı olduğuna karar ver.
- Eylem: Küreği uygun yöne hareket ettir.
Bu yaklaşım, basit kurallara dayalı olduğundan reaktif AI olarak adlandırılır.
Karar Ağaçları
Pong örneği aslında temel bir karar ağacı yapısıdır. AI, karar vermek için ağacın dallarını takip eder ve bir yaprakta sonlandırır. Bu sistem, karmaşık oyunlarda bile çok etkili olabilir.
Oyun yapay zekâsı, basit kurallardan karmaşık algoritmalara kadar geniş bir yelpazede tasarlanabilir. Tasarım hedeflerine göre bu yaklaşımlar şekillenir ve oyunculara unutulmaz deneyimler sunar.
Bu konuyu daha da derinleştirmek ister misiniz? Belki karar ağaçlarının daha karmaşık oyunlarda nasıl kullanıldığını inceleyebiliriz:

Karar ağacının her bir parçasına genellikle ‘düğüm’ denir çünkü AI bu tür yapıları tanımlamak için grafik teorisini kullanır. Her düğüm iki türden biridir:
- Karar Düğümleri: Bazı koşulların kontrol edilmesine dayalı olarak 2 alternatif arasında yapılan bir seçim, her alternatif kendi düğümü olarak temsil edilir;
- Son Düğümler: Ağaç tarafından verilen son kararı temsil eden gerçekleştirilecek bir eylem.
Algoritma, ağacın ‘kökü’ olarak adlandırılan ilk düğümden başlar ve koşula göre hangi alt düğüme geçileceğine karar verir veya düğümde depolanan eylemi yürütür ve durur.
İlk bakışta, burada faydanın ne olduğu açık olmayabilir, çünkü karar ağacı açıkça önceki bölümdeki if-ifadeleriyle aynı işi yapıyor. Ancak burada her kararın tam olarak 1 koşulu ve 2 olası sonucu olduğu çok genel bir sistem var, bu da bir geliştiricinin yapay zekayı ağaçtaki kararları temsil eden verilerden oluşturmasına ve onu sabit kodlamaktan kaçınmasına olanak tanır.
Ağacı şu şekilde tanımlamak için basit bir veri biçimi hayal etmek kolaydır:
Düğüm No | Karar / Aksiyon | Evet | Hayır |
---|---|---|---|
1 | Kürek Topu Kürek Solundaki Top mudur? | Node 2’yi kontrol edin | Node 3’ü kontrol edin |
2 | Son | Kürekleri Sola Hareket Ettir | — |
3 | Top, Küreğin Sağında mı? | Node 4’e git | Node 5’e git |
4 | Son | Kürekleri Sağa Hareket Ettir | — |
5 | Son | Hiçbir şey yapma | — |
Bu satırların her birini okuyacak, her biri için bir düğüm oluşturacak, karar mantığını 2. sütuna göre bağlayacak ve alt düğümleri 3. ve 4. sütunlara göre bağlayacak bir sisteminiz olurdu. Koşulları ve eylemleri yine de sabit kodlamanız gerekir, ancak şimdi ekstra kararlar ve eylemler eklediğiniz ve ağaç tanımıyla metin dosyasını düzenleyerek tüm yapay zekayı ayarlayabileceğiniz daha karmaşık bir oyun hayal edebilirsiniz. Dosyayı, oyunu yeniden derlemeye ve kodu değiştirmeye gerek kalmadan davranışı ayarlayabilen bir oyun tasarımcısına teslim edebilirsiniz — kodda zaten yararlı koşullar ve eylemler sağladıysanız.
Karar ağaçlarının gerçekten güçlü olabileceği yer, büyük bir örnek kümesine dayalı olarak otomatik olarak oluşturulabildikleri zamandır (örneğin ID3 algoritması kullanılarak). Bu, onları giriş verilerine dayalı durumları sınıflandırmak için etkili ve yüksek performanslı bir araç yapar, ancak bu, ajanların eylemleri seçmesini sağlayan basit bir tasarımcı tarafından yazılmış sistemin kapsamının ötesindedir.
Komut dosyası
Daha önce, önceden yazılmış koşulları ve eylemleri kullanan bir karar ağacı sistemimiz vardı. Yapay zekayı tasarlayan kişi ağacı istediği gibi düzenleyebilirdi, ancak programcının ihtiyaç duyduğu tüm gerekli koşulları ve eylemleri zaten sağlamış olmasına güvenmek zorundaydı. Tasarımcıya kendi koşullarından bazılarını ve hatta belki de kendi eylemlerinden bazılarını oluşturmalarına izin veren daha iyi araçlar verebilirsek ne olur?
Örneğin, kodlayıcının “Top Kürek Solunda mı” ve “Top Kürek Sağında mı” koşulları için kod yazması yerine, tasarımcının bu değerleri kendisi kontrol etmek için koşulları yazdığı bir sistem sağlayabiliriz. Karar ağacı verileri daha çok buna benzeyebilir:
Düğüm Numarası | Karar (veya ‘Son’) | Aksiyon |
---|---|---|
1 | top.pozisyonu.x < kürek.pozisyonu.x | Evet → Node 2’yi kontrol et |
– | Hayır → Node 3’ü kontrol et | |
2 | Son | Kürekleri Sola Hareket Ettir |
3 | top.pozisyonu.x > kürek.pozisyonu.x | Evet → Node 4’ü kontrol et |
– | Hayır → Node 5’i kontrol et | |
4 | Son | Kürekleri Sağa Hareket Ettir |
5 | Son | Hiçbir şey yapma |
Bu yukarıdakiyle aynıdır, ancak kararların kendi kodları vardır ve bir if ifadesinin koşullu kısmına biraz benzer. Kod tarafında, bu Karar düğümleri için 2. sütunda okunur ve çalıştırılacak belirli koşulu aramak yerine (“Top Kürek Solundaki mi”), koşullu ifadeyi değerlendirir ve buna göre doğru veya yanlış döndürür.
Bu, geliştiricinin oyunundaki nesneleri (örneğin top ve kürek) almasına ve betikte erişilebilen değişkenler oluşturmasına (örneğin “top.position”) olanak tanıyan Lua veya Angelscript gibi bir betik dili yerleştirerek yapılabilir. Betik dili genellikle C++’dan yazılması daha kolaydır ve tam bir derleme aşaması gerektirmez, bu nedenle oyun mantığında hızlı ayarlamalar yapmak ve ekibin daha az teknik üyelerinin bir kodlayıcının müdahalesine gerek kalmadan özellikleri şekillendirebilmesini sağlamak için çok uygundur.
Yukarıdaki örnekte betik dili yalnızca koşullu ifadeyi değerlendirmek için kullanılıyor, ancak çıktı eylemlerinin de betiklenemeyeceğine dair hiçbir neden yok. Örneğin, “Kürek Sağa Taşı” gibi eylem verileri “ball.position.x += 10” gibi bir betik ifadesi haline gelebilir, böylece eylem de programcının bir MovePaddleRight işlevini zorla kodlamasına gerek kalmadan betikte tanımlanır.
Bir adım daha ileri giderek, tüm karar ağacını veri satırları listesi yerine betik dilinde yazmanın mantıksal sonucuna varmak mümkün. Bu, yukarıda tanıttığımız orijinal sabit kodlu koşullu ifadelere çok benzeyen bir kod olurdu ancak artık ‘sabit kodlu’ olmazlardı harici betik dosyalarında bulunurlardı, yani tüm programı yeniden derlemeden değiştirilebilirlerdi. Oyun çalışırken betik dosyasını değiştirmek bile sıklıkla mümkündür bu da geliştiricilerin farklı AI yaklaşımlarını hızla test etmelerine olanak tanır.
Olaylara yanıt verme
Yukarıdaki örnekler, Pong gibi basit bir oyunda her kareyi çalıştırmak için tasarlanmıştır. Fikir, Sense/Think/Act döngüsünü sürekli olarak çalıştırabilmeleri ve son dünya durumuna göre hareket etmeye devam edebilmeleridir. Ancak daha karmaşık oyunlarda, her şeyi değerlendirmek yerine, oyun ortamındaki önemli değişiklikler olan ‘olaylara’ yanıt vermek genellikle daha mantıklıdır.
Bu Pong için pek geçerli değil, bu yüzden farklı bir örnek seçelim. Düşmanların oyuncuyu tespit edene kadar hareketsiz kaldığı ve daha sonra kim olduklarına göre farklı eylemler gerçekleştirdiği bir nişancı oyunu hayal edin – kavgacılar oyuncuya doğru hücum edebilirken, keskin nişancılar geride kalıp ateş edebilir. Bu hala temelde temel bir tepkisel sistemdir – “eğer oyuncu görülürse, o zaman bir şeyler yap” fakat mantıksal olarak olay (“Oyuncu Görüldü”) ve tepki (bir tepki seçme ve gerçekleştirme) olarak ayrılabilir.
Bu bizi doğrudan Sense/Think/Act döngümüze geri getiriyor. Her karede düşmanın oyuncuyu görüp görmediğini kontrol eden ‘Sense’ kodu olan bir kod parçamız olabilir. Eğer göremiyorsa hiçbir şey olmaz ancak görüyorsa ‘Player Seen’ olayını yaratır. Kodda ‘Player Seen’ olayı gerçekleştiğinde, yap” diyen ayrı bir bölüm olurdu ve , Düşünme ve Harekete Geçme ile başa çıkmak için ihtiyaç duyduğunuz yanıt olurdu. Brawler karakterinizde, “ChargeAndAttack” yanıt işlevini Player Seen olayına bağlayabilirsiniz – ve Sniper karakterinizde, “HideAndSnipe” yanıt işlevini bu olaya bağlayabilirsiniz. Önceki örneklerde olduğu gibi, bu ilişkileri bir veri dosyasında yapabilirsiniz, böylece motoru yeniden oluşturmadan hızlıca değiştirilebilirler. Bu yanıt işlevlerini bir betik dilinde yazmak da mümkündür böylece tasarımcılar bu olaylar gerçekleştiğinde karmaşık kararlar alabilirler.
Gelişmiş Karar Verme
Basit reaktif sistemler çok güçlü olsa da, gerçekten yeterli olmadıkları birçok durum vardır. Bazen, etkenin şu anda yaptığı şeye dayanarak farklı kararlar almak isteriz ve bunu bir koşul olarak temsil etmek kullanışsızdır. Bazen, bir karar ağacında veya bir betikte etkili bir şekilde temsil etmek için çok fazla koşul vardır. Bazen, bir sonraki hamlemize karar vermeden önce ileriyi düşünmemiz ve durumun nasıl değişeceğini tahmin etmemiz gerekir. Bu sorunlar için daha karmaşık çözümlere ihtiyacımız var.
Sonlu durum makineleri
Sonlu durum makinesi (veya kısaca FSM), bir nesnenin (örneğin, yapay zeka ajanlarımızdan biri) şu anda birkaç olası durumdan birinde olduğunu ve bir durumdan diğerine geçebileceğini söylemenin süslü bir yoludur. Bu durumlardan sonlu sayıda vardır, bu nedenle adı budur. Gerçek hayattan bir örnek, kırmızıdan sarıya, sarıdan yeşile ve tekrar geriye giden bir dizi trafik ışığıdır. Farklı yerlerin farklı ışık dizileri vardır ancak ilke aynıdır – her durum bir şeyi temsil eder (“Dur”, “Geç”, “Mümkünse dur” vb.), herhangi bir anda yalnızca bir durumdadır ve basit kurallara göre birinden diğerine geçiş yapar.
Bu, oyunlardaki NPC’ler için oldukça geçerlidir. Bir muhafızın aşağıdaki belirgin durumları olabilir:
Devriye gezme
Saldırmak
Kaçmak
Ve durumlarını değiştirdikleri zaman aşağıdaki kuralları uygulayabilirsiniz:
Bir gardiyan bir rakip görürse saldırır
Bir gardiyan saldırıyorsa ancak rakibi artık göremiyorsa devriye gezmeye geri dönün
Bir gardiyan saldırıyorsa ancak ağır yaralıysa kaçmaya başlayın
Bu, onu sabit kodlu if-ifadeleri olarak yazabileceğiniz kadar basittir; değişken, muhafızın hangi durumda olduğunu ve yakınlarda bir düşman olup olmadığını, muhafızın sağlık seviyesinin nasıl olduğunu vb. kontrol eden çeşitli kontrolleri depolar. Ancak birkaç durum daha eklemek istediğimizi düşünün:
Boşta bekleme (devriyeler arasında)
Arama (Daha önce fark edilen bir düşmanın saklanması)
Yardım için koşmak (bir düşman görüldüğünde ancak tek başına savaşamayacak kadar güçlü olduğunda)
Mevcut seçenekler genellikle sınırlıdır; örneğin, muhafız muhtemelen sağlığı çok düşükse kayıp bir düşmanı aramak istemeyecektir
Sonunda “eğer ise” şeklindeki uzun bir liste için biraz fazla kullanışsız hale gelir ve durumlar ve durumlar arasındaki geçişler hakkında düşünmenin resmi bir yoluna sahip olmak yardımcı olur. Bunu yapmak için tüm durumları ele alırız ve her bir durumun altında, diğer durumlara geçişleri ve bunlar için gerekli koşulları listeleriz. Ayrıca, başka koşullar geçerli olmadan önce neyle başlayacağımızı bilmemiz için bir başlangıç durumu belirlememiz gerekir
Durum | Geçiş Koşulu | Yeni Devlet |
---|---|---|
Boşta çalışma | 10 saniye boyunca boşta kaldım | Devriye gezme |
Devriye gezme | Düşman görünür ve düşman çok güçlü | Yardım Bulma |
Yardım Bulma | Düşman görünür ve sağlık yüksek | Saldırmak |
Saldırmak | Düşman görünür ve sağlık düşük | Kaçmak |
Kaçmak | Devriye gezme | Tamamlanmış devriye rotası |
Boşta çalışma | Düşman görünür ve düşman çok güçlü | Yardım Bulma |
Yardım Bulma | Düşman görünür ve sağlık yüksek | Saldırmak |
Saldırmak | Düşman görünür ve sağlık düşük | Kaçmak |
Kaçmak | Saldırmak | Görünürde düşman yok |
Boşta çalışma | Sağlık düşük | Kaçmak |
Kaçmak | Kaçmak | Görünürde düşman yok |
Boşta çalışma | Arama 10 saniyedir arıyorum | Boşta çalışma |
Boşta çalışma | Düşman görünür ve düşman çok güçlü | Yardım Bulma |
Yardım Bulma | Düşman görünür ve sağlık yüksek | Saldırmak |
Saldırmak | Düşman görünür ve sağlık düşük | Kaçmak |
Kaçmak | Yardım Bulma | Arkadaş görünür |
Saldırmak | Başlangıç durumu: Boşta çalışma |
Bu, bir durum geçiş tablosu olarak bilinir ve FSM’yi temsil etmenin kapsamlı bir yoludur.
Bu verilerden, bir diyagram çizmek ve NPC’nin davranışının zaman içinde nasıl gerçekleşebileceğine dair kapsamlı bir görsel denetim elde etmek de mümkündür.

Bu, o etkenin içinde bulunduğu duruma göre karar alma sürecinin özünü yakalar; her ok, okun yanındaki koşul doğruysa durumlar arasında bir geçişi gösterir.
Her güncelleme veya ‘tik’te, ajanın mevcut durumunu kontrol eder, geçiş listesine bakarız ve bir geçiş için koşullar karşılanırsa yeni duruma geçeriz. Boşta kalma durumu, her kare veya tikte, 10 saniyelik zamanlayıcının süresinin dolup dolmadığını kontrol eder ve eğer dolduysa, Devriye durumuna geçişi tetikler. Benzer şekilde, Saldırma durumu, ajanın sağlığının düşük olup olmadığını kontrol eder ve eğer düşükse, Kaçma durumuna geçiş yapar.
Bu, durumlar arasındaki geçişleri yönetir – peki ya durumların kendileriyle ilişkili davranışlar ne olacak? Belirli bir durum için gerçek davranışları gerçekleştirme açısından, genellikle eylemleri sonlu durum makinesine bağladığımız 2 tür ‘kanca’ vardır:
- Mevcut durum için örneğin her kare veya her ‘tik’ için periyodik olarak gerçekleştirdiğimiz eylemler.
- Bir durumdan diğerine geçtiğimizde yaptığımız eylemler.
İlk türün bir örneği için, Devriye durumu, her kare veya tik, aracı devriye rotası boyunca hareket ettirmeye devam edecektir. Saldıran durumu, her kare veya tik, bir saldırı başlatmayı veya bunun mümkün olduğu bir konuma geçmeyi deneyecektir.
İkinci tür için, ‘Düşman görünürse ve düşman çok güçlüyse → Yardım Bulma’ geçişini düşünün. Ajan, yardım bulmak için nereye gideceğini seçmeli ve bu bilgiyi, Yardım Bulma durumunun nereye gideceğini bilmesi için depolamalıdır. Benzer şekilde, Yardım Bulma durumu içinde, yardım bulunduğunda ajan Saldıran durumuna geri döner, ancak o noktada arkadaşa tehdit hakkında bilgi vermek isteyecektir, bu nedenle bu geçişte bir “ArkadaşaTehditBildir” eylemi gerçekleşebilir.
Tekrar, bu sistemi Sense/Think/Act merceğinden görebiliriz. Duyular, geçiş mantığı tarafından kullanılan verilerde somutlaştırılmıştır. Düşünme, her bir durumda mevcut olan geçişler tarafından somutlaştırılmıştır. Ve eylem, bir durum içinde veya durumlar arasındaki geçişlerde periyodik olarak gerçekleştirilen eylemler tarafından gerçekleştirilir.
Bu temel sistem iyi çalışır, ancak bazen geçiş koşulları için sürekli yoklama yapmak pahalı olabilir. Örneğin, her ajanın Devriyeden Saldırıya geçip geçmemeye karar vermek için herhangi bir düşmanı görüp görmediğini belirlemek üzere her karede karmaşık hesaplamalar yapması gerekiyorsa, bu çok fazla CPU zamanı kaybına neden olabilir. Daha önce gördüğümüz gibi, dünya durumundaki önemli değişiklikleri, meydana geldikleri anda işlenebilen ‘olaylar’ olarak düşünebiliriz. Dolayısıyla, durum makinesinin her karede açıkça “Ajanım oyuncuyu görebilir mi?” geçiş koşulunu kontrol etmesi yerine, ayrı bir görünürlük sisteminin bu kontrolleri biraz daha az sıklıkta (örneğin saniyede 5 kez) gerçekleştirmesini ve kontrol geçtiğinde bir “Oyuncu Görüldü” olayı yayımlamasını sağlayabilirsiniz. Bu, artık bir “Oyuncu Görüldü olayı alındı” geçiş koşuluna sahip olacak ve olaya göre yanıt verecek olan durum makinesine verilir. Son davranış, yanıt vermede neredeyse fark edilmeyen (ve yine de daha gerçekçi) gecikme dışında aynıdır, ancak sistemin Sense bölümünü programın ayrı bir bölümüne taşımanın bir sonucu olarak performans daha iyidir.
Hiyerarşik Durum Makineleri
Bunların hepsi güzel ancak büyük durum makineleriyle çalışmak zor olabilir. Saldıran durumunu ayrı Yakın Saldırı ve Menzilli Saldırı durumlarıyla değiştirerek genişletmek isteseydik şimdi ve gelecekte Saldıran durumuna geçiş yapması gereken her durumdaki gelen geçişleri değiştirmemiz gerekirdi.
Örneğimizde çok sayıda yinelenen geçiş olduğunu da fark etmiş olabilirsiniz. Bekleme durumundaki geçişlerin çoğu Devriye durumundakilerle aynıdır ve özellikle buna benzer daha fazla durum eklersek bu işi yinelemek zorunda olmamak iyi olur. Bekleme ve Devriyeyi, sadece bir tane paylaşılan savaş durumu geçişi kümesinin olduğu bir tür ‘Savaş Dışı’ ortak etiketi altında gruplamak mantıklı olabilir. Bunu kendi başına bir durum olarak temsil edersek, Bekleme ve devriyeyi bunun ‘alt durumları’ olarak düşünebiliriz bu da tüm sistemi daha etkili bir şekilde temsil etmemizi sağlar. Örneğin, yeni Savaş Dışı alt durumu için ayrı bir geçiş tablosu kullanmak:
Durum Geçiş Tablosu
Mevcut Durum | Geçiş Koşulu | Yeni Durum |
---|---|---|
Savaş Dışı | Düşman görünür ve düşman çok güçlü | Yardım Bulma |
Savaş Dışı | Düşman görünür ve sağlık yüksek | Yardım Bulma |
Savaş Dışı | Düşman görünür ve sağlık düşük | Saldırmak |
Savaş Dışı | Görünürde düşman yok | Kaçmak |
Savaş Dışı | Sağlık düşük | Savaş Dışı |
Savaş Dışı | Görünürde düşman yok | Kaçmak |
Savaş Dışı | 10 saniyedir arıyorum | Savaş Dışı |
Savaş Dışı | Düşman görünür ve düşman çok güçlü | Yardım Bulma |
Savaş Dışı | Düşman görünür ve sağlık yüksek | Yardım Bulma |
Savaş Dışı | Düşman görünür ve sağlık düşük | Saldırmak |
Savaş Dışı | Arkadaş görünür | Yardım Bulma |
Başlangıç Durumu | – | Savaş Dışı |
Boşta çalışma | 10 saniye boyunca boşta kaldım | Boşta çalışma |
Devriye gezme | Tamamlanmış devriye rotası | Boşta çalışma |
Ve diyagram biçiminde:

Bu esasen aynı sistemdir ancak şimdi Devriye ve Beklemenin yerini alan bir Savaş Dışı durum vardır ve Devriye ve Bekleme’nin 2 alt durumu olan kendi başına bir durum makinesidir. Her durum potansiyel olarak alt durumlardan oluşan bir durum makinesi içerir (ve bu alt durumlar belki de kendi durum makinelerini içerir, ihtiyacınız olduğu kadar aşağıya inebilirsiniz), bir Hiyerarşik Sonlu Durum Makinesi’ne (kısaca HFSM) sahibiz. Savaş dışı davranışları gruplayarak bir sürü gereksiz geçişi ortadan kaldırdık ve geçişleri paylaşabilecek eklemeyi seçtiğimiz herhangi bir yeni durum için de aynısını yapabiliriz. Örneğin, Saldıran durumunu gelecekte Yakın Saldırı ve Füze Saldırı durumlarına genişletirsek, bunlar alt durumlar olabilir, düşmana olan mesafeye ve mühimmat mevcudiyetine göre birbirleri arasında geçiş yapabilir ancak çıkış geçişlerini sağlık seviyelerine vb. göre paylaşabilirler. Karmaşık davranışlar ve alt davranışlar, minimum sayıda yinelenen geçişle bu şekilde kolayca temsil edilebilir.
Davranış Ağaçları
HFSM’lerle nispeten karmaşık davranış kümeleri oluşturma becerisine nispeten sezgisel bir şekilde sahip oluyoruz. Ancak, tasarımdaki ufak bir kırışıklık, geçiş kuralları biçimindeki karar almanın mevcut duruma sıkı sıkıya bağlı olmasıdır. Birçok oyunda, tam olarak istediğiniz budur. Ve durumların hiyerarşisinin dikkatli kullanımı, burada geçiş tekrarının miktarını azaltabilir. Ancak bazen hangi durumda olursanız olun geçerli olan veya hemen hemen tüm durumlarda geçerli olan kurallar istersiniz. Örneğin, bir ajanın sağlığı %25’e düştüyse, şu anda savaşta, hareketsiz duruyor, konuşuyor veya başka bir durumda olsun kaçmasını isteyebilirsiniz ve gelecekte bir karaktere ekleyebileceğiniz her duruma bu koşulu eklemeyi hatırlamak istemezsiniz. Ve tasarımcınız daha sonra eşiği %25’ten %10’a değiştirmek istediğini söylerse, o zaman her bir durumun ilgili geçişini gözden geçirmeniz ve değiştirmeniz gerekir.
İdeal olarak bu durum için hangi eyalette olunacağına dair kararların eyaletlerin dışında gerçekleştiği bir sistem istersiniz, böylece değişikliği tek bir yerde yapabilir ve yine de doğru bir şekilde geçiş yapabilirsiniz. İşte davranış ağacının devreye girdiği yer burasıdır.
Davranış ağaçlarını uygulamanın birkaç farklı yolu vardır, ancak öz çoğu için aynıdır ve daha önce bahsedilen karar ağacına oldukça benzerdir: algoritma bir ‘kök düğüm’de başlar ve ağaçta kararları veya bir eylemi temsil eden düğümler vardır. Ancak birkaç önemli fark vardır:
- Düğümler artık 3 değerden birini döndürüyor: Başarılı (işi bittiyse), Başarısız (çalışamıyorsa) veya Çalışıyor (hala çalışıyorsa ve tam olarak başarılı olmadıysa veya henüz başarısız olduysa).
- Artık 2 alternatif arasında seçim yapmak için karar düğümlerimiz yok, bunun yerine tek bir alt düğümü olan ‘Dekoratör’ düğümlerimiz var. ‘Başarılı’ olurlarsa, tek alt düğümlerini yürütürler. Dekoratör düğümleri genellikle başarılı olup olmadıklarına (ve alt ağaçlarını yürüttüklerine) veya başarısız olup olmadıklarına (ve hiçbir şey yapmadıklarına) karar veren koşullara sahiptir. Ayrıca uygunsa Çalışıyor döndürebilirler.
- Eylem gerçekleştiren düğümler, devam eden etkinlikleri temsil etmek için Çalışan değerini döndürecektir
Bu küçük düğüm kümesi, çok sayıda karmaşık davranış üretmek için birleştirilebilir ve genellikle çok özlü bir gösterimdir. Örneğin, önceki örnekteki muhafızın hiyerarşik durum makinesini bir davranış ağacı olarak yeniden yazabiliriz:

Bu yapı ile, Boşta veya Devriye durumlarından Saldıran durumlara veya diğerlerine açık bir geçiş olması gerekmez ağaç yukarıdan aşağıya, soldan sağa geçilirse, doğru karar mevcut duruma göre verilir. Bir düşman görünürse ve karakterin sağlığı düşükse, ağaç daha önce hangi düğümde yürütülüyor olursa olsun – Devriye, Boşta, Saldıran, vb. – yürütmeyi ‘Kaçma’ düğümünde durduracaktır.
Şu anda Devriye Durumundan Boşta Durumuna dönmek için bir geçiş olmadığını fark edebilirsiniz – koşulsuz dekoratörlerin devreye girdiği yer burasıdır. Yaygın bir dekoratör düğümü Tekrar’dır bunun bir koşulu yoktur, ancak basitçe ‘Başarılı’ döndüren bir alt düğümü keser ve o alt düğümü tekrar çalıştırır, bunun yerine ‘Çalışıyor’ döndürür. Yeni ağaç şu şekilde görünür:

Davranış ağaçları oldukça karmaşıktır çünkü ağacı çizmenin birçok farklı yolu vardır ve doğru dekoratör ve bileşik düğüm kombinasyonunu bulmak zor olabilir. Ayrıca ağacı ne sıklıkla kontrol edeceğimiz (her karede mi yoksa yalnızca koşullardan birinin değiştiği anlamına gelen bir şey olduğunda mı geçmek istiyoruz?) ve düğümlerle ilgili durumu nasıl depolayacağımız (10 saniye boşta kaldığımızı nasıl anlarız? Son seferde hangi düğümlerin yürütüldüğünü nasıl biliriz, böylece bir diziyi doğru şekilde işleyebiliriz?) gibi sorunlar da vardır. Bu nedenle birçok farklı uygulama vardır. Örneğin, Unreal Engine 4 davranış ağacı sistemi gibi bazı sistemler dekoratör düğümlerini satır içi dekoratörlerle değiştirmiştir, yalnızca dekoratör koşulları değiştiğinde ağacı yeniden değerlendirir ve ağaç yeniden değerlendirilmediğinde bile düğümlere bağlanmak ve periyodik güncellemeler sağlamak için ‘hizmetler’ sağlar. Davranış ağaçları güçlü araçlardır ancak bunları etkili bir şekilde kullanmayı öğrenmek, özellikle de birden fazla farklı uygulama karşısında, göz korkutucu olabilir.
Fayda tabanlı sistemler
Bazı oyunlar çok sayıda farklı eylemin mevcut olmasını ister ve bu nedenle daha basit, merkezi geçiş kurallarının faydalarını ister, ancak belki de tam bir davranış ağacı uygulamasının ifade gücüne ihtiyaç duymazlar. Sırayla yapılacak açık bir seçim kümesi veya ağaç yapısı tarafından belirlenen örtük geri çekilme konumlarına sahip olası eylemler ağacı yerine, belki de tüm eylemleri incelemek ve şu anda en uygun görüneni seçmek mümkün olabilir mi?
Fayda tabanlı bir sistem tam olarak budur bir etkenin emrinde çeşitli eylemler olduğu ve her eylemin göreceli faydasına göre birini yürütmeyi seçtiği bir sistem , burada fayda, o eylemi gerçekleştirmenin etken için ne kadar önemli veya arzu edilir olduğunun keyfi bir ölçüsüdür. Etkenin ve çevresinin mevcut durumuna göre bir eylemin faydasını hesaplamak için fayda fonksiyonları yazarak, etken bu fayda değerlerini kontrol edebilir ve böylece herhangi bir zamanda en alakalı durumu seçebilir. Tekrar bu geçişlerin mevcut durum da dahil olmak üzere her olası durum için puanla belirlendiği bir sonlu durum makinesine oldukça benzer. Genellikle geçiş yapmak için en yüksek puanlı eylemi seçtiğimizi (veya zaten bu eylemi gerçekleştiriyorsak içinde kaldığımızı) unutmayın, ancak daha fazla çeşitlilik için ağırlıklı rastgele seçim (en yüksek puanlı eylemi tercih ederek ancak diğerlerinin seçilmesine izin vererek), ilk 5’ten (veya başka herhangi bir nicelikten) rastgele bir eylem seçmek vb. olabilir.
Tipik bir fayda sistemi, bazı keyfi fayda değerleri aralığı atayacaktı örneğin, 0 (tamamen istenmeyen) ila 100 (tamamen istenen) ve her eylem, bu değerin nasıl hesaplandığını etkileyen bir dizi düşünceye sahip olabilir. Muhafız örneğimize dönersek, buna benzer bir şey hayal edebiliriz:
Eylem | Şartlar | Dönen Değer |
---|---|---|
Aksiyon | Fayda Hesaplaması | – |
Yardım Bulma | Eğer düşman görünürse ve düşman güçlü ve canı düşükse | 100 |
Aksi takdirde | 0 | |
Kaçmak | Eğer düşman görünür ve canı düşükse | 90 |
Aksi takdirde | 0 | |
Saldırmak | Eğer düşman görünürse | 80 |
Boşta Çalışma | Şu anda boştaysa ve 10 saniye geçmediyse | 50 |
Aksi takdirde | 0 | |
Devriye Gezme | Devriye rotasının sonunda | 0 |
Aksi takdirde | 50 |
Bu kurulum hakkında fark edilecek en önemli şeylerden biri, eylemler arasındaki geçişlerin tamamen örtük olmasıdır herhangi bir durum yasal olarak diğer herhangi bir durumu takip edebilir. Ayrıca, eylem öncelikleri döndürülen fayda değerlerinde örtüktür. Düşman görünür durumdaysa ve bu düşman güçlüyse ve karakterin sağlığı düşükse, hem Kaçma hem de Bulma Yardımı sıfır olmayan yüksek değerler döndürecektir, ancak Bulma Yardımı her zaman daha yüksek puan alır. Benzer şekilde, savaş dışı eylemler asla 50’den fazla döndürmez, bu nedenle her zaman bir savaş eylemi tarafından alt edilirler. Eylemler ve fayda hesaplamaları bunu akılda tutarak tasarlanmalıdır.
Örneğimizde eylemler sabit bir sabit fayda değeri veya iki sabit fayda değerinden birini döndürür. Daha gerçekçi bir sistem genellikle sürekli bir değer aralığından bir puan döndürmeyi içerir. Örneğin, Kaçma eylemi, ajanın sağlığı düşükse daha yüksek fayda değerleri döndürebilir ve Saldırma eylemi, düşman yenilmesi çok zorsa daha düşük fayda değerleri döndürebilir. Bu, ajanın rakibini yenecek kadar sağlığı olmadığını hissettiği herhangi bir durumda Kaçma eyleminin Saldırmaya göre öncelik kazanmasına izin verir . Bu, göreceli eylem önceliklerinin herhangi bir sayıda kritere göre değişmesine izin verir ve bu tür bir yaklaşımı bir davranış ağacından veya sonlu durum makinesinden daha esnek hale getirebilir.
Oyun tasarlamak başlı başına çok detaylı bir süreçtir ancak ana hatlarıyla temel fonksiyonlar bahsedildiği gibidir. Bu konuda çok daha fazla bilgi için Dave Mark‘ın çalışmalarına bakabilirsiniz.
Diğer blog içeriklerimize buradan ulaşabilirsiniz!
FounderN, girişimcilik dünyasının en güncel haberleri, inovasyon odaklı içerikleri ve ekosistemin her bir parçasına değer katan çalışmalarıyla, faaliyet gösteren dinamik bir dijital medya platformudur. 2020 yılında “Girişim Haberleri” adıyla başlayan serüvenimiz, Eylül 2024 itibarıyla FounderN kimliği ile, girişimcilik ekosisteminin ilham veren dinamik sesi olma yolculuğuna devam ediyor. FounderN; teknoloji, girişim ve yatırım dünyasındaki gelişmeleri yaratıcı ve yenilikçi bir perspektifle sunarak iş dünyasının liderlerini, yatırımcılarını ve girişimcilerini sizlerle bir araya getirir.
FounderN olarak misyonumuz, yalnızca yaşanan son gelişmeleri paylaşmak değil, okurlarımızı bu gelişmelerin aktif bir parçası haline getirmek ve ekosistemin sürdürülebilir büyümesine katkı sağlamaktır. Ekosistemdeki en yeni gelişmelerden haberdar olmak, büyüyen bu topluluğun bir parçası olmak istiyorsanız, bültenimize abone olabilir, sosyal medya hesaplarımızdan bizi takip ederek ilham dolu bu yolculuğa katılabilirsiniz.
Bizimle Keşfetmeye Devam Edin: İlginizi çekebilecek diğer #Gündem Haberleri için tıklayın!
Foundern LinkedIn hesabına buradan ulaşabilirsiniz.
Foundern Instagram hesabına buradan ulaşabilirsiniz.