Merhabalar,
Burada Event Dispatcher ların UE içinde nasıl uygulandıklarını anlatmayacağım. Bu konuda internette bir çok ders tutorial mevcut. Ben sadece neden kullanmanız gerektiğini anlatacağım. Bunun için 2 genel sebep var. Birisi optimizasyon, Diğeri ise haber yayımı (Benim deyimimle). Önce mantığını anlatacağım sonra bu iki sebebi örneklerle açıklamaya çalışacağım:
Mantığı:
Dispatcher ingilizcede telsiz anlamında kullanılır. Mesela polisler telsize "Dispatcher" derler ve şöyle kullanırlar: Bir polis amiri ya da her hangi bir polis telsizden yayın yapar "Şu şu mahallede hırsız görüldü şu an peşindeyiz tüm birimlerin dikkatine". Bunu duyan bütün polisler duyar duymaz ellerinde ki işi bırakır ve o hırsıza yönelirler. Bu sırada merkezde santral deki polis belki daha üst amirlere haber ulaştırırken o da kaymakam muhtar falan onları arar. Bu sırada bunu duyan trafik polisi ise yolları kesmeyi düşünebilir. Gece bekçileri ise o mahalledeki bekçi sayısını derhal arttırabilir. Bütün bu işler nasıl başladı, bir polis memurunun bir telsiz çağrısı ile. Bu arada telsiz tüm herkese haber vermek için kullanıldığı gibi sadece iki polis arasında da haberleşme amacı ile kullanılabilir. Mesela bir polis diğerine benim yanıma gelir misin diyebilir. İşte UE Event Dispatcher aynen budur. Bütün o referanslarla ulaşmaya çalıştığınız değişken tuttuğunuz sistemleri kenara koyup oyun içerisindeki bir obje den diğerine telsiz çağrısı yapsam o da ne yapması gerekiyorsa onu yapsa olmazmı diye düşünseniz. Bir polisin çağrı yaptığı gibi mesela oyundaki karakterimiz bir çağrı yapsa ve bu çağrı oyundaki tüm widgetlara hatta diğer nesnelere de ulaşsa, ve tüm bu kendilerine düşen işi otomatik yapsalar olmazmıydı. Event Dispatcher aynen budur. Şimdi örnek verelim.
1. Optimizasyon:
Mesela Call of Duty gibi bir oyun yapsaydınız ve ana karakterinizin bir HealthBar yani bir can göstergesi olsaydı: Muhtemelen UMG widget ta bir progressbar yapardınız ve karakterin health (Can) değerini buraya bağlardınız değil mi? Even en basit çözüm yolu böyledir ancak bu normalde yüklenmesi gereken CPU yüküne göre belki 200 kattan daha fazla iş yükü getirecektir. Çünkü widget ı karakterin health değişkenine bağladığınızda diyorsunuz ki: " Her saniye de 1000 defa Health(Can) değerini kontrol et ve buradaki widgetın değerini güncelle". Bu aynen yukarıdaki analojide şuna benziyor. Bir polis diğer bir polisi saniye başına 1000 defa arıyor ve soruyor "iyi misin?, bir şeyin varmı? bir değişiklik varmı?". Ne kadar büyük bir israf olurdu değil mi. Ama bunu şöyle bir sistem yapsaydık. Karakterimizde bir EventDispatcher (Telsiz) olsaydı ve bizim widget ımız kendisini güncelleyen bir fonksiyonu (yani telsiz çağrısı sonucu yapılması gereken işi ) bu Event Dispatcher a bağlasaydı. Karakterimiz sadece kendisine bir darbe geldiğinde EventDispatcher ını ateşleseydi ( Polis diyor ki telsizden "Bana bir darbe geldi") bu otomatik olarak ona bağlı olan tüm fonksiyonları çalıştıracaktı. Dolayısı ile widget fonksiyonu da ona bağlı olduğu için bizim ekrandaki göstergemiz yine olması gerektiği gibi güncellenecekti.
Peki iki yöntem arasında ne gibi bir fark var burda. Birinci herkesin bildiği yöntemde saniye de 1000 defa bakmasını istiyoruz o değişkene ve değişken aynı da olsa yine de o göstergeyi güncelliyoruz. Bu büyük bir kaynak israfı. Onun yerine ikinci sistemde eğer karakter 5 dakika boyunca hiç darbe almasa o 5 dakika boyunca o değişken hiç kontrol bile edilmeyecekti. Sadece değerinde bir değişiklik varsa o gösterge güncellenecekti. Saniyede 1000 defa olan bir şeyin 5 dakika da ne kadar boş iş yaptığını siz hesap edin. Peki ya bu hesap işi health yani can hesabı gibi basit bir şey olmasaydı ve biraz daha karmaşık bir hesap kitap gerektirseydi. O zaman saniye de 1000 defa yaptığınız o hesap sonucu değişmese de oyunu durma noktasına getirecekti. O zaman mecbur event dispatcher ları öğrenmek zorunda kalacaktınız.
2. Haber Yayılması:
Event Dispatcher ların asıl varoluş maksadı ise bu konudur. Burada şöyle bir şey düşünün oyunda bir şey olacak ve oyundaki bir çok nesne buna kendisine uygun şekilde tepki verecek. Yani teknik olarak bir yerde bir Event Dispatcher olacak, diğer tüm istekli nesneler kendilerine uygun bir fonksiyonlarını buna bağlayacaklar. Gerektiğinde Event Dispatcher ateşlenecek ve tüm bu diğer nesneler gereken şeyi yapacaklar. Şimdi örneğe geçelim (örneği anlaşılsın diye extreme veriyorum).
Bir hayatta kalma türü oyun düşünelim. Oyun da bir anda hava sıcaklığı -40 ın altına düştüğünde oyunun her tarafında bir donma etkisi oluşmasını istiyorsunuz. Şöyleki hava sıcaklığı -40 ın altına düştüğünde, havada uçan kuşlar donarak yere düşsün, etrafta bulunan su birikintileri buza dönüşsün, evlerin saçaklarında buz sarkıtları oluşsun, oyundaki buz dolapları donarak açılamaz hale gelsin, karakterini hızı yavaşlasın ve canı azalmaya başlasın, bu sırada çevrede bulunan diğer karakterler ya da NPC ler yardım istemeye ya da evlerine koşuşmaya başlasınlar, bir kaç tane buz golemi yuvasından çıkıp köylere inip av arasınlar ekrandaki buz göstergesi de dolmaya başlasın falan filan.
Şimdi bir dakika düşünün bu sistemi en etkin şekilde nasıl yapardınız? (Burda bire bir yani bir NPC öldü kapı açıldı gibi bir ilişki değil 1 e 10000 gibi bir ilişki var)Tüm bu nesnelere birer "Custom Event" verip sonra hepsine sırası ile "Get All Actors of Class" la ulaşıp bir yerden bir döngüye sokup her nesnenin eventini ayrı ayrı çağırır mıydınız ? Peki bir de şu durumu eklesem: Bazı insanlar evlerinde olduğundan bunlardan hiç etkilenmemesi gerekse yani get all actos of class aldığınız ve bulduğunuz tüm karakterlere de bunu uygulamamanız gerekse işler daha da kompleks hale gelmez miydi? Ya siz bu uzun döngüyü çalıştırırken orada olması gereken bir nesne yok olsa, mesela kuş ölmüş olsa oyun çökerdi. Peki sonradan bir başka fonksiyon daha eklemeniz gerekse ya da yeni bir şey yapmanız gerekse. Mesela dışarıda bulunan kedi köpekler donarak ölüyor gibi. Eklemeniz gittikçe bu sistemi daha sıkıntıya sokardı.
Bunu Event Dispatcher lar ile şöyle çözüyorsunuz. Her nesneye, bu nesnenin cinsi ne olursa olsun bir event yazıyorsunuz ve bu eventi level BP içerisinde tanımlı FrostEventDispatcher isimli event dispatcher a bağlıyorsunuz. Yani her nesne BeginPlay olduğunda bu eventini Level BP de bulunan event dispatcher a bağlıyor. Yapmanız gereken tek şey level bp de bu FrostDispatcher ı ateşlemek ve unutmak. Oyunda bulunan her nesne kendisine uygun olan işi otomatik yapacaktır. Siz yeni bir şey eklemek istediğiniz de onun bu eventini oraya bağlayabilirsiniz sadece. Dikkat edin. Burada Level BP ateşlediği bu şeylerin ne yaptığından haberi bile yok. Kaç kişinin cevap vereceğinden bile haberi yok. Umurunda değil. O sadece ateşlemeyi yapıyor. Ona bağlanan (Telsize abone olan diyelim polis dilinde) herkes kendiliğinden ne yapması gerektiğini bilecek ve otomatik uygulayacaktır. Mesela burada can barımız göstergemiz aslında bir actor bile değil. Ama o bile ne yapması gerektiğini biliyor ve onu yapıyor. Oyun boyunca "sıcaklık -40 a düşebilir" diye düşünmüyor. Düşerse zaten one level bp haber verecek. Tüm bu nesnelere tick fonksiyonunda hava sıcaklığını kontrol et derseniz oyununuz gereksiz yere performans olarak durma noktasına gelebilir. Bir de her şeyi tick te sürekli kontrol ettirerek kendinize de zulmetmiş olursunuz. Orası öyle kalabalıklaşır ki artık takibi zorlaşır.
Yani özetle bir nesne telsiz den yapıyor "Hey benim durum değişti duyanlar tepki göstersin !". O kanala bağlı olan herkes kendi içerisinde ne yapacağını tanımladığı zaman 10 numara sistem işliyor. Bu arada bazı insanlar eve girdiklerinde bu telsizi kapatabilir, çıktıklarında tekrar aça da bilirler. Böylece bu haber geldiğinde onların gereksiz yere heyecan yapmasına da gerek kalmaz. Yani oyunda bir şeyi insan yaptınız diye her durumda tepki vermesi de gerekmez. Sobanın yanına yaklaştığında telsizin o kanalını kapattırırsınız uzaklaştığında açtırırsınız sistem işlemeye devam eder.
Bir nesne kendisine kimin abone olduğunu, kaç abonesi olduğunu, ya da abone olanların ne yaptığını umursamadan çağrı yapıyor. Her nesne nereye abone olduğunu o abone olduğu yerde başka kaç abone olduğunu diğerlerinin ne yaptığını umursamadan o çağrıya cevap veriyor.
Umarım biraz açıklayıcı olmuştur.
(Örneği herkes sürekli kullandığı için level bp den haber uçuyor gibi verdim ama siz onu her objeye uygulayabilirsiniz. Meselea karakter bp ya da game mode ya da game instance ya da herhangi bir actor. Ne olursa yani kimin haber uçurduğu hiç te önemli değil. Yani event dispatcher ın nerede tanımlanım nerede ateşlendiği hiç önemli değil. Ayrıca fonksiyon dediğim her yeri custom event olarak anlayabilirsiniz.)