Oyun dünyasının vazgeçilmez unsurlarından biri olan görev (quest) sistemleri, oyunculara hedefler sunarak onları hikaye boyunca yönlendirir ve oyun deneyimini zenginleştirir. Ancak karmaşık bir görev sistemini yönetmek, özellikle büyük ölçekli oyunlarda, zaman zaman zorlayıcı olabilir. Unity geliştiricileri için bu zorluğun üstesinden gelmenin şık ve etkili bir yolu: ScriptableObject tabanlı bir görev sistemi mimarisi oluşturmak. Bu makalede, ScriptableObject’lerin gücünü kullanarak nasıl modüler, esnek ve kolayca yönetilebilir bir görev sistemi kuracağımızı adım adım inceleyeceğiz.
ScriptableObject Nedir ve Neden Görev Sisteminde Kullanmalıyız?
Unity’deki ScriptableObject’ler, MonoBehaviour’lardan farklı olarak bir sahneye bağlı olmayan, veri depolamak için tasarlanmış özel bir varlık türüdür. Temel olarak, bir ScriptableObject bir C# sınıfının bir örneğidir ve proje varlığı olarak kaydedilebilir. Bu sayede, aynı veriyi birden fazla yerde kullanabilir, oyun objelerine bağlamak zorunda kalmadan bağımsız veri yapıları oluşturabiliriz. Görev sistemleri söz konusu olduğunda, ScriptableObject’ler bize şu avantajları sunar:
- Veri Odaklı Tasarım: Görevlerin tüm tanımını (başlık, açıklama, adımlar, ödüller) ScriptableObject’ler içinde tutarak, koddan veriyi ayırırız. Bu, görevlerin kolayca oluşturulmasını, düzenlenmesini ve genişletilmesini sağlar.
- Yeniden Kullanılabilirlik: Ortak görev adımları veya ödüller, farklı görevlerde yeniden kullanılabilir ScriptableObject’ler olarak tanımlanabilir.
- Modülerlik ve Esneklik: Her görev veya görev adımı bağımsız bir varlık olarak tasarlanabilir. Bu, yeni görev tipleri eklemeyi veya mevcutları değiştirmeyi çok daha kolay hale getirir.
- Tasarımcı Dostu İş Akışı: Oyun tasarımcıları, kod yazmaya gerek kalmadan Unity editörü üzerinden yeni görevler oluşturabilir ve mevcutları düzenleyebilir.
- Performans: MonoBehaviour’lar gibi sahnedeki her bir nesne için ek yük getirmezler.
Görev Sistemi Mimarisi Temelleri: Ana Bileşenler
Etkili bir ScriptableObject tabanlı görev sistemi, genellikle üç ana bileşen etrafında şekillenir:
QuestScriptableObject: Her bir görevin genel tanımını ve yapısını barındırır.QuestStep(veyaObjective) ScriptableObject’leri: Her görevin içindeki belirli adımları veya hedefleri tanımlar.QuestManager(MonoBehaviour): Oyun çalışma zamanında görevlerin durumunu yöneten, ilerlemeyi takip eden ve olayları tetikleyen merkezi bir bileşendir.
1. Quest ScriptableObject Yapısı
Ana Quest ScriptableObject’imiz, bir görevin tüm temel özelliklerini içerecektir. Bu, görevin kimliğini, adını, açıklamasını, kabul edilip edilemeyeceğini ve içerdiği görev adımlarını barındırır.
[CreateAssetMenu(fileName = "NewQuest", menuName = "Quest System/Quest")]
public class QuestSO : ScriptableObject
{
public string ID;
public string QuestName;
[TextArea] public string Description;
public List<QuestStepSO> QuestSteps; // Görev adımlarının listesi
public List<RewardSO> Rewards; // Görev tamamlandığında verilecek ödüller
public bool IsRepeatable;
public bool IsCompleted { get; private set; }
public void CompleteQuest() { IsCompleted = true; }
}
Yukarıdaki örnekte görüldüğü gibi, QuestSO sınıfı, bir görevin tüm meta verilerini tutar. QuestSteps ve Rewards listeleri de ScriptableObject referansları içerebilir, bu da esnekliği artırır.
2. Görev Adımları (Quest Steps) ve Hedefler
Bir görev genellikle birden fazla adımdan oluşur. Bu adımların her biri de kendi içinde bir ScriptableObject olarak tanımlanabilir. Bu sayede, farklı türdeki görev adımlarını (örneğin, bir nesne toplama, düşman öldürme, belirli bir yere gitme) kolayca tanımlayabiliriz.
public abstract class QuestStepSO : ScriptableObject
{
public string StepDescription;
public bool IsStepCompleted { get; protected set; }
public abstract void InitializeStep();
public abstract void CheckProgress();
}
[CreateAssetMenu(fileName = "NewCollectItemStep", menuName = "Quest System/Quest Step/Collect Item")]
public class CollectItemQuestStepSO : QuestStepSO
{
public ItemData TargetItem;
public int RequiredAmount;
private int currentAmount;
public override void InitializeStep()
{
currentAmount = 0;
IsStepCompleted = false;
// Gerekli eventlere abone olma (örneğin ItemManager.OnItemCollected)
}
public override void CheckProgress()
{
// currentAmount'ı kontrol et ve IsStepCompleted'ı güncelle
if (currentAmount >= RequiredAmount)
{
IsStepCompleted = true;
}
}
}
QuestStepSO soyut sınıfı, tüm görev adımları için ortak bir arayüz sağlar. CollectItemQuestStepSO ise belirli bir görev adımı türünü temsil eder. Bu yapı, gelecekte yeni görev adımı türleri (KillEnemyQuestStepSO, GoToLocationQuestStepSO vb.) eklemeyi son derece kolaylaştırır.
3. QuestManager ile Çalışma Zamanı Yönetimi
QuestManager, oyun çalışma zamanında görevlerin durumunu takip eden, oyuncu girdilerine veya oyun olaylarına yanıt veren merkezi bir MonoBehaviour’dur. Bu sınıf, oyuncunun aktif görevlerini tutar, görev adımlarının ilerlemesini günceller ve görevler tamamlandığında ödülleri dağıtır.
- Aktif Görevler Listesi: Oyuncunun o anda kabul ettiği ve üzerinde çalıştığı görevleri tutar.
- Olay Yönetimi: Görev adımlarının ilerlemesini tetiklemek için oyun içi olaylara (örneğin, bir düşman öldürüldüğünde, bir nesne toplandığında) abone olur.
- Görev İlerlemesi: Her görev adımının tamamlanıp tamamlanmadığını kontrol eder ve bir adım tamamlandığında bir sonraki adımı etkinleştirir.
- Ödül Dağıtımı: Bir görev tamamen tamamlandığında, tanımlanmış ödülleri oyuncuya verir.
QuestManager, görev ScriptableObject’lerini doğrudan düzenlemez; bunun yerine, onların durumunu (IsCompleted, IsStepCompleted gibi) güncelleyen metotlarını çağırır veya harici bir veri saklama mekanizması (örneğin, kaydetme sistemi) ile entegre olur.
Avantajlar ve En İyi Pratikler
- Ayırma (Decoupling): Kod ve veri arasındaki ayrım, sistemin daha sağlam ve hata ayıklaması daha kolay olmasını sağlar. Görev verilerini değiştirmek, kodu yeniden derlemeyi gerektirmez.
- Genişletilebilirlik: Yeni görev adımı türleri veya ödül tipleri eklemek, mevcut sistemi bozmadan yeni ScriptableObject sınıfları oluşturmak kadar basittir.
- Editör Entegrasyonu: Unity’nin
CreateAssetMenuniteliği sayesinde, tasarımcılar kod yazmadan görevleri ve adımları oluşturabilir, bu da iterasyon hızını artırır. - Veri Doğrulaması: Custom Editor’lar yazarak ScriptableObject’ler üzerindeki verilerin doğruluğunu kontrol edebilir ve tasarımcıların hata yapmasını engelleyebilirsiniz.
- Kaydetme/Yükleme: Görev sisteminin durumunu kaydetmek ve yüklemek, ScriptableObject’lerin referanslarını ve ilgili durum değişkenlerini (örneğin, hangi adımların tamamlandığı) kaydetmekle basitleşir.
Sonuç
Unity’de ScriptableObject’ler kullanarak bir görev sistemi mimarisi oluşturmak, oyun geliştirme sürecinizi büyük ölçüde kolaylaştırabilir. Bu yaklaşım, görev verilerini koddan ayırarak daha esnek, modüler ve tasarımcı dostu bir yapı sunar. Yeniden kullanılabilirlik, kolay genişletilebilirlik ve performans avantajlarıyla, ScriptableObject tabanlı görev sistemleri, modern oyun geliştirmede güçlü bir araçtır. Bu mimariyi benimseyerek, oyuncularınıza zengin ve dinamik görevler sunarken, kendi geliştirme sürecinizi de optimize edebilirsiniz.



