Unity Eğitim
Dersler
Forum Sınav Merkezi Premium 💎
Başlangıç Seviyesi

Unity'de Basit Bir Memory Match Oyunu Nasıl Yapılır?

Paylaşan: Unity Eğitim 30 October 2025 9 dakika okuma 174 görüntülenme

Giriş: Hafızanızı Test Edin!

Unity Memory Match oyunları, hem eğlenceli hem de eğitici olmalarıyla bilinir. Oyuncuların hafızasını ve dikkatini test eden bu basit ama sürükleyici oyunlar, Unity ile oyun geliştirmeye yeni başlayanlar için harika bir başlangıç projesidir. Bu makalede, Unity ve C# kullanarak sıfırdan basit bir kart eşleştirme (Memory Match) oyunu nasıl geliştireceğinizi adım adım öğreneceksiniz. Kartların oluşturulmasından eşleştirme mantığına, UI entegrasyonundan yaygın hataların çözümüne kadar geniş bir yelpazeyi kapsayacağız.

Hedefimiz, temel bir Unity Memory Match oyununun tüm bileşenlerini anlamak ve kendi projelerinizde uygulayabileceğiniz sağlam bir temel oluşturmaktır. Hazırsanız, Unity editörünü açıp kodlamaya başlayalım!

Temel Oyun Mekaniği ve Unity Hazırlığı

Bir Memory Match oyununun ana mekaniği oldukça basittir: kapalı kartlar arasından iki tanesini açın, eğer eşleşirlerse oyundan kalkarlar veya açık kalırlar, eşleşmezlerse tekrar kapanırlar. Oyun, tüm kartlar eşleşene kadar devam eder.

Unity Proje Kurulumu

  1. Yeni bir 2D Unity projesi oluşturun.
  2. Oyun kartları için kullanacağınız `Sprite`'ları (resimleri) projeye aktarın. Her kart çifti için aynı `Sprite`'tan iki tane olacak şekilde ayarlayın. Bir de kartların arka yüzü için bir `Sprite`'a ihtiyacınız olacak.
  3. Bir `Canvas` oluşturun (`GameObject > UI > Canvas`) ve `Render Mode`'unu `Screen Space - Camera` olarak ayarlayın.
  4. `Canvas` altına bir `GridLayoutGroup` bileşeni içeren boş bir `GameObject` oluşturun. Bu, kartların düzenli bir şekilde yerleşmesini sağlayacak.

Kart Prefab'ı Oluşturma

Her bir kartımız için bir `Prefab` oluşturacağız. Bu, kartları dinamik olarak üretmemizi sağlayacak.

  1. `Canvas` altına bir `Button` (`GameObject > UI > Button`) oluşturun. Bu, kartımızın temelini oluşturacak.
  2. `Button`'ın `Image` bileşeninin `Sprite`'ını kartın arka yüzü `Sprite`'ı olarak ayarlayın.
  3. Bu `Button`'a `CardController.cs` adında yeni bir C# script'i ekleyin.
  4. `Button`'ı `Assets` klasörüne sürükleyerek bir `Prefab` haline getirin ve sahnedeki orijinal `Button`'ı silin.

GameManager Script'i

Oyunun genel akışını, kartların oluşturulmasını, karıştırılmasını ve eşleştirme kontrolünü yönetecek bir `GameManager` script'ine ihtiyacımız var.

using System.Collections; 
using System.Collections.Generic; 
using UnityEngine; 
using UnityEngine.UI; 

public class GameManager : MonoBehaviour 
{
    [SerializeField] private GameObject cardPrefab; 
    [SerializeField] private Transform cardParent; 
    [SerializeField] private List<Sprite> cardFrontSprites; 

    private List<CardController> allCards = new List<CardController>(); 
    private List<CardController> openedCards = new List<CardController>(); 
    private int matchesFound = 0; 
    private bool canFlip = true; 

    void Start() 
    {
        SetupGame(); 
    }

