Unity - Singleton Pattern Kullanımı

Unity - Singleton Pattern Kullanımı

2023-01-17    

Unity’de singleton tasarım deseni kullanmanın tartışmalı bir konu olduğunu biliyorusunuzdur.

Singleton Pattern Kullanımı

Singloton tasarım deseninin yararlı olduğunu biliyor olsanız bile, oyununuz büyüdükçe yönetilmesi oldukça zorlaşacaktır. Bu yüzden kullanırken iki kere düşünmenizi tavsiye ediyorum.

Oyun projelerinde singleton tasarım desenini kullanmaktan mutlu olan bir çok Unity geliştiricisi var.

Yararlı mı yoksa zararlı mı? Tabi ki projeye göre değişir.

Genel olarak konuşursak, bir singleton tasarım desenini kullanımından doğabilecek sorunların çoğu, singleton'ın kendisinden değil, onları projenizde nasıl kullanmayı seçtiğinizden kaynaklanır.

Bunun nedeni, çoğu zaman bir singleton kullanmanın etkisinin ancak daha sonra, projeniz büyüdükçe veya siz bir şeyi değiştirmeye çalıştığınızda netleşmeye başlayabilmesidir.

Ne yazık ki bu bir singleton kullanmanın risklerinin belirsiz olabileceği anlamına gelir

Bu makalede, oyununuzu oluşturmayı kolaylaştırmak için singleton'ları kullanabileceğiniz farklı yollardan bazılarının yanı sıra bazı potansiyel riskleri göreceğiz, böylece oyunuzuda singleton'ları kullanıp kullanmama konusunda doğru kararı verebilirsiniz.

Unity’de Singleton Nedir?

Genel olarak Unity'deki bir singleton, sahnede yalnızca bir kez var olan, global olarak erişilebilir bir sınıftır.

Buradaki ana fikir, diğer herhangi bir betiğin singleton'a erişerek, nesneleri oyunun önemli bölümlerine, örneğin oyuncuya (player) veya diğer oyun sistemlerine (game objects) kolayca bağlamanıza izin vermesidir.

Örneğin, bir ses yöneticisi (Audio Manager) gibi ilgisiz nesneler ile komut dosyalarını global sistemlere bağlamak için yararlı olabilir.

Statik referans, bir singleton'ı küresel olarak erişilebilir kılan şeydir.

public class Singleton : MonoBehaviour 
{
    public static Singleton instance;
}

Bir değişkeni statik yapmak, sınıfın tüm örnekleri tarafından paylaşıldığı anlamına gelir; bu herhangi bir komut dosyasının tekil öğeye bir başvuruya ihtiyaç duymadan sınıf adı aracılığıyla erişebileceği anlamına gelir.

Bu değişkeni korumak genellikle iyi bir fikirdir, diğer script dosyaları tarafından okunabileceği fakat yalnızca kendi sınıfı içinden değiştirilebileceği anlamına gelir.

public class Singleton : MonoBehaviour 
{
    public static Singleton Instance { get; private set; }
}

Burada bir başka sorun daha görünür. Komut dosyasına yapılan başvuru statik olsa da, yani sınıfın tüm örneklerinde aynıdır, işaret ettiği örnek değildir.Yani referans, betiğin yalnızca bir örneğine işaret edebilirken, sahnede birden fazla singleton örneğine sahip olmak mümkündür.

Bu nedenle, statik referansın komut dosyası örneğiyle eşleşip eşleşmediğini kontrol ederek tekil öğenin yalnızca bir örneğinin olduğundan emin olmak önemlidir.

public class Singleton : MonoBehaviour 
{
    public static Singleton Instance { get; private set; }

    private void Awake() 
    { 
        // Bir örnek varsa ve ben değilse, yoket.
        
        if (Instance != null && Instance != this) 
        { 
            Destroy(this);
                    return;
        } 
        Instance = this;
            DontDestroyOnLoad(this.gameObject);
    }
}

