leonscottkfm

Unreal MVP
31 May 2015
1,541
5
219
63
28
(34) İstanbul Avrupa
store.steampowered.com
Online projemde oyuncuların yürüme sesini yapmak istedim. Asfaltta farklı kumlu bir alanda farklı vs.
Oyuncunun animasyonuna notify ekledim , project settingsten surface ekledim ve asfalta belli physics material diğerlerinede olması gerektiği gibi ekledim tek tek.

Sonra oyuncuların ayakları yere değiyorsa belli bir ses çıkmasını sağladım. Ve bu oyuncular birbirlerinin yürüme sesini duyabiliyorlar. Ama şöyle bir problem var .

Bir oyuncu asfalta yürüyorsa diğeri asfaltta yürüyen kumda yürüyenide asfalt sesiyle duyuyor. Kumda yürüyen ise asfalta yürüyeni kum sesi ile duyuyor. Bu problemi nasıl çözebilirim ?





Kodum şöyle bir şey zaten bunu biliyorsunuzdur. Fakat herhangi bir replication işlemi uygulamadım ben. AnimBP de zaten replication işlemi uygulanmıyormuş herhalde.

Büyük ihtimalle problem getplayercharacter>getactorlocation kısmında
Çünkü getplayercharacter her zaman ID 0 ı alıyordur büyük ihtimalle.

Asıl sorun şu:
Her oyuncu için özel işlemi nasıl uygularım ? Mesela getplayercharacter yaparsak herkesin kendisini local olarak alıyor. Fakat aynı şekilde CasttoThirdrpersonCharacter yaparsakta bu sefer tüm oyuncular aynı işleme maruz kalıyor.
Herhangi bir obje bir karaktere hasar verecekse o karakteri yani oyuncuyu diğerlerinden nasıl ayırıp işlem yapacağız ?
 
Evet AnimGraph ta replication olmuyor. En azından en son baktığımda öyleydi.
GetPlayerCharacter sadece o an oynayan oyuncuyu verir. Yani oyunda 300 kişi de olsa, oyunu o an oynayan karakter geri döner. Sen anim graph ta alttaki yüzeyi kontrol ediyorsun ama kimin altındaki yüzeyi. Muhtemelen diğer tüm karakterlerde de bu AnimGraph çalışıyordur. GetPlayerCharacter yaptığın için oyundaki herkesin AnimGraphı sadece "asıl oyunu oynayanın" bastığı yeri kontrol ediyor şu an. O nereye basıyorsa orayı hesaplıyor. TryGetPawnOwner ile o "AnimGraphı kullanan" karaktere ulaşıp onun basıtığı yere göre işlem yapman gerekli. Böylece herkes kendi bastığı yere göre ses çalabilecek. (Cast in bu konuyla zaten alakası yok. TryGetPawnOwner dan gelen Pawn ı Characterine çevirmek için kullanabilirsin sadece ama altındaki zemini kontrol etmek için o da gerekli değil).
   Diğer karakterlere ulaşmak çok kolay ama duruma göre değişir. Mesela Apply damage kullandıysan, o karakterin take damage i zaten çalışacaktır. Bir şey değdiğinde ulaşmak istiyorsan OnComponentBegin Overlap sana hangi karaktere dokunduğunu Actor olarak sunacaktır. HitTrace ile mesela silah hedeflemesi için ulaşmak istediğinde hittrace ten sana HitResult ın içerisnde Actor cinsinden yine verilecektir. Bunun gibi ne yaptığına göre diğer karakterlere ulaşma şeklin değişebilir. Hepsine birden ulaşmak istersen GameMode da PlayerController ların listesi var. Oradan GetPawn ile o an oyunda ki tüm karakterlere ulaşabilirsin. GetAllActors of Class ta kullanılabilir. Ama hepsine birden ulaşmak genel de ihtiyaç duyulmayan bir şeydir.
 Not: " Fakat aynı şekilde CasttoThirdrpersonCharacter yaparsakta bu sefer tüm oyuncular aynı işleme maruz kalıyor." Bu sözü anlamadım. Yani bazı karakterler bastıkları yeri kontrol etmesin mi istiyorsun? Bazı karakterlerin bu işlemlerden dışarıda kalmasını istiyorsan eğer kriter nedir ? Yani neye göre bir karakter üzerine bastığı şeyin kontrolünü yapmalı ya da yapmamalı ?
 