    void SetupGame() 
    {
        // Kart çiftlerini oluşturun 
        List<Sprite> gameSprites = new List<Sprite>(); 
        foreach (Sprite sprite in cardFrontSprites) 
        {
            gameSprites.Add(sprite); 
            gameSprites.Add(sprite); // Her sprite'tan iki tane ekle 
        }

        // Kartları karıştırın 
        Shuffle(gameSprites); 

        // Kartları sahneye yerleştirin 
        for (int i = 0; i < gameSprites.Count; i++) 
        {
            GameObject cardGO = Instantiate(cardPrefab, cardParent); 
            CardController card = cardGO.GetComponent<CardController>(); 
            card.SetCard(gameSprites[i], i, this); 
            allCards.Add(card); 
        }
    }

    void Shuffle(List<Sprite> list) 
    {
        for (int i = 0; i < list.Count; i++) 
        {
            Sprite temp = list[i]; 
            int randomIndex = Random.Range(i, list.Count); 
            list[i] = list[randomIndex]; 
            list[randomIndex] = temp; 
        }
    }

    public void CardFlipped(CardController card) 
    {
        if (!canFlip || openedCards.Contains(card)) return; 

        openedCards.Add(card); 
        card.FlipToFront(); 

        if (openedCards.Count == 2) 
        {
            canFlip = false; 
            StartCoroutine(CheckMatch()); 
        }
    }

    IEnumerator CheckMatch() 
    {
        yield return new WaitForSeconds(1f); // 1 saniye beklet

        CardController card1 = openedCards[0]; 
        CardController card2 = openedCards[1]; 

        if (card1.CardSprite == card2.CardSprite) 
        {
            // Eşleşti! 
            matchesFound++; 
            card1.SetMatched(); 
            card2.SetMatched(); 

            if (matchesFound * 2 == allCards.Count) 
            {
                Debug.Log("Oyun Bitti! Tüm kartlar eşleşti."); 
                // Oyunu bitirme veya yeniden başlatma mantığı eklenebilir. 
            }
        }
        else 
        {
            // Eşleşmedi, kartları geri çevir 
            card1.FlipToBack(); 
            card2.FlipToBack(); 
        }

        openedCards.Clear(); 
        canFlip = true; 
    }
} 

Kart Eşleştirme Mantığının Temelleri

Her bir kartın kendi durumunu yönetmesi ve `GameManager` ile iletişim kurması için `CardController` script'ine ihtiyacımız var.

using UnityEngine; 
using UnityEngine.UI; 

public class CardController : MonoBehaviour 
{
    [SerializeField] private Sprite cardBackSprite; 
    private Sprite cardFrontSprite; 
    private int cardId; 
    private GameManager gameManager; 
    private Button cardButton; 
    private Image cardImage; 

    public Sprite CardSprite { get { return cardFrontSprite; } } 
    private bool isFlipped = false; 
    private bool isMatched = false; 

    void Awake() 
    {
        cardButton = GetComponent<Button>(); 
        cardImage = GetComponent<Image>(); 
        cardButton.onClick.AddListener(OnCardClicked); 
    }

    public void SetCard(Sprite frontSprite, int id, GameManager manager) 
    {
        cardFrontSprite = frontSprite; 
        cardId = id; 
        gameManager = manager; 
        FlipToBack(); // Başlangıçta tüm kartlar kapalı 
    }

    void OnCardClicked() 
    {
        if (!isFlipped && !isMatched) 
        {
            gameManager.CardFlipped(this); 
        }
    }

    public void FlipToFront() 
    {
        cardImage.sprite = cardFrontSprite; 
        isFlipped = true; 
    }

    public void FlipToBack() 
    {
        cardImage.sprite = cardBackSprite; 
        isFlipped = false; 
    }

    public void SetMatched() 
    {
        isMatched = true; 
        cardButton.interactable = false; // Eşleşen kartlara tıklanamaz 
        // Kartı hafifçe saydam yapabiliriz veya yok edebiliriz 
        // LeanTween veya DOTween gibi kütüphanelerle animasyon eklenebilir 
    }
} 

Unity Editör Kurulumu

