Kayıt Sistemi (Bölüm 2)
Birinci dersi okuduğunuzu ve temelleri bildiğinizi varsayıyorum. Bu bölümde biraz daha kolay kullanılabilir bir sistem yazacağız.
Önceki derste anlattığım sitemin eskilerinden de bahsetmiştim; her değişkeni string’e çevirmeniz gerekiyordu. Yüklerken de string’i çözümlemeniz ve her değişkeni elle tek tek atamanız gerekiyor. Bu uzun, zahmetli ve hata yapması kolay bir yöntem. Onun yerine verileri tutan tek bir sınıfımız olsa, tek satır kod ile kaydedip yükleyebilsek güzel olmaz mıydı? Olurdu tabii! E yapalım o zaman, tutan yok.
Öncelikle PlayerData.cs diye yeni bir betik (script) yaratalım ve içine playerName’i ve playerHealth’i yapıştıralım:
public class PlayerData { public string playerName; public float playerHealth; }
Şimdi de bir Player sınıfı yaratıp içinde bu veri tipini kullanalım (eğer önceki dersi bitirdiyseniz oradaki Player sınıfını değiştirebilirsiniz).
using UnityEngine; public class Player : MonoBehaviour { public PlayerData playerData; private void Start() { // Load the data when the game starts LoadData(); } private void OnDisable() { // Save the data when the game stops SaveData(); } private void SaveData() { // Save the data } private void LoadData() { // Load the data } }
Güzel hoş ama şimdi Unity’de inspector’a bakarsanız orada playerData’yı göremeyeceksiniz. Ama sakin olun, korkulacak bir şey yok. PlayerData’nın başına [System.Serializable] yazarsanız problem çözülecektir.
[System.Serializable] public class PlayerData { public string playerName; public float playerHealth; }
Şimdi inspector’e bakarsanız ilgili alanı göreceksiniz.
Bu noktada önceki derste yaptığımız sitemi bire bir kullanabilirsiniz. Tek yapmanız gereken şey playerHealth yerine playerData.playerHealt, ve playerName yerine playerData.playerName yazmanız. Ancak tahmin edebileceğiniz gibi bu asıl problemimizi çözmeyecek. Hala her bir değişkeni tek tek elle yüklememiz gerekiyor. Sistemin kalanını yazmadan önce JavaScript Object Notation diye bir şeyi öğrenmemiz lazım.
JSON
İsmi görüp hemen kaçmayın! Burada korkulacak bir şey yok. JavaScript Object Notation ya da kısaca JSON bir dil değil. Verileri yedekleyip aktarmak için kullanılan basit bir format. JSON dosyalarını herhangi bir editör ile açıp değiştirebilirsiniz. Bir JSON dosyası aşağı yukarı şöyle görünür:
{}
Evet, yanlış okumadınız. Bir JSON dosyasında olması zorunlu tek şey şekilli parantezler. Kaydetmek istediğimiz değişkenleri ise “değişkenAdı” : değer şeklinde yazıyor ve virgül ile ayırıyoruz:
{ "playerName": "Anton", "playerHealth": 32.0, "levelNumber": 3, "hasWeapon": false, "inventory": [ "item1", "item2", "item3" ] }
Gördüğünüz gibi bu şekilde string, int, float, bool ve listeleri kaydedebiliyoruz. Ayrıca farklı objeleri de kaydedebiliriz ama o konuya en son değineceğim.
XML ve YAML’ın başı kel mi?
JSON benzeri birçok farklı dil ve format bulabilirsiniz. Mesela Extensible Markup Language ya da kısaca XML ve Yet Another Markup Language (diğer adı ile YAML Ain’t Markup Language) ya da kısaca YAML en çok kullanılan alternatifler. İki dil de veri saklamak için kullanılabilir. Ancak JSON’ın Unity ile çok güzel bir entegrasyonu var ve kendisi oldukça hafif bir dil. O nedenle genelde JSON’ı tercih ediyorum.
Kaydeteme ve yükleme
JSON kullanmanın en güzel tarafı bir objeyi string’e çevirmek bir satır koda bakıyor:
private void SaveData() { string savePath = $"{Application.persistentDataPath}/Save.json"; string data = JsonUtility.ToJson(playerData); System.IO.File.WriteAllText(savePath, data); }
Gördüğünüz gibi verilerimizden bir string elde etmek artık çok kolay. Peki yükleme işini nasıl yapıyoruz?
private void LoadData() { string savePath = $"{Application.persistentDataPath}/Save.json"; // Json dosyasını oku string data = System.IO.File.ReadAllText(savePath); // Okuduğumuz string'i PlayerData'ya çevir playerData = JsonUtility.FromJson<PlayerData>(data); }
Bu kadar! Başka bir değişken kaydetmek için PlayerData sınıfına eklemeniz yeterli. Kayıt dosyanızı Unity’yi veya oyunu açmadan değiştirmek isterseniz de Notepad dahil herhangi bir metin editörü işinizi görecektir.
İpuçları ve potansiyel sıkıntılar
Format sıkıntıları
Eğer yukarıdaki kodu bire bir yazdıysanız JSON dosyanız şuna benzemiştir:
{"playerName":"Anton","playerHealth":32.0}
Bütün veriler tek bir satıra yazılmış. Bunun basit bir sebebi var: bir metin dosyasında yeni satıra geçmek için arka planda bir karakter kullanılır (Windows’ta genelde bu karakter \n diye gösterilir). Dosyaya fazladan karakter eklemek tahmin edebileceğiniz gibi o dosyayı daha büyük yapar. Tabii ki bir kayıt dosyası için bir problem oluşturmaz. Ancak JSON’ın çevrim içi uygulamalarda ve internet sitelerinde sık sık kullanıldığını hatırlayalım. O durumlarda gereksiz veri gödermek ısraftan başka bir şey değil. O yüzden varsayılan olarak yeni satır karakterleri görmezden gelinir.
Eğer JSON destekleyen bir IDE ya da editör kullanıyorsanız bir iki tuş ile dosyayı otomatik olarak formatlayabilirsiniz. Ancak direkt olarak düzgün bir şekilde formatlanmış hali ile kaydetmek zor bir iş değil. Tek yapmanız gereken şey ToJson() metoduna ekstra bir argüman eklemek:
string data = JsonUtility.ToJson(playerData, true);
Metodda gördüğünüz ikinci argüman sayesinde düzgünce formatlanmış bir JSON dosyası elde edeceksiniz.
Objeleri kaydetmek
Yukarıda JSON’a objeleri kaydedebileceğinizden bahsetmiştim. Obje derken PlayerData gibi sınıfları ve diğer veri yapılarını kastediyorum. Örneğin oyunumuza bir yoldaş ekleyelim. Sınıfın adı Companion olsun:
[System.Serializable] public class Companion { public string name; public int age; }
Bu sınıfı PlayerData’ya ekleyelim.
[System.Serializable] public class PlayerData { public string playerName; public float playerHealth; public Companion companion; }
Şimdi oyunu başlatalım, companion’ın değerlerini ayarlayıp durduralım. Companion Unity editöründe şöyle görünecektir:
JSON’ımız şu hale geldi:
{ "playerName": "Anton", "playerHealth": 32.0, "companion": { "name": "CoolGuy", "age": 25 } }
Gördüğünüz gibi companion değişkeninin değeri kendi başına bir JSON dosyası gibi görünüyor.
Döngüsel referans yok!
Diyelim ki yoldaşımız başka bir oyuncunun verisini tutmak istiyor:
[System.Serializable] public class Companion { public string name; public int age; public PlayerData anotherPlayerData; }
Bu bir soruna yol açacak. PlayerData bir Companion verisi tutuyor, Companion verisi de PlayerData. Bu şekilde birbirlerine referans vererek sonsuza kadar gidebilirler. JSON bir kenara, Unity’nin bile hoşuna giden bir durum değil. Unity’yi açtığınız anda şu uyarıyı alacaksınız:
Serialization depth limit 10 exceeded at 'Companion.anotherPlayerData'. There may be an object composition cycle in one or more of your serialized classes.
Ve tabii ki companion’ın tuttuğu PlayerData verisi JSON’a dahil olmayacak. Böyle bir durumun etrafından dolaşmanın yolları var ama imanınız varsa kaçınmaya çalışın. İlla böyle olması gerekiyorsa Newtonsoft’un Unity için Json paketini kullanabilirsiniz. Unity’nin JsonUtility’sinden çok daha gelişmiş bir araç kendisi.
Private değişkenleri kaydetmek
Şu ana kadar hep public değişkenler kullandım. Ancak ciddi bir projede bu böyle olmayacaktır. Eğer private bir değişkeni JSON’a kaydetmek ya da inspector’da görüp değiştirmek isterseniz önüne [SerializeField] yazmanız yeterli olacaktır.
[System.Serializable] public class PlayerData { public string playerName; public float playerHealth; [SerializeField] private int _moneyInTheBank; public Companion companion; }
JSON kullanmaya başlamak için bilmeniz gerekenler bu kadar. Konu hakkında bir sorunuz veya bir ders isteğiniz olursa haber vermekten çekinmeyin!
Filed under: Programlama,Unity - @ August 13, 2022 8:37 pm
Tags: Unity, Programlama, Kayıt Sistemi