Blog'a dön
•
ByteGurus

Unity ile Oyun Geliştirmede İyi Uygulamalar

Unity ile oyun geliştirmede mimari, nesne havuzu, profil çıkarma, proje düzeni, sürüm kontrolü, test ve mobil optimizasyon için pratik öneriler.

Unity Oyun Geliştirme C# Mobil

Yayınlanan ve güncellenmeye devam eden oyunlar sağlam bir mimariye ve disiplinli bir geliştirme pratiğine dayanır. Unity hızlı başlamayı kolaylaştırır; aynı kolaylık, proje büyüdükçe dağınık sahnelere, yavaşlayan kare hızına ve çözülemeyen birleştirme çakışmalarına dönüşebilir. Bu yazı bunu önleyen uygulamaları sıralıyor.

Mimari

Oyun mantığını sunumdan ayırın

Oyun kurallarını (can, puan, envanter) ekranda gösterilmelerinden ayırmak, tasarımcının arayüzü oyun koduna dokunmadan değiştirmesini ve kuralların test edilebilmesini sağlar. MVC, MVP ya da olay tabanlı bir yaklaşım seçebilirsiniz; önemli olan bir MonoBehaviour’ın hem kuralı hem görüntüyü yönetmemesidir.

Bileşen tabanlı yapı

Unity bileşen tabanlıdır: büyük, her şeyi yapan sınıflar yerine tek işi yapan küçük bileşenler yazın.

using UnityEngine;

public class Health : MonoBehaviour
{
    [SerializeField] private int maxHealth = 100;
    public int Current { get; private set; }
    public event System.Action<int> Changed;
    public event System.Action Died;

    private void Awake() => Current = maxHealth;

    public void TakeDamage(int amount)
    {
        if (Current <= 0) return;
        Current = Mathf.Max(0, Current - amount);
        Changed?.Invoke(Current);
        if (Current == 0) Died?.Invoke();
    }
}

Can çubuğu Changed olayını dinler, ölüm animasyonu Died olayını; Health ikisini de bilmez. Ayarları kodda değil, ScriptableObject varlıklarında tutmak da dengeyi tasarımcının elinde bırakır.

Performans

Nesne havuzu

Mermi, efekt gibi sık oluşturulup yok edilen nesneler çöp toplayıcıyı (GC) yorar ve kare atlamalarına yol açar. Unity’nin yerleşik ObjectPool<T> sınıfı bunun için hazırdır:

using UnityEngine;
using UnityEngine.Pool;

public class BulletSpawner : MonoBehaviour
{
    [SerializeField] private Bullet prefab;
    private ObjectPool<Bullet> pool;

    private void Awake()
    {
        pool = new ObjectPool<Bullet>(
            createFunc: () => Instantiate(prefab),
            actionOnGet: b => b.gameObject.SetActive(true),
            actionOnRelease: b => b.gameObject.SetActive(false),
            defaultCapacity: 32);
    }

    public void Fire(Vector3 position, Quaternion rotation)
    {
        var bullet = pool.Get();
        bullet.transform.SetPositionAndRotation(position, rotation);
        bullet.Init(release: () => pool.Release(bullet));
    }
}

Her karede iş yapmayın

Update içinde GetComponent, Find ya da yeni nesne oluşturmak her karede bedel öder. Referansları Awake içinde önbelleğe alın; zamanlı işleri her karede değil, gerektiğinde çalıştırın. Bekleme gerektiren akışlarda eşyordamlar (coroutine) ya da Awaitable kullanılabilir; bekleme nesnelerini (WaitForSeconds) her döngüde yeniden oluşturmak yerine bir kez oluşturup yeniden kullanın.

Önce ölçün

Tahmine göre optimizasyon zaman kaybıdır. Unity Profiler ve Frame Debugger ile darboğazı bulun ve ölçümü hedef cihazda yapın: editördeki performans, düşük donanımlı bir telefondakinin göstergesi değildir. İşlemci mi, grafik işlemci mi, bellek mi; önce hangisinin sınır olduğunu belirleyin.

Proje düzeni

Klasör yapısı

Assets/
├── _Project/
│   ├── Scripts/
│   │   ├── Gameplay/
│   │   ├── UI/
│   │   └── Systems/
│   ├── Prefabs/
│   ├── Scenes/
│   ├── Art/
│   └── Audio/
└── ThirdParty/

Kendi varlıklarınızı üçüncü taraf paketlerden ayırmak, güncellemeleri ve temizliği kolaylaştırır. Kodu Assembly Definition dosyalarıyla bölmek derleme süresini kısaltır.

Sürüm kontrolü

  • Unity’nin önerdiği .gitignore ile Library/, Temp/ ve derleme çıktılarını dışarıda tutun
  • Editörde “Visible Meta Files” ve “Force Text” serileştirmesini açın
  • Büyük ikili dosyalar (doku, ses, model) için Git LFS kullanın
  • Sahne çakışmalarını azaltmak için sahneleri küçük parçalara ve prefab’lara bölün

Kod kalitesi

Adlandırma: C# kurallarını izleyin; sınıf ve yöntemler PascalCase, alanlar camelCase. Inspector’da görünmesi gereken özel alanlar public değil [SerializeField] private olmalı.

Belgeleme: açık olmayan kararların nedenini kodun yanında yazın.

Test: Unity Test Framework ile kuralları Edit Mode testleriyle, sahne davranışlarını Play Mode testleriyle doğrulayın. Kuralı MonoBehaviour’dan bağımsız düz bir C# sınıfına koymak testi kolaylaştırır; Edit Mode’da bileşenlerin Awake yöntemi çağrılmaz:

using NUnit.Framework;

public class HealthModel
{
    public int Current { get; private set; }
    public HealthModel(int max) => Current = max;
    public void TakeDamage(int amount) => Current = System.Math.Max(0, Current - amount);
}

public class HealthTests
{
    [Test]
    public void Health_never_goes_below_zero()
    {
        var health = new HealthModel(100);
        health.TakeDamage(500);
        Assert.AreEqual(0, health.Current);
    }
}

Mobil oyunlar

  • Hedef kare hızını cihaz sınıfına göre belirleyin; pil ve ısınma da birer kısıttır
  • Doku sıkıştırma ve atlas kullanın, çizim çağrılarını (draw call) azaltın
  • Bellek bütçesi koyun; düşük bellekli cihazlarda uygulama işletim sistemi tarafından kapatılabilir
  • Adresable varlıklarla ilk indirme boyutunu küçük tutun
  • Gerçek cihazlarda, en düşük desteklenen modelde test edin

Sonuç

Unity’de başarılı bir proje; ayrık sorumluluklar, ölçümle yapılan optimizasyon, düzenli bir proje yapısı ve testle ayakta durur. Bu alışkanlıklar baştan kurulduğunda ekip büyüse de proje yönetilebilir kalır.

Oyun projeniz için teknik değerlendirme isterseniz bize yazın.

B

ByteGurus

Yazar

Tüm yazılara dön
Başlamaya hazır mısınız?

Projenize başlamaya hazır mısınız?

Fikirlerinizi hayata geçirmek için size nasıl yardımcı olabileceğimizi konuşalım.