Cnrtnbl

Unreal MVP
24 Kas 2020
216
162
43
36
(35) İzmir
Herkese iyi günler. Bugün projemde save ve load game mekaniklerini bitirdim. Yeni şeyler ekledikçe sistemi genişletiyordum. Son olarak AI karakterleri eklemiştim ve onlar için de bitirdim. Konuyu açmamdaki sebep özellikle yeni ve orta derecede bilgili olanlar ve strateji oyunu yapmak isteyenlerin daha en baştan dikkate alması gereken bir şey; oyunu kaydedip kaldığı yerden devam edebilmek.

Henüz daha bunu düşünmeyenler için söyleyeyim. Oyunu öylece kaydetme gibi bir mekanik yok. Oyunlar oyun klasöründe bir dosya içinde kaydedilir ve bu dosyaya Unreal'in temel değişkenlerinden başka bir şey kaydedemezsiniz. Sadece integer, bool, vector, float, actor class, transform gibi en temel değişkenleri hafızaya alır. Yani projede yarattığın bir obje blueprintini referans alıp değişken olarak kaydedemezsin. Sadece class ını alıp kaydedebilirsiniz. Onu da yükle diyemezsiniz çünkü fiziksel bir obje değil. Adım adım oyun nasıl kaydedilir ve yüklenir onu anlatmayacağım youtube'ta videoları vardır. Ben strateji oyunu yaparken gidebileceğiniz yolu söyleyeceğim. 

Peki oyunlarda kaydedip sonradan devam etme nasıl oluyor? Olay şu: Load game dediğinizde aslında o level New game gibi sıfırdan açılıyor. Sonrasında load game from slot komutu ile kaydedilmiş bilgileri çağırıp oyunda tek tek ne değişiklik yapılması gerekiyorsa yapıyorsunuz. Yani karakterin canını, olduğu konumu, elindeki silahın mermi sayısını, elindeki silahın cinsini vb. yeniden atayarak öyle başlıyorsunuz. 

Silahlı ve hikayeli oyunlarda bu nispeten kolay çünkü az değişken var. Ama iş strateji oyununa geldiğinde oyunda yüzlerce aktör olabiliyor. Her birinin pek çok değişkeni olabiliyor. Ve oyun yüklendiği zaman her şeyin tam olarak nasıl bırakıldıysa aynen o şekilde devam etmesi gerekiyor. Bug'a girmiş bir karakter oyun boyu ortada öylece kalabilir mesela.

Gözünüz korkmadı mı? Peki AI Behaviour u nasıl kaydedeceksin? Ve kaldığı durumdan nasıl devam ettireceksin? Kökten başlıyor tekrardan ve oyunda kaydetmeden önce yukarı doğru bir eve giderken oyunu yükledikten sonra başka bir kararla başka eve yönelebilir? Peki diyelim ki ev blueprint'inde yaşayan kişilerin referanslarını tutuyorsun. Bu evde ahmet mehmet yaşıyor diye. İsimlerine tıklayınca da o kişi köyde neredeyse oraya gidiyor kamera diyelim. Şimdi oyun oynanırken bu kişi bu eve taşındığında referansını eve atayabilirsin. Ama kayıtlı oyunu yüklediğinde bu referansları atayamayacaksın. Teknik olarak evlerde hiç yaşayan olmayacak.

Bu iki durum save ve load sistemindeki en can sıkıcı durumdur. Gidilebilecek yol ise fazla basit bir yol. Farklı farklı yollar vardır ama ben şu sistemi kullandım:

1-)Yükleme sonrası referansları tekrar atayabilmek için her aktöre doğduğunda bir integer ActorID atıyorum. 0 dan başlayıp 1 artarak devam ediyor sıradaki doğan aktörün ID'si. HasActorID diye bir Interface ekliyorum ID olması gereken aktörlere ki cast yapmadan her aktörden ID'lerini alabileyim. Oyunu kaydederken de referanslarının IDlerini alıp kaydediyorum. 