Mesela kısaca anlatayım.

Erginegider aşağıda küçük bir örneğim var. Mesela bir top actorü yaptım ben ve bizim oyuncularımızdan biri bunu overlap eder alır ise bu top silincek ve mesaj gönderecek değil mi?

Bu kod doğru mudur ? Bir oyuncu top aktörünü alır ise herkesten silinmesi gerekir.



İlk yaptığımda çalışmadı, çünkü multicast ile birlikte yapmıştım ama neden bunu sadece serverde replicate edip çalıştırabiliyoruz ? Destroy ve yer değiştirme şeyleri sadece server ile hallolabiliyor mu? Neyler sadece serverde replicate edilmeli neyler multicast kullanımı gerektirmelidir ?


Aşağıda sorunumu anlatan bir video hazırladım incelerseniz sevinirim ayrıca video sesli.

Bu içeriği görmek için üçüncü parti çerezlerine izin vermeniz gerekli.
Daha fazla detay için çerezler sayfasını ziyaret edin.
 
Biraz beynim yandı :)
    Öncelikle şu iki hususu belirtmem lazım. Birincisi sorun ne kadar komplex olursa olsun çözümü mümkün olan en basit şekilde kurmak zorundayız. Basitlik programlamada pozitif bir şey. Ne kadar basit o kadar iyi. İkincisi profesyoneller için, bu tarz şeylerde kaybettiğiniz vakide karşın en baştan C++ öğrenseydiniz, muhtemelen istediğiniz seviyeye çok çok daha erken varırdınız. Tabi profesyonel düşünenler için diyorum.
    Sen mantığı anladığım kadarı ile şöyle kurmuşsun: 
    Her objective harita üzerinde durduğu yerden oyuncu karaktere mesafesini ölçerek kendisini tabiri caizse "kurulu" ya da "kurulu olmayan" duruma getiriyor.    CanUse ile yapmak istediğin şey aslında bu. Bu işlemi objective içinde lokalde ve tick fonsiyonunda yapıyorsun. Oyunda bir server var bir de client var. Bu iki bilgisayarda, bütün objectiveler kurulu ya da kurulu olmama durumunu kendi tarafında lokal olarak belirliyorlar sürekli tickte. Yani client objective leri kendi durumunu sürekli kontrol ediyor ve saklıyor, server objectiveleri de ayrı bir bilgisayarda kendi durumlarını çek ediyor ve saklıyor. Bir kere bu objective aktörleri kendi aralarında bir veri akışına yani bilgi akışına sahip değiller. Serverdaki destroy olursa client taki de destroy olur sadece. Bunun haricinde şu an birbirlerinden hiç haberleri yok. Karakterinde ise tamamen bağımsız başka bir sistem var. Bir tuşa basıldığında server tarafında bir fonksiyon çalıştırıyorsun ve o an kurulu olan her objective üzerinde işlem yaptırıyorsun. Buna göre şimdi durumu inceleyelim.
   Client tayız. Karakterimiz objective e doğru yanaşıyor. Client tarafındaki tüm objectiveler kendi durumlarını, yanaşan bu karakterimize göre, mesafeye bağlı olarak kuruyorlar. Yani yeterince yanaşırsak kendisini benim deyimimle "kurulu" hale getirecekler. Bu sırada, karakter deki ayrı bir sistemde, oyuncu bir tuşa basarsa servera haber gidecek ve istenen fonksiyon çalışacak. Bu fonksiyon o an kurulu olan "KENDİ TARAFINDAKİ, SERVER DAKİ" kurulu olan tüm objectiveleri kullanmaya çalışacak. Ancak bir sorun var. Serverın objectiveleri kendi kurulu olma durumlarını kendi alanlarında ve kendi playercharacter lerine göre hesaplıyorlar. Dolayısı ile client ta kurulu olan objective ler server tarafında kurulu değiller o an. Onlar server ın player characterinin yanaşmasını bekliyorlar kendi durumlarını değiştirebilmek için. Server da oynayan "SimulateProxy" karakter onların umurlarında bile değil. 
   Fark ettiğim hatalar:
  1. Sistemi söylediğin gibi collision ile kurmamak. Ya da getoverlapping actors gibi bir fonksiyon kullanmamak.
  2. Tick te delay mantıklı değil. Eğer 0.2 sn de bir olmasını istiyorsan timer kurmalısın. Hem tick hem delay doğru bir hareket değil.