`GameManager` `GameObject`'u oluşturun ve `GameManager.cs` script'ini ekleyin.

  • `Card Prefab` alanına oluşturduğunuz kart `Prefab`'ını sürükleyin.
  • `Card Parent` alanına `GridLayoutGroup` içeren `GameObject`'i sürükleyin.
  • `Card Front Sprites` listesine kartların ön yüzü için kullanacağınız `Sprite`'ları ekleyin (her kart çifti için bir adet).

`CardController` script'ine de kartın arka yüzü `Sprite`'ını sürüklemeyi unutmayın.

Oyun Durumu Yönetimi ve Kullanıcı Arayüzü

Yukarıdaki `GameManager` script'inde temel oyun durumu yönetimi (açılan kartlar, eşleşme kontrolü) zaten mevcut. Ancak skor, zamanlayıcı veya oyun bitiş ekranı gibi UI öğeleri ekleyerek oyun deneyimini zenginleştirebiliriz.

  • Skor: `GameManager`'a bir `Text` referansı ekleyip `matchesFound` sayısını bu `Text` ile güncelleyebilirsiniz.
  • Yeniden Başlatma: Oyun bittiğinde veya oyuncu istediğinde oyunu yeniden başlatmak için bir `Button` ekleyip `GameManager`'a bir `RestartGame()` metodu yazabilirsiniz. Bu metod, `allCards` listesini temizleyip `SetupGame()` metodunu tekrar çağırabilir.

Pratik İpuçları ve En İyi Uygulamalar

1. Coroutine'ler ile Akıcı Geçişler

Kartların açılıp kapanması veya eşleşme kontrolü gibi işlemlerde anlık geçişler yerine belirli bir süre bekleme (`yield return new WaitForSeconds()`) kullanmak, oyuna akıcılık katar. Yukarıdaki `CheckMatch` Coroutine'i bunun güzel bir örneğidir. Bu sayede oyuncu açtığı kartları görebilir ve eşleşip eşleşmediğini anlayabilir.

2. Kart Prefab'ı Kullanımı

Her bir kartı manuel olarak sahneye yerleştirmek yerine, bir `Prefab` oluşturup `Instantiate` etmek, hem proje düzenini korur hem de kart sayısını dinamik olarak değiştirmeyi kolaylaştırır. Bu, farklı zorluk seviyeleri için oyun tahtası boyutunu kolayca ayarlamanıza olanak tanır. Unity Memory Match oyunlarında bu yaklaşım, özellikle büyük kart setleri için vazgeçilmezdir.

3. Görsel ve Sesli Geri Bildirimler

Oyuncuya her eylemde görsel veya sesli geri bildirim vermek, oyun deneyimini büyük ölçüde iyileştirir. Kart açıldığında küçük bir animasyon veya ses efekti, eşleşme bulunduğunda farklı bir animasyon/ses, eşleşmeme durumunda ise başka bir ses ekleyebilirsiniz. Unity'nin `Animator` bileşeni veya LeanTween gibi popüler kütüphaneler, bu tür animasyonları kolayca oluşturmanıza yardımcı olur.

4. Esnek Tasarım: Zorluk Seviyeleri

Oyununuzu farklı zorluk seviyelerine uygun hale getirmek için `cardFrontSprites` listesinin boyutunu değiştirebilirsiniz. Örneğin, kolay seviye için 4 çift (8 kart), orta seviye için 8 çift (16 kart) kullanabilirsiniz. `GridLayoutGroup` ayarlarıyla da kartların boyutunu ve boşluklarını ayarlayarak farklı tahta düzenleri oluşturabilirsiniz.