Küresel olarak erişilebilir bir sınıf, ancak yalnızca bir örneği var. Bunlar, bir singleton için iki temel gereksinimdir.

public class GameManager: Singleton
{
		[SerializeField] private int score = 0;
        [SerializeFİeld] private int playerHealth = 100;
}

Neden Singleton Kullanılır?

Singletons, oyununuzun parçalarını daha kolay bir şekilde birbirine bağlamanıza izin verdiği için çok kullanışlı olabilir.

Örneğin, oyuncunun sağlığını kullanıcı arayüzüne ifşa etmek için bir singleton kullanabilirsiniz.

float healthBarValue = GameManager.Instance.playerHealth;

Veya oyundaki herhangi bir komut dosyasından tek bir ses efekti işlevini çağırabilirsini

GameManager.Instance.PlaySound(clipToPlay);

Bu, oyununuzun farklı bölümlerini birbirine bağlamayı çok daha kolay hale getirebilir.

Yine de… Singleton'ların kullanımı kolay olsa da sorunlara da neden olabilirler.

Neden Singleton Kötü Sonuçları Olabilir?

Genel olarak Singleton projeniz büyüdükçe yönetmek zorlaşır. Projenizi değiştirmeyi, genişletmeyi zorlaştırabilir ve test etmede sorunlara neden olabilirler.

Bir singleton kullanırken özellikle ne ters gidebilir?

Singleton'larla ilgili en büyük risklerden biri, doğası gereği küresel erişimdir.

Oyun Yöneticileri

Projenizde bir singleton kullanmanın ana faydalarından biri, oyun yöneticileri (game manager, audio manager, level manager vs) gibi önemli komut dosyalarını bunlara erişmesi gerekebilecek birçok farklı nesneyle sıkı bir şekilde bağlama ihtiyacından kaçınmaktır.

Örneğin Audi Manager;

Bir ses çalmak isteyen her bir nesneye Audi Manager komut dosyasına manuel olarak referans oluşturmaya çalışmak genellikle kötü bir tasarım olur.

Aynı şekilde, ihtiyaç duyabilecek her yeni nesne oluşturulduğunda sahnede ses yöneticisini bulmaya çalışmak performans için çok kötü olabilir.

Bu nedenle, bir ses yöneticisi singleton'u çok anlamlı olabilir.

Diyelim ki tam olarak bunu yaptınız, global erişime açık Play Sound Effect işlevine sahip bir Audio Manager singleton'u oluşturdunuz.

private AudioSource audioSource;

void Start()
{
	audioSource = new AudioSource();
}

public void PlaySound(AudioClip clip)
{
    audioSource.PlayOneShot(clip);
}

Basit ve kullanışlı…

Peki bu ne gibi sıkıntılara yol açabilir?

Oyununuz büyüdükçe oyununuza yeni sesler eklemeye başladığınızda, bazılarının diğerlerinden daha yüksek olduğunu, bazılarının ise tekrarlayıcı sesler çıkarmaya başladığını fark edebilirsiniz.

Tek başına bu sorunu düzeltmek kolaydır fakat bir çok farklı yerden çağrılan bu metod için yeniden düzenleme yapmak bazen çok can sıkıcı olur.

Singleton Kullanmanın Doğru Yolur Nedir?

Bir singleton kullanmanın tek bir doğru yolu olmasa da, kullanılmasından kaynaklanabilecek sorunlar genellikle projenize ve onunla ne yapmayı planladığınıza bağlıdır.

Bunun nedeni, bir singleton kullanmanın risklerinin, singleton'ın kendisi ile değil onu nasıl kullanmayı seçtiğinizle ilgili olmasıdır.

Örneğin; Bir dosya kaydetme sistemine küresel erişime izin verilmesi durumunda iki betik bilmeden aynı anda oyunu kaydetmeye çalışırsa sorunlara neden olabilir.

Yine de…

Singleton kullanmanın çok mantıklı olduğu zamanlar olabilir.