Ne yapmak lazım: 
 1.  O objective deki UI sistemi collision sistemi ile değiştirilerek kalabilir. UI yine collisin a göre gözükür. Tick teki okadar hesaptan kurtulmuş olursun. Bu UI olayını önceden yaptığın gibi yerel de ve lokal düşüne bilirsin.
 2. Karakterin bir tuşa bastığında server da bir fonksiyon çağırılsın. Serverdaki ve client taki karakterler aynı lokasyonda oldukları için server daki bu fonksiyonda GetOverlappingActors le ya da SphereOverlappingActors gibi bir fonksiyonla o an server ın yakınında olan objectivelere bir referans al ve ne yapıyorsan yap onunla. Sonra da destroy et. Bütün bu işlemler server da olduğu için client lara otomatik yansıyacaktır. Eğer objective de kullandığın collision shape ile yukarıda saydığım fonksiyonlar için collision radius aynı olursa aynı mesafede hiç sorun çıkmadan sistem işleyecektir.
 Bu sistem çok çok daha basit olacaktır.
 Tavsiye olarak: 
 Genel olarak (yeni başlıyorsan ) ne yapıyorsam "serverda" yapmalıyım psikolojisinde ol.

Bu arada ilk resim client ta çalışmaz çünki actorlerde Owner default olarak olmaz. RPC fonksiyonları multicast hariç çalışmaz. Owner olayını belirlemen gerekir. Yani replication ı kim yapacak diye belirlemek gerekir.
https://docs.unrealengine.com/4.26/en-US/InteractiveExperiences/Networking/Actors/OwningConnections/
 
Teşekkür ederim hepsini anladım uygulayacağım şimdi. Zahmet edip uzunca anlatmışsın.
Sanırım mesafe ölçmek ve overlapping olayları dışında LineTrace üzerinde çalışmamı istiyorsun. Çünkü linetrace serverde gayet net çalışan bir şey bunu zaten silaha aim yaparken kullanmıştım.
SphereTrace yollayıp actor referansı alsam her türlü işe yarar.
Widget göstergesi içinde Collision kullanırsam delaylara ticklere ve fazladan hesaplamaya gerek kalmaz böylece local şekilde hallederiz onuda performansa etkisi olur.
Tamam o zaman o şekilde deneyelim. Footstep olayınıda try get pawn owner şeklinde yapmaya çalışacağım.


Edit: Sistem düzgün şekilde çalışıyor. Daha az komplike daha iyi sistem oluştu. Aslında bir çok şeyi linetrace ile yapmak lazım çok rahat çalışıyor her türlü veriye ulaşabiliyor.
Widgetta çalıştı şimdi footstepe bakacağım.

Bu arada başkasına yazıyla anlatsan anlamazdı ha büyük ihtimalle ::DD yine gelip sorardı
 
Başkasının yaptığı şeyi anlamak kendin yapmaktan da zordur çoğu zaman. İnsanların önce senin yaptıklarını anlaması sonra gelip benim yazdıklarımı senin yaptıklarına göre anlaması gerekiyor. Çoğu kişi uğraşmayacaktır bile anlamaya. Ben de aklıma geldiği gibi kafasını gözünü yara yara yazıyorum tabi o da var. Türkçe katliamı falan yapıyorum. Dekoder lazım benim yazdıklarımı da anlamak için. :)