Yaygın Hatalar ve Çözümleri

  • `NullReferenceException` Hatası: Bu, Unity geliştiricilerinin en sık karşılaştığı hatalardan biridir. `GameManager` veya `CardController` script'indeki `[SerializeField]` ile işaretlenmiş alanlara Unity editöründen `GameObject` veya `Sprite` atamayı unutmanızdan kaynaklanır. Hata mesajındaki satır numarasını kontrol ederek hangi referansın eksik olduğunu bulabilirsiniz.
  • Aynı Anda Birden Fazla Kartın Açılması: `canFlip` gibi bir boolean değişken kullanmak, oyuncunun eşleşme kontrolü yapılırken üçüncü bir kartı çevirmesini engeller. `CheckMatch` Coroutine'i bitene kadar bu değişkeni `false` tutmak, bu hatayı önler.
  • Kartların Doğru Karıştırılmaması: `Shuffle` fonksiyonunuzun gerçekten rastgele bir dağılım sağladığından emin olun. Yukarıdaki Fisher-Yates karıştırma algoritması güvenilir bir yöntemdir. Bazı basit `Random.Range` kullanımları, tekrarlayan desenlere yol açabilir.
  • UI Güncellemelerinin Gecikmesi: Eğer skor veya diğer UI öğeleri anında güncellenmiyorsa, `Update()` metodunda değil, ilgili olayın tetiklendiği yerde (örneğin, `matchesFound` arttığında) güncellemeyi tetiklediğinizden emin olun.

Performans ve Optimizasyon Notları

Basit bir Unity Memory Match oyunu genellikle büyük performans sorunları yaratmaz. Ancak, yüzlerce kart içeren çok büyük tahtalar veya mobil cihazlar için geliştirme yapıyorsanız aşağıdaki noktalara dikkat edebilirsiniz:

  • Gereksiz `GameObject` Oluşturmaktan Kaçınma: `Instantiate` işlemi maliyetlidir. Eğer oyununuzda çok sık kart oluşturup yok ediyorsanız (ki Memory Match'te bu pek olmaz), `Object Pooling` tekniğini düşünebilirsiniz. Ancak bu senaryo için genellikle gerek yoktur.
  • `Update` Metodu Yerine Olay Tabanlı Yaklaşımlar: Performans açısından kritik olmayan kontrolleri her `frame`'de çalışan `Update()` metoduna koymaktan kaçının. Bunun yerine, bir olay (kart tıklanması, eşleşme bulunması) tetiklendiğinde çalışan metotları kullanın.
  • UI Optimizasyonu: Unity UI, bazen performans darboğazlarına neden olabilir. Özellikle çok sayıda UI öğesi veya karmaşık düzenler kullanıyorsanız, `Canvas`'ları bölmek veya `Graphic Raycaster`'ı optimize etmek gibi yöntemleri araştırabilirsiniz. Ancak bu basit Memory Match projesi için bu seviyede bir optimizasyon genellikle gereksizdir.

Sonuç

Bu makalede, Unity ve C# kullanarak temel bir kart eşleştirme (Unity Memory Match) oyununu nasıl geliştireceğinizi öğrendiniz. Kart `Prefab`'ı oluşturmaktan, `GameManager` ve `CardController` script'leri ile oyun mantığını kurmaya, eşleştirme kontrolünü yapmaya ve pratik ipuçları ile oyununuzu geliştirmeye kadar birçok konuya değindik. Artık bu temel bilgileri kullanarak kendi yaratıcı Memory Match oyunlarınızı geliştirmeye başlayabilir, daha karmaşık özellikler (zamanlayıcı, puan sistemi, farklı zorluk seviyeleri, çok oyunculu mod) ekleyerek oyununuzu daha da zenginleştirebilirsiniz.

Unutmayın, oyun geliştirme sürekli bir öğrenme sürecidir. Deney yapmaktan, hatalar yapmaktan ve çözümler bulmaktan çekinmeyin. İyi kodlamalar!

🧠 Ders Sonu Değerlendirme Testi

Dersi tamamladıktan sonra bilgilerinizi test edin ve ekstra puanlar kazanın.

🔥 +50 XP Ödül
🔒

Sınava Katılmak İçin Giriş Yapın

Bu ders sonu testini çözebilmek, bilginizi test edip **+50 XP** kazanmak ve **Sınav Şampiyonu** rozetinin kilidini açmak için üye girişi yapmalısınız.

Yorumlar (0)

Yorum yazabilmek ve derslere katkıda bulunabilmek için giriş yapmalısınız.

İlk yorumu siz yapın!