Örneğin bir gemimiz var ve bu gemi limana spline yolu kullanarak ilerliyor. Bu Spline aktörünün referansı var. Oyunu kaydederken referansı kaydedemediğimiz için onun yerine aktör ID'sini kaydediyoruz. Diyelim ki oyunu yükledik spline spawn oldu ve gemi bir limana yanaşmaya devam edecek. Spline için hafızaya aldığım nokta sayısını ve posizyonlarını atadım. Yine kaydettiğim bu aktöre ait ActorID'yi atadım. Oyunda spawn edilmesi gereken her şeyi spawn ettim. Tüm spawn edilip atanması gereken değerler atandıktan sonra Game Instance üzerinde oluşturduğum event dispatcher'i çağırıyorum. Bu dispatcher'i dinleyen ve referansları olan her aktör referans alma fonksinyonunu çağırıyor. O da bu gemi için şudur: Get all actors of class(MySplineBP). Bu bize Tüm Spline aktörlerini getirecek. Gelen array için for each loop with break diyerek bu spline ların aktör ID'lerini çağırıp kaydettiğimiz spline ID'sine eşit mi karşılaştırıyoruz. Eşit olanı bulunca bunu referans alıp break diyoruz ve gemimiz referansını almış oldu. Kaldığı yerden devam edebilir.

Bir yola bağlı bir bina için de aynı sistem. Bir binaya giderken target actor arayan bir AI için de aynı sistem.

2-)AI Behaviour tree için de kayıt etme olayı basit. Blackboarddaki tüm değişkenleri normal kaydediyoruz. Object referansları kaydedemeyeceğimiz için onların ActorID'sini alıp kaydeyoruz yine. Kaydetme olarak da her ne iş yapıyorsa kaydederken o görevi text, name ya da integer olarak size kolay ve anlaşılır gelecek şekilde kaydedin. Ayrıca Behaviour tree de kökten sonra gelen ilk şeye gate olarak bool kullanıyoruz mesela gameloaded isminde. Her işlemden önce game loaded'e bakıyor. Yani oyun yüklenmiş mi?. Eğer doğru ise kaydetmiş olduğunuz en son ne iş yapıyorsa ona yönlendiriyorsunuz. Tabi bunu yapmadan önce yine referansları almanız gerekiyor. Bu göreve yönlendirdikten sonra game loaded false diyorsuz ve o görev bittikten sonra doğal haline dönmüş oluyor.

Yükleme sırası şu şekilde yani: Aktörleri spawn et->Değişkenlerini ata->Referanslarını aldır->AI Behaviour Tree yi yükle.

Biraz gözünüz korktuysa o kadar korkutucu değil. Biraz amelelik ama bir mekanik geliştirmeye çalışırken karşılaşacağınız buglar gibi zorlayıcı buglar çıkarmıyor. Projemdeki kaydetme yükleme nodelarının resmini yüklüyorum biraz gözünüz bulansın diye ::D Düşünün bu kadar node her bir aktör için çağırılıyor. Bine yakın belki geçkin bir miktarda node işleniyor olabilir. Geçen gün performansına baktığımda tüm level'in yüklenmesi sırasında bu node'lar toplamda 0.01ms 'de işlenmiş beklentimin üzerinde. Ama sahnede yüzlerce aktör daha eklendiğinde ne olur bilemiyorum. Ayrıca bu iki resim sadece kaydetme yükleme. Referans alma arrayleri de var. Ama bu kadar kaydedip yükleme sistemini 2-3 günde yapabilirsiniz. Benim herhalde parça parça toplamda 2-3 günümü almıştır maksimum

 
 
Kolay gelsin kardeş.
"Save Load Income Recors" ta neden o kadar çok Float var.?
Structure kullanıyormusun?

Structure set etsen daha iyi olur.

Bende zamanında böyle yapmıştım.
Şimdi Structure ve arraylar kullanıyorum.
Tekli solo Değişken(Variable) belirli bir sayıdan sonra kasmaya başlıyor.
 
jetboy_hrn1990' Alıntı:
Kolay gelsin kardeş.
"Save Load Income Recors" ta neden o kadar çok Float var.?
Structure kullanıyormusun?

Structure set etsen daha iyi olur.

Bende zamanında böyle yapmıştım.
Şimdi Structure ve arraylar kullanıyorum.
Tekli solo Değişken(Variable) belirli bir sayıdan sonra kasmaya başlıyor.


Struclarla kötü anılarım var diyelim  :s Birkaç kere yeni bir değişken eklediğimde komple proje çökmüştü hiç açılmıyordu direk crash yiyordun. Proje dosyalarından struct u silip baştan yapmam gerekti o structu baya uğraştırdı. O günden beri yeni değişken eklemeyeceğime inandığım şeyleri struct yapıyorum