…devriye gezen, ses duyunca araştıran, sizi görünce kovalayan ve canı azalınca kaçan bir düşman tasarlayabilecek, onu üç farklı şekilde kodlayabilecek ve bir FSM kütüphanesini projenize ekleyebileceksiniz.
🤔 ISINMA: BİR GİZLİLİK OYUNUNDAKİ NÖBETÇİYİ ANLATIN
“Normalde devriye gezer. Bir ses duyarsa gidip bakar. Sizi görürse kovalar, yaklaşınca ateş eder. Canı azalırsa kaçar.”
Kalın kelimeler: nöbetçinin durumları — aynı anda sadece birindedir.
“-ırsa / -erse” ile başlayan kısımlar: geçişler ve koşulları.
Tebrikler: az önce bir sonlu durum makinesi tasarladınız. Kodun geri kalanı bu cümlenin tercümesi.
🎯 Bu konu için bilmeniz gerekenler
Yeşil = gerekli · kesikli = faydalı ama şart değil. Tıklayınca ilgili sunuma gider.
Neden?FSM’nin diyagramı bir yönlü graftır: düğümler durumlar, oklar geçişler. Yığınlı FSM ise bildiğimiz yığını kullanır. Ama ikisi de şart değil; burada sıfırdan anlatıyoruz.
🧰 Kodlamadan korkuyorsanızFSM’yi anlamak için kod gerekmez: kâğıda yuvarlaklar ve oklar çizmek yeter. Unity Animator, PlayMaker gibi görsel araçlarla kod yazmadan da FSM kurabilirsiniz (son bölüm).
Mini sözlük
finite state machine (FSM)
sonlu durum makinesi
Sonlu sayıda durum + aralarındaki geçişler
state
durum
Karakterin o anki “modu”: devriye, saldırı…
transition · condition
geçiş · koşul
Bir durumdan diğerine ok · okun ne zaman izleneceği
event
olay
Geçişi tetikleyen anlık bilgi: “ses duyuldu”
entry / exit action
giriş / çıkış eylemi
Duruma girerken / çıkarken bir kez yapılan iş
hierarchical FSM (HFSM)
hiyerarşik FSM
Durumların içinde alt durum makineleri
pushdown automaton
yığınlı otomat
Durumları yığında tutan, “önceki duruma dön” bilen FSM
hysteresis
histerezis (gecikme)
Girmek ve çıkmak için farklı eşikler: titremeyi önler
LEVEL 0
Durum ve geçiş
trafik ışığından Pac-Man’e
durum ve geçiş
bir nöbetçi tasarlayalım
kod: üç yol
sorunlar ve çözümler
hiyerarşik ve yığınlı FSM
gerçek oyunlarda FSM
kütüphaneler ve entegrasyon
Her yerde durum makineleri
Sonlu sayıda durum: 3
Aynı anda tek aktif durum
Oklar: geçişler; üstündeki yazı: koşul
Diğer örnekler: kapı (açık/kapalı/kilitli), içecek makinesi, asansör, oyun menüleri, karakter animasyonları (dur/yürü/koş/zıpla)
🎒 Bir FSM diyagramı = yönlü graf (Yönlü Graflar sunumu): düğüm = durum, kenar = geçiş
Önce bir kedi: “şu an ne yapıyor?” ve “ne olursa değişir?” 🐱
Bir durum makinesi iki sorudan ibarettir. Durum = şu an ne yapıyor (kutular). Geçiş = ne olursa başka bir şey yapmaya başlar (oklar; üstündeki yazı olay). Senaryoları oynatın, sonra olay düğmelerine kendiniz basın.
📸 Oyundan bir kare: Pac-Man (1980)
Dört hayalet (Blinky, Pinky, Inky, Clyde) aynı labirentte ama her biri başka bir “kovala” kuralıyla. Hepsi aynı üç durum arasında geçiş yapar: dağıl, kovala, kork (mavi). Sonraki slayt bu durumları diyagram olarak çiziyor. Görsel: Pac-Man gameplay, Bandai Namco Entertainment America, Wikimedia Commons, CC BY 3.0
Pac-Man hayaletleri bir FSM’dir
Y1’deki demo: zamanlayıcıyla DAĞIL ↔ KOVALA geçişi
Güç hapı → KORKU (rastgele yürü, mavi ol)
Her durumda farklı hedef kuralı çalışır
Aslında bir de “yenildi → evine dön” durumu var. FSM’ler büyüdükçe diyagram karışır — birazdan göreceğiz.
Quiz 1 · durum ve geçiş
Bir FSM’de aynı anda kaç durum aktif olabilir?
Düz bir FSM’de her an tek bir durum aktiftir: nöbetçi ya devriyededir ya kovalamaktadır. Aynı anda “yürü + nişan al” gibi şeyler gerekirse birden fazla FSM (katmanlar) ya da hiyerarşik FSM kullanılır.
LEVEL 1
Bir nöbetçi tasarlayalım
beş durum, sekiz geçiş
durum ve geçiş
bir nöbetçi tasarlayalım
kod: üç yol
sorunlar ve çözümler
hiyerarşik ve yığınlı FSM
gerçek oyunlarda FSM
kütüphaneler ve entegrasyon
Nöbetçinin beş durumu: her biri ne demek?
🚶 DEVRİYE
Ne yapar? Dört yol noktası arasında sakin sakin yürür.
Aklından geçen: “Her şey yolunda.”
Çıkış: oyuncuyu görürse ya da ses duyarsa.
❓ ŞÜPHE
Ne yapar? Sesin geldiği (ya da oyuncuyu son gördüğü) yere gider, durup etrafına bakınır.
Aklından geçen: “Orada bir şey mi vardı?”
Çıkış: görürse kovalar; 4 sn bir şey bulamazsa devriyeye döner.
Çıkış: oyuncu 90 birimden uzaklaşırsa yeniden kovalar; kaybederse şüphe.
💨 KAÇ
Ne yapar? Oyuncudan uzaklaşır, bu sırada canı yavaşça dolar.
Aklından geçen: “Ölmek üzereyim!”
Giriş:hangi durumda olursa olsun can 30’un altına düşünce. Çıkış: can 70’i geçince devriye.
Durum = “şu an ne yapıyorum”. Geçiş = “ne olursa başka bir şey yapmaya başlarım”. Renkler sonraki slaytlardaki tablo, diyagram ve canlı demoda hep aynı.
Nöbetçinin geçiş tablosu
şu anki durum
koşul
yeni durum
her durum
can < 30
KAÇ
DEVRİYE
oyuncuyu görüyor
KOVALA
DEVRİYE
ses duydu
ŞÜPHE
ŞÜPHE
oyuncuyu görüyor
KOVALA
ŞÜPHE
4 sn geçti
DEVRİYE
KOVALA
göremiyor
ŞÜPHE (son görülen yere git)
KOVALA
mesafe < 60
SALDIR
SALDIR
göremiyor / mesafe > 90
ŞÜPHE / KOVALA
KAÇ
can > 70
DEVRİYE
Her durumda ne yapar?
DEVRİYE: yol noktaları arasında yürü
ŞÜPHE: sesin geldiği yere git, etrafa bak
KOVALA: oyuncuya koş
SALDIR: dur, nişan al, ateş et
KAÇ: oyuncudan uzaklaş, iyileş
Tablonun sırası önemli: “can < 30” kuralı önce kontrol edilir. Saldırıya 60’ta girip ancak 90’da çıkmasının sebebi birazdan (“titreme”).
Tablodan diyagrama: olayları siz verin 🎛️
Az önceki tablonun her satırı burada bir ok. Canlı oyundan önce nöbetçiyi elle yönetin: bir senaryo seçin ya da alttaki olay düğmelerine basın ve her seferinde önce tahmin edin: hangi kutuya geçecek, yoksa hiç kıpırdamayacak mı?
Demoyu okuma kılavuzu: ekranda ne var?
Sol: oyun alanı
Ok biçimli üçgen = nöbetçi. Rengi ve üstündeki yazı şu anki durumu. Altındaki çubuk canı.
Yeşil daire = oyuncu. Fareyi alana sokunca siz olursunuz; fare alandan çıkınca oyuncu olduğu yerde kalır.
Koyu dikdörtgenler = duvar: arkasındaki görülmez.
Kesikli dikdörtgen = devriye yolu.
Turuncu halkalar = duyulan ses (tıkladığınız yer).
Sağ: nöbetçinin “beyni”
Diyagram: dolu kutu = şu anki durum. Kalın kırmızı ok = az önce kullanılan geçiş.
Sayaçlar: nöbetçinin o anki algısı — can, oyuncuya mesafe, görüyor mu?
“Son 5 sn’de geçiş”: çok yüksekse nöbetçi kararsız (titreme) demektir.
Günlük: son geçişler ve zamanları.
Kontroller: fare = oyuncu · tıkla = ses çıkar · X = nöbetçiye ateş et (−25 can) · “1 kare” ile adım adım izleyin.
Nöbetçi FSM — canlı
🔎 DEMODA DENEYİN
Nöbetçinin arkasında bir yere tıklayın (ses). ŞÜPHE durumuna geçip oraya gidiyor mu?
Görüş konisine girin, sonra bir duvarın arkasına saklanın. KOVALA → ŞÜPHE geçişini izleyin: son gördüğü yere gidiyor.
Yaklaşıp SALDIR’a geçirin, sonra klavyeden üç kez X’e basın (her biri −25 can). Can 30’un altına düşünce hangi durumda olursa olsun KAÇ’a geçiyor mu? Can 70’i geçince ne oluyor?
▶| 1 kare düğmesiyle tek tek ilerleyin: sağdaki diyagramda kırmızı ok = az önce kullanılan geçiş.
The AI of Half-Life: Finite State Machines AI and Games (Tommy Thompson) · YouTube’da aç
Az önce elle yönettiğiniz nöbetçinin 1998’deki atası: Half-Life’taki askerlerin ve yaratıkların durumları, bu durumlar arasındaki geçişler ve her durumda çalışan “görev listeleri”.
🤔 İzlerkenVideodaki canavarın durumlarından hangileri bizim nöbetçinin beş durumuna karşılık geliyor? Bizde olmayan hangi durum var? “Koşul” (condition) dedikleri şey, bizim olay düğmelerimizden hangisine benziyor?
LEVEL 2
Kod: üç yol
switch · durum sınıfları · geçiş tablosu
durum ve geçiş
bir nöbetçi tasarlayalım
kod: üç yol
sorunlar ve çözümler
hiyerarşik ve yığınlı FSM
gerçek oyunlarda FSM
kütüphaneler ve entegrasyon
Yol 1: enum + switch (1/2)
Yol 1: enum + switch (2/2)
🎒 enum: sabit isimlerden oluşan tür — yazım hatası yapınca derleyici yakalar ("CAHSE" gibi string hataları sessizce bug olur!). Python’da enum.Enum, JS’te sabit nesne kullanılabilir.
🎒 Ön bilgi: arayüz ve çok biçimlilik
Arayüzinterface: “bu metotlara sahip olacağım” sözü. IState: Enter, Update, Exit
Her durum bu sözü veren ayrı bir sınıf: PatrolState, ChaseState…
Çok biçimlilikpolymorphism: nöbetçi sadece current.Update() der; hangi sınıfın kodu çalışacağına nesnenin türü karar verir
Python ve JS’te “arayüz” zorunlu değil: aynı isimli metotları yazmak yeter (ördek tiplemeduck typing: “ördek gibi vaklıyorsa ördektir”)
Yol 2: durum sınıfları State pattern
Artı: her durum kendi dosyasında, giriş/çıkış eylemleri temiz. Eksi: geçişler sınıfların içine dağılmış — bütün resmi görmek zor.
Yol 3: geçiş tablosu (veri güdümlü) (1/2)
Yol 3: geçiş tablosu (veri güdümlü) (2/2)
Artı: bütün davranış tek bir tabloda; tasarımcı (hatta bir JSON/CSV dosyası) değiştirebilir. Bu, PlayMaker ve Unity Animator gibi görsel editörlerin arkasındaki fikir.
Bütün program bu üç satırın etrafında döner: sense() algıyı toplar, nextState() geçiş tablosudur (laboratuvarda yazacağınız fonksiyon), act() her durumda ne yapılacağını söyler.
🎮 Çalıştırın, kopyalayın, bozun
▶ Eksiksiz örneği aç — yaklaşık 150 satır, tek dosya, yorumlu. Sayfada hem oyun hem kodun tamamı var; “kodu kopyala” ile editor.p5js.org’a yapıştırın.
Deneyin:
Çıkış eşiğini 90’dan 60’a çekin: titremeyi kendi gözünüzle görün.
Görüş açısını 110°’den 40°’ye indirin: arkasından dolaşmak ne kadar kolaylaştı?
Yeni durum: YARDIM_CAGIR — oyuncuyu ilk gördüğünde 1 sn dursun, sonra kovalasın.
🌱 Isınma kodu: trafik ışığı
Dünyanın en küçük durum makinesi: 3 durum, 3 geçiş. İki satır ekleyin. p5.js’te bunu draw() içinde bir zamanlayıcıyla çağırıp ışığın rengini state’e göre seçersiniz.
🌱 Isınma kodu: kapı (olaylı FSM)
Bu sefer geçişi zaman değil olay tetikliyor. Dikkat: kilitli kapı “ac” olayıyla açılmamalı, açık kapı kilitlenememeli — return state satırı bunu bedavaya sağlıyor. Bir FSM’nin gücü: izin verilmeyen geçiş, yazılmamış geçiştir.
🧪 Canlı laboratuvar: nöbetçinin beynini yaz
Tablodaki 9 kuralı tamamlayın (saldırıdan çıkış eşiği 90!). Çalıştırınca önce testler, sonra sağdaki canlı simülasyon sizin fonksiyonunuzla çalışır. Bilerek bir hata yapın (ör. KOVALA’dan çıkışı silin): nöbetçi nasıl davranıyor?
🐍 Kod laboratuvarı — Python
Geçiş tablosunun tamamını Python’la yazın. İpucu: önce “can < 30 ve durum KAC değilse → KAC” kuralı; sonra her durum için bir if/elif bloğu. Eşikler: saldırıya giriş < 60, saldırıdan çıkış > 90, şüphe süresi 4 sn, iyileşme > 70.
LEVEL 3
Sorunlar ve çözümler
titreme, durum patlaması, spagetti
durum ve geçiş
bir nöbetçi tasarlayalım
kod: üç yol
sorunlar ve çözümler
hiyerarşik ve yığınlı FSM
gerçek oyunlarda FSM
kütüphaneler ve entegrasyon
Titreme oscillation / flicker
Bu kopyada saldırıya giriş ve çıkış eşiği aynı (60) ve oyuncu (bot) nöbetçi yaklaştıkça yavaşça geri çekiliyor. Nöbetçi tam eşikte KOVALA ↔ SALDIR arasında saniyede defalarca gidip geliyor: “son 5 sn’de geçiş” sayacına ve diyagramdaki oka bakın. Histerezis kutusunu açın: çıkış eşiği 90 olur, titreme anında biter. İkinci kaynak: “algı hafızası” kapalıyken fareyle bir duvar köşesinin tam kenarında durun (KOVALA ↔ ŞÜPHE).
Titremeye üç çare
1) HisterezisGirmek ve çıkmak için farklı eşikler: “10 m’den yakınsa kovalamaya başla, 15 m’den uzaksa vazgeç.” Arada kalan 5 m: tampon bölge. (Termostatlar da böyle çalışır.)
2) Hafıza“Gördüm” bilgisini bir süre sakla: son görülme zamanı + konum. Algılama sunumunda ayrıntılı (Y11).
3) Minimum süreBir duruma girince en az 0,5 sn kal (timeInState). İnsan da saniyede 10 kez fikir değiştirmez.
Y1’deki kural: fikir değiştiren NPC, oyuncunun gözünde “bozuk YZ”dir. Titreme, yapay aptallığın en yaygın kaynağı.
Durum patlaması ve spagetti
Tasarımcı yeni istekler getiriyor:
“Mermisi bitince şarjör değiştirsin” → hangi durumlardan? Kovalarken, saldırırken, kaçarken… her birine ok
“Yaralı hâlde yürüyüş animasyonu farklı olsun” → Devriye-yaralı, Kovala-yaralı, … durum sayısı ikiye katlanır
“Telefon çalınca konuşsun, sonra kaldığı yerden devam etsin” → nereden geldiğini nasıl bilecek?
N durumlu bir FSM’de olası geçiş sayısı ~N². 20 durumda diyagram bir spagetti tabağına döner.
Çareler (sonraki bölüm ve sunumlar)
Hiyerarşi: durumları gruplara topla (HFSM)
Yığın: “öncekine dön” (pushdown)
Paralel FSM’ler: hareket ve silahı ayrı makinelerde yönet
Büyük karakterlerde: davranış ağaçları (Y3) ve utility (Y4)
Paralel FSM’ler: çarpma yerine toplama
Karakter aynı anda iki ayrı konuda karar veriyor: nasıl hareket ettiği ve silahıyla ne yaptığı.
Hepsini tek makineye koyarsanız her birleşim ayrı bir durum olur: “yürü + hazır”, “yürü + ateş”, “yürü + şarjör”, “koş + hazır”…
Yeni bir hareket (“sürün”) eklemek: üç yeni durum. Bir de “yaralı / sağlam” eklenirse: 3 × 3 × 2 = 18. Buna durum patlaması denir.
Çözüm: her konu için ayrı bir makine; hepsi aynı anda çalışır. Karakterin durumu = makinelerin o anki durumlarının birleşimi.
“Yürürken şarjör değiştir” için özel durum gerekmez: hareket makinesi “yürü”de, silah makinesi “şarjör”de.
Gerektiğinde mesajlaşırlar: silah “ateş”e geçince harekete “koşmayı kes” der.
konular
tek makine
paralel makineler
3 hareket × 3 silah
9
3 + 3 = 6
4 hareket × 4 silah × 3 sağlık
48
4 + 4 + 3 = 11
+ 5 duygu durumu
240
16
Unity’nin Animator penceresindeki katmanlar (layer) tam olarak budur: “bacaklar” ve “üst gövde” ayrı durum makineleridir; karakter koşarken şarjör değiştirebilir.
Quiz 2 · sorunlar
Nöbetçi “oyuncu 8 m’den yakınsa KOVALA, değilse DEVRİYE” kuralıyla çalışıyor ve oyuncu tam 8 m civarında dururken saniyede onlarca kez durum değiştiriyor. En uygun çözüm hangisi?
Tek eşik nerede olursa olsun sorun o çizgide tekrarlanır (A). Seyrek güncelleme titremeyi yavaşlatır ama çözmez (C). İki farklı eşik, arada bir tampon bölge bırakır: girmek ve çıkmak için farklı koşullar.
LEVEL 4
Hiyerarşik ve yığınlı FSM
durumların içinde durumlar, “öncekine dön”
durum ve geçiş
bir nöbetçi tasarlayalım
kod: üç yol
sorunlar ve çözümler
hiyerarşik ve yığınlı FSM
gerçek oyunlarda FSM
kütüphaneler ve entegrasyon
Hiyerarşik FSM HFSM
Her durum kendi içinde bir FSM olabilir
Üst seviyedeki geçiş (BARIŞ → SAVAŞ) içerideki bütün alt durumlar için geçerli: oklar azalır
“Can < 30 → KAÇ” artık dört ayrı ok değil: iki yeşil ok (BARIŞ’tan ve SAVAŞ’tan). Devriye, Şüphe, Kovala, Saldır — hangisinde olursa olsun çalışır.
Game AI Pro’daki örnek: gece bekçisi kasa ile kapı arasında devriye gezer. “Telefon çaldı → konuş → devriyeye dön” durumunu her devriye durumuna ayrı ayrı eklemek yerine, devriyeyi tek bir üst durum yaparsınız.
Problem: “işim bitince kaldığım yere döneyim”
🎮 Kesintiler
Nöbetçi devriye geziyor. Telefon çaldı: konuş. Konuşurken silah sesi geldi: alarm.
Tehlike geçince ne yapmalı? Telefona dönmeli. Telefon bitince? Devriyeye.
Oyun menüleri aynı kalıptır: ana menü → ayarlar → ses ayarları; “geri” tuşu bir önceki ekrana döner.
Düz FSM’nin derdi: tek bir değişkeni var: “şu anki durum”. ALARM’a geçince TELEFON’da olduğunu unutur. Alarm bitince nereye döneceğini bilemez; herkes “varsayılan” duruma (devriye) atılır.
Her kesinti için “önceki durum” değişkeni eklemek? Kesinti içinde kesinti olunca yetmez.
Fikir: durumu tek değişkende değil, bir yığında tut (Yığınlar sunumu: son giren ilk çıkar). Yeni iş çıkınca üstüne koy (push); iş bitince üstten al (pop): altındaki, yani yarım kalan iş kendiliğinden geri gelir.
Adı nereden geliyor? “Pushdown automaton” = “aşağı iten otomat”: yeni durum eskileri yığında aşağı iter. “Otomat”, durum makinesinin eski adı. Türkçesi: yığınlı durum makinesi.
Elle izleme (yığının tepesi sağda)
olay
yığınlı FSM: yığın
şu an
düz FSM: tek değişken
başlangıç
DEVRİYE
devriye
DEVRİYE
📞 telefon çaldı
DEVRİYE · TELEFON
telefon
TELEFON
🔫 silah sesi
DEVRİYE · TELEFON · ALARM
alarm
ALARM
✔ tehlike geçti
DEVRİYE · TELEFON
telefona döndü
??? → DEVRİYE
✔ telefon bitti
DEVRİYE
devriyeye döndü
DEVRİYE
Dördüncü satır farkı gösteriyor: yığın, alarmın altında telefonu saklamıştı; düz FSM telefonu çoktan unutmuştu, yarım kalan konuşma havada kaldı.
Kurallar: (1) şu anki durum = yığının tepesi; (2) yalnızca tepedeki durum çalışır, alttakiler bekler; (3) bir durum “işim bitti” deyince yığından çıkar. Menülerde: her açılan ekran push, “geri” tuşu pop.
Yığınlı FSM pushdown automaton
🔎 Deneyin Nöbetçi devriyede. Sırayla basın: 📞 Telefon çaldı → 🔫 Silah sesi → iki kez ✔ Bitti. Soldaki yığın her “bitti”de bir önceki işe döner (alarm → telefon → devriye). Sağdaki düz FSM tek bir değişken tuttuğu için telefonu çoktan unutmuştur: ???.
Durumları bir yığında tut (Yığınlar sunumu!): yeni bir kesinti üste eklenir (push), bitince çıkarılır (pop) ve karakter otomatik olarak kaldığı yerden devam eder. Düz FSM tek bir değişken tuttuğu için nereden geldiğini unutur.
📜 Statecharts (Harel, 1987)David Harel, hiyerarşi, paralel bölgeler ve geçmiş (history: “en son hangi alt durumdaydım?”) özelliklerini bir araya getirip statechart notasyonunu tanımladı — ilk uygulaması bir savaş uçağının arayüzüydü. Bugün UML durum diyagramları ve JavaScript’teki XState kütüphanesi bu fikirlerden gelir.
⚙️ Paralel FSM’lerBir karakterin aynı anda birkaç makinesi olabilir: hareket FSM’si (yürü/koş/çömel), silah FSM’si (hazır/ateş/şarjör), animasyon FSM’si. Birbirlerine mesaj gönderirler. Böylece “yürürken şarjör değiştir” için ayrı bir durum gerekmez — durum patlamasının çaresi.
LEVEL 5
Gerçek oyunlarda FSM
Doom, Metal Gear, Hollow Knight, Unity Animator
durum ve geçiş
bir nöbetçi tasarlayalım
kod: üç yol
sorunlar ve çözümler
hiyerarşik ve yığınlı FSM
gerçek oyunlarda FSM
kütüphaneler ve entegrasyon
📸 Oyundan bir kare: DOOM (1993)
Ekrandaki her canavar, birkaç slayt sonra satır satır okuyacağımız info.c tablosundaki durumlardan birinde: ayakta bekliyor, yürüyor, saldırıyor ya da acı çekiyor. Görsel: DOOM oyun içi görüntüsü, id Software, Wikipedia (eğitim amaçlı adil kullanım)
📜 Doom (1993): kaynak kodda bir FSM
Doom’un Imp’i: animasyon kareleri ile YZ durumları aynı tabloda. A_Look oyuncuyu görünce “görme durumu”na, A_Chase yakın mesafede saldırı durumuna geçirir (p_enemy.c). 30 yıllık kod, bugün okuduğunuz FSM’nin aynısı.
🎒 Doom tablosunu okuyalım: bir satır = bir durum
Tablonun her satırı beş bilgi taşır. İlk satır üzerinden:
{SPR_TROO, 0, 10, {A_Look}, S_TROO_STND2, 0, 0}
alan
değer
anlamı
sprite
SPR_TROO
Hangi yaratığın resimleri? TROO = “trooper”: oyundaki Imp (ateş topu atan kahverengi iblis).
kare
0
O yaratığın kaçıncı resmi çizilsin? (0 = A karesi, 1 = B…)
süre
10
Bu durumda kaç tic kalınsın? Doom saniyede 35 tic işler: 10 tic ≈ 0,29 sn.
eylem
A_Look
Bu duruma girildiğinde çağrılacak fonksiyon: “etrafa bak, oyuncu görünüyor mu?”
sonraki durum
S_TROO_STND2
Süre dolunca geçilecek satır.
Son iki sıfır kullanılmayan yedek alanlar. Satırların adı sağdaki yorumda: S_TROO_STND = “Imp, ayakta bekliyor”.
STND → STND2 → STND → …: iki satır birbirini gösteriyor: sonsuz bir bekleme döngüsü. Her 10 tic’te resim değişiyor (nefes alıyor gibi) ve A_Look çağrılıyor.
Döngüden nasıl çıkılıyor? Tablodan değil, eylemden: A_Look oyuncuyu görürse durumu elle S_TROO_RUN1’e çevirir. “Sonraki durum” sütunu yalnızca “hiçbir şey olmazsa” yoludur.
RUN1 … RUN8: sekiz satırlık yürüme animasyonu; her 3 tic’te A_Chase: oyuncuya doğru bir adım at, menzildeysen saldırı durumuna geç.
ATK1 → ATK2 → ATK3 → RUN1: iki karede hedefe dön (8 + 8 tic: oyuncunun kaçması için uyarı süresi), üçüncüde ateş topunu at, kovalamaya geri dön.
🎮 Neden böyle yazmışlar?Animasyon ve yapay zekâ tek tabloda: çizer yeni kare eklerken, tasarımcı süreleri değiştirirken programcıya gerek kalmaz. “Imp’in ateş etmeden önceki bekleme süresi” bir sayıdır: 8’i 4 yaparsanız oyun zorlaşır. Oyundaki bütün yaratıklar, silahlar ve eşyalar aynı tablonun 967 satırıdır.
Aynı tablo, durum diyagramı olarak: Imp’in beyni
Bu sunumun başındaki nöbetçi FSM’siyle karşılaştırın: Devriye ↔ BEKLE, Kovala ↔ KOVALA, Saldır ↔ SALDIR. Fark yalnızca yazım biçiminde: orada switch, burada veri tablosu. Tabloyla yazılan FSM’ye “veri güdümlü” denir: davranışı değiştirmek için kodu değil veriyi değiştirirsiniz.
Oyunlardan FSM örnekleri
Metal Gear Solid 2 (2001)Nöbetçilerin bütün üssü kapsayan alarm evreleri: Sızma (normal) → Alarm (görüldünüz, ekranda geri sayım) → Kaçış (sizi arıyorlar) → Dikkat (tetikte devriye) → normal. Ekrandaki sayaç oyuncuya FSM’nin hangi durumda olduğunu açıkça gösterir.
Hollow Knight · HearthstoneTeam Cherry, Hollow Knight’ın düşman ve boss davranışlarını Unity için görsel bir FSM aracı olan PlayMaker ile kurdu (mod yapımcıları bu FSM’leri düzenler). Blizzard da Hearthstone’daki birçok olayı PlayMaker ile yaptı: sanatçılar kod yazmadan etkileşim kurabildi.
Half-Life (1998)Askerler “görev planları” (schedule) ve durumlardan oluşan bir FSM ile çalışır; bir koşul bozulunca plan kesilir ve yenisi seçilir. AI and Games’in “The AI of Half-Life” videosu ayrıntılı anlatıyor.
Final Fantasy XV (2016)Karakter YZ’si davranış ağaçları ile durum makinelerini birleştirir: büyük resim FSM, her durumun içi davranış ağacı (Game AI Pro 3, 11. bölüm). Gerçek projelerde teknikler karışır.
📸 Oyundan bir kare: Metal Gear Solid 2 (2001)
Muhafızlar oyuncuyu fark edince bütün üs “alarm” evresine geçer; ekranın köşesindeki sayaç evrenin ne kadar süreceğini gösterir. Sonraki slayttaki diyagram bu evreleri çiziyor. Görsel: Metal Gear Solid 2: Substance ekran görüntüsü, Konami, Wikipedia (eğitim amaçlı adil kullanım)
Metal Gear Solid 2: bütün üssün tek bir durum makinesi
Burada FSM tek bir nöbetçinin değil, bütün üssün ortak durumudur: bir nöbetçi telsizle haber verince herkes aynı anda ALARM’a geçer.
Geçişlerin çoğu süreye bağlı: KAÇIŞ ve DİKKAT’te ekranda geri sayan bir çubuk var. Sayaç bitene kadar saklanabilirseniz bir sonraki, daha sakin duruma geçilir.
🎮 Tasarım dersi: FSM’yi oyuncuya gösterinÇoğu oyunda durum makinesi gizlidir; oyuncu düşmanın ne düşündüğünü tahmin eder. Metal Gear durumun adını ve kalan süresini ekrana yazar: oyuncu “şu an neredeyim, ne kadar dayanmalıyım?” sorusunun cevabını bilir ve plan yapar. Gizlilik oyunlarındaki “!” ve “?” işaretleri de aynı işi görür (Y11, Y19).
Bir duruma StateMachineBehaviour betiği eklenebilir: OnStateEnter, OnStateUpdate, OnStateExit
⚠️ Tartışmalı: YZ mantığını Animator’a koymak hızlıdır ama animasyon ve karar birbirine karışır. Çoğu ekip kararı ayrı bir FSM’de verip Animator’a sadece parametre gönderir (animator.SetBool("IsChasing", true)).
Quiz 3 · oyunlarda
Metal Gear Solid 2’nin “Alarm → Kaçış → Dikkat → Sızma” evrelerinin ekranda bir sayaçla gösterilmesinin YZ tasarımı açısından en önemli faydası nedir?
Y1’deki ders: oyuncunun anlamadığı YZ “rastgele” görünür. Durumu görünür kılmak (sayaç, müzik, nöbetçi replikleri) oyuncuya bilgiye dayalı karar verdirir ve YZ’yi adil hissettirir.
Hafif FSM; tetikleyiciler, koşullar, giriş/çıkış geri çağırmaları
pip install transitions
Aynı nöbetçi, üç kütüphaneyle
Fark: UnityHFSM koşul güdümlü (her karede kontrol eder), XState ve transitions olay güdümlü (bir şey olunca siz haber verirsiniz). Oyunlarda ikisi de yaygın.
🧩 Projenize FSM eklerken: adım adım
Kâğıtta çizin: durumlar, oklar, koşullar. Tabloya dökün (bu sunumdaki gibi).
Algıyı ayırın: SeesPlayer(), HeardNoise gibi fonksiyonlar FSM’nin dışında hesaplansın.
Önce en basit hâli: enum + switch ile 2–3 durum. Çalıştığını görün.
Hata ayıklama görselleri: NPC’nin başına durum adını yazın (Unity: OnDrawGizmos / Handles.Label). Bu sunumdaki demolar gibi.
Büyüdükçe: durum sınıflarına ya da bir kütüphaneye (UnityHFSM) geçin.
Animasyonla bağ: FSM karar verir, Animator’a parametre gönderir.
⚙️ PerformansFSM çok ucuzdur: her karede sadece aktif durumun kodu ve onun birkaç koşulu çalışır. Pahalı olan koşulların kendisi (görüş ışını, yol bulma). Onları her karede değil, saniyede birkaç kez hesaplayın (Y18).
🤖 Bu konuyu bir YZ kod asistanıyla yazarken
Sık yapılan hatalar — kontrol edin
Her karede new ChaseState() üretmek (GC çöpü — durumları bir kez oluşturup saklayın)
String durum adlarında yazım hatası (enum kullanın)
Karar mantığını Animator geçişlerine gömmek
İyi bir istek (prompt) örneği
“Unity 6, C#. Bir Guard için enum + switch ile FSM yaz: durumlar Patrol, Suspicious, Chase, Attack, Flee. Geçiş tablosu şu: [tabloyu yapıştır]. Kovalamaya başlama mesafesi 8, bırakma mesafesi 12 olsun (histerezis). Her durum değişiminde Debug.Log yaz ve OnDrawGizmos ile durum adını karakterin üstüne çiz. Durum değişince Animator’a "State" int parametresi gönder.”
Durum ve geçiş tablosunu isteğe siz yazın; asistana tasarımı değil kodu yaptırın
Hangi yolu istediğinizi söyleyin (enum+switch / State pattern / UnityHFSM)
Her geçişte Debug.Log ile durum yazdırmasını isteyin
Titreme önlemini (histerezis, minimum süre) açıkça isteyin
💬 Tartışma soruları
Yanınızdakiyle 2 dakika konuşun, sonra sınıfça tartışalım
Bugün kullandığınız, oyun olmayan bir şeyin (asansör, çamaşır makinesi, otomat, telefon kilidi) durumlarını ve geçişlerini sayın. Hangi geçiş yasak?
Metal Gear Solid, nöbetçinin durumunu ekranda sayaçla gösteriyor. Aynı şeyi bir korku oyununda yapar mıydınız? Durumu göstermek ne zaman oyunu bozar?
Nöbetçinize 6. bir durum ekleyeceksiniz: “arkadaşını yardıma çağır”. Kaç yeni ok çizmeniz gerekir? Bu sayı sizi neden rahatsız etmeli?
Titreme (KOVALA ↔ ŞÜPHE) bir hata. Peki bir karakterin bilerek kararsız görünmesini isteyeceğiniz bir sahne olabilir mi? Nasıl tasarlardınız?
[kolay]Pac-Man modları — Y1’deki Pac-Man demosuna korku modunu ve “yenildi → evine dön” durumunu ekleyin; diyagramını çizin.
[orta]Gizlilik oyunu — Unity’de 3 nöbetçili bir oda: bu sunumdaki FSM + görüş konisi + MGS tarzı alarm evreleri (bütün nöbetçileri etkileyen global FSM).
[orta]Yığınlı menü — Oyununuzun menülerini yığınlı FSM ile yazın (ana menü → ayarlar → ses → geri).
[zor]HFSM boss — Üç fazlı bir boss: her faz bir üst durum, içinde 3–4 saldırı durumu. UnityHFSM ya da LimboAI ile.
[araştırma]Doom’u okuyun — Doom kaynak kodunda (info.c, p_enemy.c) bir canavarın bütün durumlarını çıkarıp diyagramını çizin. A_Chase hangi koşullarda saldırıya geçiriyor?
Neler öğrendik? 🎒
FSM: sonlu durum + geçişler; her an tek durum.
Tasarım: önce tablo/diyagram, sonra kod.
Kod: enum+switch (basit), durum sınıfları (düzenli), geçiş tablosu (veri güdümlü).
Titreme: histerezis, hafıza, minimum süre.
Durum patlaması → HFSM, yığınlı FSM, paralel FSM’ler.
Gerçek oyunlar: Doom, MGS2, Half-Life, Hollow Knight, FFXV.
Sonraki: davranış ağaçları — büyük karakterler için daha modüler bir yol.
🎮 Bu sunumdaki oyunlar
Adı geçen oyunu tanımıyorsanız: oyuncuların kullandığı wiki sayfası ve oyunu kısaca gösteren bir video. ▶ video slaydın üstünde açılır (Esc ile kapanır); 🎯 işaretli bağlantılar doğrudan bu sunumdaki konuya gider.
Pac-Man1980 · arcade
Labirentte yem toplayıp dört hayaletten kaçarsınız; her hayaletin ayrı bir kovalama kuralı var.