leonscottkfm

Unreal MVP
31 May 2015
1,441
5
193
63
27
(34) İstanbul Avrupa
store.steampowered.com
Merhaba arkadaşlar,

Uzun süredir üzerinde çalıştığım multiplayer bir oyun projem var ve projemde yapay zekanın önemi büyük.
Hayatımda ilk defa behavior tree kullanarak yapay zeka yapmak istedim, çünkü kaliteli olmalı ve zor kararları alabilmeli.Fakat bir problem yaşıyorum.
Yapay zeka beni kovalıyor vuruyor diyelim, fakat ben yanımdaki oyuncudan uzaklaşınca ona saldırmak yerine benim karakterim silinene kadar bana saldırıyor. Yani hafızasına bir kişiyi aldığı zaman o şahıs ölene kadar ona gidiyor , fakat olması gereken şey en yakında kim varsa o veriyi sürekli güncelleyip yakındakine saldırmalı. Biliyorum çok ufak bir yerde hata yaptım ama nerede yaptım :/














HandleSightSense adlı fonksiyon perception kullanarak herhangi bir düşmandan uyaran almayı sağlıyor , daha sonra bu uyaranı actor kısmına kaydediyor. Normalde bu single player için yapılmış fakat ben getallactors ile tüm oyuncuları foreachloop yaparak çektim ve gerekli bölüme bağladım. Onlardan birine eşit ise onu kovalıyor fakat belli bir süre kovaladıktan sonra Actor değişkeninin içini boşaltıp oraya en yakındaki gördüğü oyuncuyu yazması gerekiyor. Bu sorun ancak o şekilde düzelebilir.
LastKnownLocaiton ise görülen en son konuma gidip orada araştırma yapmasını sağlamakta. Delay falanda kullanamıyorum fonksiyonun içerisinde nasıl belli bir süre sonra actor değişkenini boşaltıp en yakındaki oyuncuyu ekleyeceğim ?
 
