Unity: Sahneler Arası Veri Koruma ve Geçiş Yöneticisi
Unity ile oyun geliştirirken, farklı oyun durumları (menü, oyun içi, ayarlar) için ayrı sahneler kullanmak yaygın bir yaklaşımdır. Ancak sahneler arası geçiş yaparken veri bütünlüğünü korumak ve kullanıcıya akıcı bir deneyim sunmak bazen zorlayıcı olabilir. Bu makalede, Unity'nin DontDestroyOnLoad özelliğini ve bu özelliği kullanarak nasıl sağlam bir Scene Transition Manager (Sahne Geçiş Yöneticisi) oluşturacağımızı adım adım inceleyeceğiz. Bu sayede oyunlarınızda sahneler arası veri kaybını önleyecek ve geçişleri daha profesyonel hale getireceksiniz.
DontDestroyOnLoad Nedir ve Neden Önemlidir?
Unity'de bir sahne yüklendiğinde, önceki sahnedeki tüm GameObject'ler varsayılan olarak yok edilir. Bu durum, oyun yöneticisi, ses yöneticisi, oyuncu verileri veya kalıcı ayarlar gibi sahneler arası yaşaması gereken objeler için bir sorun teşkil eder. İşte tam bu noktada DontDestroyOnLoad devreye girer. Bu özel Unity fonksiyonu, bir GameObject'in yeni bir sahne yüklendiğinde yok edilmesini engeller.
Kullanım Alanları:
- Oyun Yöneticileri (Game Managers): Oyunun genel durumunu, puanını veya seviyesini takip eden objeler.
- Ses Yöneticileri (Audio Managers): Arka plan müziği veya efektlerin sahneler arası kesintisiz devam etmesini sağlayan objeler.
- Oyuncu Verileri: Oyuncunun envanteri, istatistikleri veya kaydedilmiş ilerlemesi gibi verileri tutan objeler.
- Ayarlar Yöneticileri: Dil, ses seviyesi, grafik kalitesi gibi kullanıcı tercihlerini saklayan objeler.
DontDestroyOnLoad Nasıl Kullanılır?
Kullanımı oldukça basittir. Bir GameObject'in yok edilmesini istemiyorsanız, o objeye bağlı bir script'in Awake() metodunda aşağıdaki kodu çağırmanız yeterlidir:
void Awake()
{
DontDestroyOnLoad(this.gameObject);
}
Bu kod parçacığı, script'in bağlı olduğu GameObject'i ve tüm çocuklarını, yeni sahne yüklendiğinde bile yok edilmemesi için işaretler. Ancak dikkat edilmesi gereken önemli bir nokta, bu objelerin kopyalarının oluşmasını engellemektir. Genellikle bu tür kalıcı objeler için Singleton tasarım deseni kullanılır.
Geleneksel Sahne Geçişlerinin Zorlukları
SceneManager.LoadScene() metodunu doğrudan kullanmak, basit geçişler için yeterli olabilir. Ancak:
- Veri Kaybı: Yukarıda bahsedildiği gibi, önceki sahnedeki veriler kaybolur.
- Kullanıcı Deneyimi: Büyük sahnelerin yüklenmesi sırasında oyun donabilir veya takılabilir, bu da kötü bir kullanıcı deneyimine yol açar.
- Karmaşıklık: Her geçişte manuel olarak veri aktarımı yapmak veya yükleme ekranı göstermek, kodun karmaşıklığını artırır.
Bu sorunları aşmak için merkezi bir Scene Transition Manager mimarisine ihtiyaç duyarız.
Scene Transition Manager Mimarisi
Bir Scene Transition Manager, sahneler arası geçişleri tek bir noktadan yöneten bir sistemdir. Bu sistem genellikle bir Singleton olarak uygulanır, böylece oyunun herhangi bir yerinden kolayca erişilebilir ve sadece bir örneği bulunur. Temel görevleri şunlardır:
- Sahne yükleme isteklerini almak.
- Asenkron (arka planda) sahne yüklemesi yapmak.
- Yükleme ekranları göstermek ve ilerlemeyi takip etmek.
- Gerekirse sahne geçiş animasyonlarını yönetmek.
Scene Transition Manager Yapımı: Adım Adım Rehber
Şimdi adım adım sağlam bir Scene Transition Manager oluşturalım.
Adım 1: Temel Sınıf Yapısı ve Singleton Uygulaması
Yeni bir C# script'i oluşturun (örneğin SceneTransitionManager.cs) ve aşağıdaki gibi temel singleton yapısını ekleyin:
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;
public class SceneTransitionManager : MonoBehaviour
{
public static SceneTransitionManager Instance { get; private set; }
void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
}
else
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
}
// Diğer metodlar buraya gelecek...
}
Bu kod parçası, SceneTransitionManager'ın tek bir örneğinin olmasını garanti eder. Eğer zaten bir örnek varsa, yeni oluşturulan objeyi yok ederiz. Aksi takdirde, bu objeyi Instance olarak atarız ve DontDestroyOnLoad ile sahneler arası korunmasını sağlarız.
Adım 2: Sahne Yükleme Metodları
Sahne yüklemesini asenkron olarak yapacak bir metod ekleyelim. Bu, büyük sahnelerin yüklenmesi sırasında oyunun donmasını engeller ve yükleme ekranı gösterme olanağı sunar.
public class SceneTransitionManager : MonoBehaviour
{
// ... (Awake metodu)
public void LoadScene(string sceneName)
{
StartCoroutine(LoadSceneAsync(sceneName));
}
private IEnumerator LoadSceneAsync(string sceneName)
{
// Yükleme ekranını burada etkinleştirebilirsiniz (sonraki adımlarda detaylıca ele alacağız)
Debug.Log($"Sahne yükleniyor: {sceneName}");
AsyncOperation operation = SceneManager.LoadSceneAsync(sceneName);
while (!operation.isDone)
{
float progress = Mathf.Clamp01(operation.progress / 0.9f);
// Yükleme ekranındaki ilerleme çubuğunu burada güncelleyebilirsiniz
Debug.Log($"Yükleme İlerlemesi: {progress * 100}% ");
yield return null;
}
Debug.Log($"Sahne yüklendi: {sceneName}");
// Yükleme ekranını burada devre dışı bırakabilirsiniz
}
}
LoadSceneAsync metodu, sahneyi arka planda yüklerken operation.progress değeri ile yükleme durumunu takip etmemizi sağlar. yield return null sayesinde Unity'nin her karede yükleme işlemini bir miktar ilerletmesine izin veririz.
Adım 3: Yükleme Ekranı Entegrasyonu (Opsiyonel ama Önemli)
Kullanıcı deneyimini artırmak için bir yükleme ekranı ekleyebiliriz. Bunun için basit bir UI Canvas'ı ve üzerinde bir metin veya ilerleme çubuğu objesi oluşturmanız gerekir. Bu objeleri SceneTransitionManager script'ine bağlayacağız.
using UnityEngine.UI;
public class SceneTransitionManager : MonoBehaviour
{
// ... (Instance ve Awake metodu)
[SerializeField] private GameObject loadingScreen;
[SerializeField] private Slider progressBar;
[SerializeField] private Text loadingText;
// ... (LoadScene metodu)
private IEnumerator LoadSceneAsync(string sceneName)
{
if (loadingScreen != null) loadingScreen.SetActive(true);
if (progressBar != null) progressBar.value = 0;
if (loadingText != null) loadingText.text = "Yükleniyor...";
AsyncOperation operation = SceneManager.LoadSceneAsync(sceneName);
operation.allowSceneActivation = false; // Sahne tamamen yüklenene kadar beklet
while (!operation.isDone)
{
float progress = Mathf.Clamp01(operation.progress / 0.9f);
if (progressBar != null) progressBar.value = progress;
if (loadingText != null) loadingText.text = $"Yükleniyor... {Mathf.Round(progress * 100)}%";
// Yükleme %90'a ulaştığında (yani sahne hazır olduğunda) bekleyebiliriz
if (operation.progress >= 0.9f)
{
// İsteğe bağlı: Burada bir animasyonun bitmesini bekleyebilir veya belirli bir süre sonra sahneyi etkinleştirebilirsiniz.
// Örneğin, 'devam etmek için tıklayın' gibi bir mesaj gösterebilirsiniz.
// Şimdilik, hemen etkinleştirelim:
operation.allowSceneActivation = true;
}
yield return null;
}
if (loadingScreen != null) loadingScreen.SetActive(false);
Debug.Log($"Sahne yüklendi: {sceneName}");
}
}
Bu kodda operation.allowSceneActivation = false; ile sahnenin %90 yüklendikten sonra otomatik olarak etkinleşmesini engelledik. Bu sayede, yükleme ekranında özel bir bitiş animasyonu veya 'Oyuna Başla' düğmesi gibi etkileşimler ekleyebilirsiniz. `%90` değeri, Unity'nin sahne verilerini yüklemeyi bitirdiği noktayı temsil eder; geri kalan `%10` ise sahneyi etkinleştirme ve objeleri başlatma işlemidir.
Adım 4: Gelişmiş Özellikler ve Performans İpuçları
- Sahne Geçiş Animasyonları: Yükleme ekranına ek olarak, sahneler arası yumuşak geçişler için UI animasyonları (fade-in/fade-out) entegre edebilirsiniz.
- Callback'ler: Sahne yüklemesi başlamadan önce veya bittikten sonra belirli kodları çalıştırmak için olaylar (Unity Events veya C# delegeleri) tanımlayabilirsiniz. Örneğin,
OnSceneLoadedveyaOnSceneStartedLoadinggibi. - Ön Yükleme (Preloading): Eğer bir sonraki sahnede kullanılacak büyük varlıklar (dokular, sesler) varsa, bunları asenkron olarak önceden yükleyerek geçiş süresini kısaltabilirsiniz.
Uygulama Örneği: Basit Bir Kullanım Senaryosu
Oyununuzun ana menüsünde bir 'Oyunu Başlat' düğmesi olduğunu varsayalım. Bu düğmeye tıklandığında oyun sahnesine geçiş yapmak için aşağıdaki gibi bir kod kullanabilirsiniz:
using UnityEngine;
using UnityEngine.UI;
public class MainMenu : MonoBehaviour
{
public Button startGameButton;
void Start()
{
startGameButton.onClick.AddListener(StartGame);
}
void StartGame()
{
if (SceneTransitionManager.Instance != null)
{
SceneTransitionManager.Instance.LoadScene("GameScene");
}
else
{
Debug.LogError("SceneTransitionManager bulunamadı!");
// Yedek olarak doğrudan sahne yükleme
// SceneManager.LoadScene("GameScene");
}
}
}
Bu örnekte, düğmeye tıklandığında SceneTransitionManager'ın LoadScene metodunu çağırarak 'GameScene' adlı sahneyi yüklüyoruz. Bu sayede tüm geçiş süreci merkezi olarak yönetiliyor.
Sıkça Yapılan Hatalar ve Çözümleri
-
Çift DontDestroyOnLoad Objeleri: Singleton deseni doğru uygulanmazsa, aynı
DontDestroyOnLoadobjesinden birden fazla kopya oluşabilir. Bu durum, özellikle sahneye doğrudan sürüklenen objelerde sıkça görülür. Singleton kontrolü (if (Instance != null && Instance != this) Destroy(gameObject);) bu sorunu çözer. -
Yükleme Ekranının Takılması: Yükleme ekranı objesi
DontDestroyOnLoadobjesinin bir çocuğu değilse veya doğru şekilde yönetilmezse, sahne geçişi sırasında yok olabilir. Yükleme ekranı UI'sını da SceneTransitionManager'ın kendisi gibi kalıcı yapmayı düşünün veya geçici bir sahne kullanın. -
Bellek Sızıntıları:
DontDestroyOnLoadobjeleri manuel olarak yok edilmediği sürece bellekten düşmez. Eğer bir objeye artık ihtiyacınız yoksa, onuDestroy()ile manuel olarak yok etmeyi unutmayın.
Sonuç
Unity'de DontDestroyOnLoad özelliğini ve bir Scene Transition Manager'ı doğru bir şekilde uygulamak, oyunlarınızın kalitesini ve kullanıcı deneyimini önemli ölçüde artırır. Bu yapıyı kullanarak sahneler arası veri bütünlüğünü koruyabilir, akıcı yükleme ekranları sunabilir ve oyununuzun genel mimarisini daha düzenli hale getirebilirsiniz. Unutmayın, iyi bir sahne geçiş sistemi, oyuncuların oyununuzla olan etkileşimini güçlendiren temel unsurlardan biridir. Bu rehberdeki adımları takip ederek kendi güçlü sahne geçiş sisteminizi kolayca oluşturabilirsiniz.
🧠 Ders Sonu Değerlendirme Testi
Dersi tamamladıktan sonra bilgilerinizi test edin ve ekstra puanlar kazanın.
Yorumlar (0)
İlk yorumu siz yapın!