1. Actor değişkeninin içindeki kişi ile arasındaki mesafeyi ölçtür(Distance to node'u ile yapabilirsin). vector uzunluğunu alıp buna bir sınır ekle. O sınırı aştığında yeni bir event çalıştırmasını sağla. Bu event bu mesafeyi aşmayan oyuncu kim ise onu bulmak üzerine olsun. Yani for each loop ile hepsini çekip kontrol etsin.

Veya;

2. Yine mesafeyi kontrol ettir. Sınırı aşıyorsa kullandığı AI varlık SphereTrace atsın olduğu yerde. SphereTrace çapını kendin ayarlarsın ne kadar mesafeye etki edeceğini ve kimler ile overlap olacağını. Temas ettiği Actorler arasında mesafe kontrolü gerçekleştirsin ve en yakın olanı tekrar kovalasın veya her ne yapacaksa yapsın. Kimse ile temas etmez ise devriye gezsin veya döneceği yer varsa dönsün.
 
1. HandleSense fonksiyonuna OnTargetPerceptionUpdated dan gelen "Actor" ü  gönderiyorsun. Stimulusu kimin aktive ettiğini gösteriyor o, yani doğru yapmışsın. Ama nedense HandleSense fonksiyonu içerisinde onu kullanmayıp GetAllActorsOfClass a dönüyorsun. Halbu ki senin ilgilendiğin tek şey oradaki "Actor".
2. Behaviour Tree lerde "Services" diye bir konu var. Bunu öğrenmen gerekiyor ki doğru olarak söylediğin tarz sistemleri kullanabilesin.
 
"Tüm oyunculara yönlendirme yapmak" derken neyi kastediyorsun tam olarak anlamıyorum ama yukarıda anlattığım gibi OnTargetPerceptionUpdated  fonksiyonu duyu ile fark edilen her oyuncu için ayrı ayrı otomatik olarak çalışır zaten. Oradaki Actor parametresi de zaten o anda duyu ile farkedilen actor ü gösteriyor. Ama sen HandleSightSense fonksiyonuna bu değeri gönderdiğin halde, o fonksiyon içerisinde onu hiç kullanmıyorsun. Yani senin mantık şöyle bir şey oluyor "Ben şu an Ahmet i fark ettim ama ben herkesi bulup onlar üzerinde işlem yapmak istiyorum". Bir sonraki olay da da "Ben şu an Mehmet i fark ettim ama ben yine herkesi bulup onlar üzerinde işlem yapmak istiyorum" vb gibi bir şey. ( Belki de böyle bir şey yapmaya çalışıyorsun ondan da emin değilim açıkçası.)
 Şöyle anlatayım birde: Yani senin etrafında 5 karakter varsa, hepsi aynı anda görüş alanına girseler, bu kırmızı OnTargetPerceptionUpdated  event i 5 defa her biri için ayrı ayrı çalışacaktır. Farklı zamanlarda görüş alanına girseler de giren girdiği an o event i çalıştıracaktır.
  Senin resimlerde Actor adında bir değişkenle karşılaştırma yapıyorsun. Bu Actor nerede dolduruluyor resimlerde yok. Muhtemelen default olarak bir şey koymuş olabilirsin. Eğer o an görülen actorü almak istiyorsan o zaten HandleSightSense te var. Onu "Şu an görülen Actor değişkenimde ki actor mü" diye bir == eşitlik kontrolü yapabilirsin.
 Son olarak tüm AI, behaviour tree systemi tamamen multiplayer a uyumludur.
 
Actor kısmı "select" node ile doluyor orada. Eğer sight olduysa yani karakter görüldüyse A yı alıyor görülmediyse B yi alıyor B ise boş .
Bende A kısmına GetallActorsten tüm oyuncuların karakterlerini foreach ile çektim. Yani PlayerBase adında bir karakterimiz var ve diğer tüm karakterler bunun Child classı. PlayerBase master BP yani . Ben de PlayerBaseyi çekiyorum A kısmına bağlıyorum . Yani herhangi bir playerbase karakterini gördüyse ona yönelsin istiyorum.
Senin dediğin gibi yaparsam herkesi aynı anda görüyor ve kafayı yiyor. Ben en yakındaki oyuncuyla uğraşsın istiyorum ve bir süre sonra o actor kısmı boşalsın başka en yakındaki oyuncu ile uğraşsın.
Ama fonksiyon içerisinde delay kullanamıyorum . 20 saniye birini kovaladı diyelim ki , başka bir oyuncu gördüğünde artık ilkini bırakıp ona yönlenmeli. Yoksa maymun ederler AI yi. Devour ve Pacify oyunundaki gibi bir yapay zeka yapmak istiyorum kime yakınsa gidip ona saldırsın 
:(



Benim burada yapmaya çalıştığım şey , eğer ai tüm playerbasecharacter lerden birini gördüyse ona yönelsin. Actor olarak onu seçsin yani. Ve o şekilde çalışıyor fakat o eleman destroy olana kadar onu kovalıyor. Diğerlerini görmüyor bile. Birini alıyor hafızaya o kalıyor.
 
Gösterdiğin hiç bir resimde Actor değişkeni dolmuyor. Son resimdeki kırmızı işaretli yerde gelen foreach elemanları ile Actor değişkenin eşitlik kontrolü yapılıyor sadece. Tahminimce Actor değişkenini default bölümünde dolduruyorsun ama gösterdiğin hiç bir resimde bu yok. Select ile dolan şey ise BT deki TargetActor. O da tamamen farklı bir şey Actor değişkenin ile alakası yok.
Yukarıda anlattım ama bir daha anlatayım. Çünkü öncelikle elindeki malzemenin nasıl çalıştığını anlaman gerekiyor: OnTargetPerceptionUpdated birisi algılandığında ( ya da algılamadan çıktığında) çalışan bir event. Yanlış hatırlamıyorsam eğer "StimulusSuccessfullySensed" ilk algılandığında "true" gelecektir. Algı alanından çıktığında ise "false" olarak gelecektir. Yani perception component ta sight config te belirttiğin uzaklığın içerisine bir karakter girdiğinde bu event çalışacak ve herhangi birisi dışına çıktığında bu event yine çalışacaktır. Dolayısı ile sen aslında şöyle bir şey yapmaya çalışıyorsun:
1. Bu event çalıştığında ve "StimulusSuccessfullySensed" true olduğunda yeni birisi algılandı demektir. Bu algılanan kimse eğer event ile beraber geliyor zaten (Actor parametresi - değişken değil). Bu kişiyi algı alanında olanların listesine alacaksın yani bir arraya. (GetCurrentlyPerceivedActors vardı onu da kullanabilirsin direk yanlış hatırlamıyorsam).
2. Listedeki diğer actorlerle yani algı alanında o an bulunan herkesle distance yani uzaklik kontrolü yapacaksın. Eğer bu yeni algılanan kişi en yakınsa onu TargetActor e vereceksin. Eğer en yakın değilse sadece listeye eklemekle yetineceksin TargetActor e vermeyeceksin. ( Uzaklık kontrolününde EQS ile kolay direk yapımı vardı ama uzun zaman oldu şu an hatırlamıyorum )
3. Dolayısı ile tüm actorler aynı anda "sense" edilmiş olsalar bile uzaklık kontrolü ile en yakın olan sadece target actor e gidecek.
4. Dikkat edersen GetAllActorsOfClass falan yok. Zaten varsa %95 yanlış yoldasındır.

Ancak bu sistemde bir eksik var. Ve tam doğru çalışamaz. Mesela 5 karakterden 3 ü bizim görüş alanımızda ise ve bu 3 karakterden biri halen görüş alanımızda kalarak diğerinde daha yakın bir konuma geçerse yukarıdaki sistem bunu algılayamayacaktır. Ek şeylerle bu da halledilebilir
Dolayısı ile yapılması gereken 3 yöntem olabilir.
 1. EQS ile otomatik olarak en yakın karakteri seçtirmek. (En kolay ve en doğrusu)
 2. Service kullanarak o an algı alanımızdaki herkes üstünde sürekli distance yani uzaklık kontrolünü yapmak ve ona göre TargetActor ü doldurmak.
 3. Yukardaki sistem deki boşluğu dolduracak tick te bir kontrol fonksiyonu yazmak.

Ama en önemlisi daha basit seviyede önce herşey nasıl çalışıyor ne işe yarıyor bunları anlamak gerek. Yoksa çok zor gelir.