2 Boyutlu Platform Oyunu (Unity/C#) Coviddin

Herkese merhaba. Bu blog yazısında sizlere staj süresince üzerinde çalıştığım projeyi aktaracağım. Bu proje bir oyun projesidir. Oyunun türü ise 2 boyutlu platform oyunudur. Oyun Unity oyun motoru ve C# programlama dili kullanılarak hazırlanmıştır. Oyundaki kullanılan çizimler pixel art tekniği kullanılarak hazırlanmıştır.

Oyundaki amaç Coviddin adlı ana karakterimizi, bazı güçlendirmeler ile güçlendirerek, korona virüse yakalanmadan ve diğer engelleri aşarak hedefine ulaştırmaktır.

Bildiğiniz gibi şu sıralar tüm ülke ve tüm dünya olarak zor bir süreçten geçiyoruz. Bu projeye aynı zamanda gündemde olan korona virüs dahil edildi. Projenin amacı, bir yandan oyun oynarken bir yandan farkındalık oluşturmaktır.

Oyunda müzik ve ses efektleri olarak retro tarzı müzik ve ses efektleri seçililmiştir.

2 Boyutlu Platform Oyunu nedir?

2D platformer oyunları, 80’lerin başlarında çıkan, çok popüler bir video oyunu türü olan platform video oyunlarının bir çeşididir.

Platform oyunları ilk çıktığında, oyuncunun belli engelleri aşarak bölümü bitirdiği ve tüm bölümün tek ekranda olduğu bir formattaydı. Super Mario Bros’un gelişiyle birlikte oyun kamerasının oyuncuyu takip ettiği ve daha uzun bölümlerle, ilerledikçe ekranın soldan sağa doğru kaydığı bir formata dönüştü. Genellikle ana karakter platformdan platforma atlar ve kazandığı güçlendirmelerle veya silahlarla birlikte düşmanlarla başa çıkar.

Bazı popüler 2D platform oyunları Super Mario Bros, Sonic the Hedgehog ve Rayman’dir.

Unity Nedir?

Unity, bilgisayarlar, konsollar ve mobil cihazlarda video oyunu geliştirmek için kullanılan, çapraz platformlu bir oyun motorudur. Unity Technologies tarafından ilk sürümü (1.0) 2005 yılında yayınlanmış ve hala geliştirilmesine devam edilmektedir.

Unity, C# programlama ile komut dosyası yazmayı desteklemektedir.

Unity’nin desteklediği kullanıcı arayüzleri (API); Windows ve Xbox One üzerinde Direct3D; Linux, macOS ve Windows’ta OpenGL; Android ve iOS’ta OpenGL ES; Web’de WebGL.

Unity’de geliştirilen bir uygulama, herhangi bir altyapı değişikliğine gerek duymaksızın farklı platformlara aktarılabilmektedir.

2018 itibarıyla Unity; piyasadaki yeni mobil oyunların yaklaşık yarısını, artırılmış gerçeklik ve sanal gerçeklik içeriğinin de yüzde 60’ını oluşturmak için yazılımcılar tarafından kullanılmıştır. (“DeepMind partners with gaming company for AI research”As it builds out its AI, Unity will develop virtual environments where it can learn. daily dot.)

C# Nedir?

C#, Microsoft tarafından günümüzde de geliştirilmekte ve desteklenmekte olan nesneye yönelik bir programlama dilidir. C ve C++ etkileşimi ile türetilmiştir. Ayrıca C#, ortak platformlarda taşınabilir bir (portable language) programlama  dili olan Java ile pek çok açıdan benzerlik taşımaktadır. En büyük özelliği ise .Net Framework platformu için hazırlanmış bir yazılım dilidir.

Ayrıca gelişmiş derleyicisi (debugger) ile hata olasılığını ortadan kaldırmaktadır. Yazılan program çalıştırıldıktan sonra derleyici tarafından algılanan sınıf ve söz dizimi (syntax) hataları yazılımcıya ayrı bir ekranda ayrıntısı ile gösterilir ve yazılımcı bu hata penceresinden hataları tespit ederek kolayca düzeltebilir.

Unity ve C# Arasındaki İlişki

C# ile yazılan kodlar, Unity’de oluşturulan objelerin (GameObjects) kontrolünü sağlar. Projedeki objelere eklenen kodlar ve bu objelerin birbirleriyle olan etkileşimi, oyun deneyimini oluşturmaktadır. Unity ve C# büyük bir döngüde çalışır. Bir oyun sahnesindeki tüm veriler Unity tarafından okunur ve işlenir. Bu projede C# kodları Visual Studio uygulaması ile yazılmıştır.

Pixel Art Nedir?

Piksel sanatı, görüntülerin piksel düzeyinde düzenlendiği yazılım kullanılarak oluşturulan bir dijital sanat şeklidir. Bu şekillerin görüntüleri 8-16 bitlik bilgisayarlardan ve oyun konsollarından gelmektedir. Çoğu pixel art çalışmalarında kullanılan renk sayısı son derece sınırlıdır. Video oyunlarındaki pixel art karakterleri veya nesneleri oluşturma işlemi ‘spriting’ olarak adlandırılır. Bu isim pixel art topluluğu tarafından verilmiştir.

Bu projede çoğu pixel art çizimleri için 32×32 piksellik sprite’lar kullanılmıştır.

Bu uygulamadaki çizimler Piskelapp adlı uygulamada yapılmıştır. Piskelapp açık kaynak kodlu, çizim esnasında animasyonun önizlemesini sağlayan, yapılan çalışmaların çeşitli dosya tiplerinde (çoğunlukla png) çıkarılmasına izin veren ücretsiz bir pixel art uygulamasıdır.

Unity ve Animasyon

Unity oyun motorundaki animation komponenti, oyundaki animasyonları oynatmak için kullanılır. Animation komponentine, animasyon klipleri atanır ve bu klipler C# scriptleri yardımıyla kontrol edilir. Unity’de animation komponenti Enum sınıfını desteklemektedir. Bu durum animasyonlar enum ile tanımlanarak kod temizliği ve kullanım kolaylığı açısından önemli bir yere sahiptir.

Pixel art kullanılarak oluşturulan scriptler, tıpkı çizgifilmlerdeki gibi, resimler ard arda eklenerek animasyonlar oluşturulmaktadır. Projede, ana karakter ve virüs için animasyon hiyerarşileri bulunmaktadır.

Ana karakterin bekleme, koşma, yükselme, düşme ve kayma animasyonlarından oluşan bir animasyon hiyerarşisi vardır.

Bu hiyerarşi maskeli ve maskesiz animasyonlardan oluşan 11 adet animasyona sahiptir.

Animasyonlar arası geçişler int türündeki state değişkeni ile sağlanmaktadır.

Koşu animasyonu 6’şar, bekleme animasyonu 4’er çizimden oluşmaktadır.

Animasyonlar arası bağlantı etiketler aracılığıyla sağlanmaktadır.

Ana Karakter, Coviddin

CoviddinIdle CoviddinIdle  

Yukarıdaki resimler ana karakterimizin maskeli ve maskesiz bekleme animasyonuna aittir. Karakterin iki tarafa doğru yürüme ve zıplama özellikleri vardır. Bunlar dışında maske güçlendirmesi ile karakterimizin görüntüsü ve animasyonları değişmektedir. Dezenfektan güçlendirmesi ile karakterin etrafında saydam bir kalkan oluşmaktadır.

Ana Karakter, Koşma Animasyonu

Zıplama Animasyonu

Kayma Animasyonu

Bitiş Animasyonu

 

Animasyon Hiyerarşisi

 

 

private void AnimationInfo() //Animasyonlar arasındaki bağlantıyı sağlayan metot
    {
        if(gameObject.tag == "Player")
        {
            if (state == State.jumping)
            {
                if(rb.velocity.y < 0.1f)
                {
                    state = State.falling;
                }
            }

            else if(state == State.falling)
            {
                if(coll.IsTouchingLayers(ground))
                {
                    state = State.idle;
                }
            }

            else if(state == State.hurt)
            {
                if(Mathf.Abs(rb.velocity.x) < 0.1f)
                {
                    state = State.idle;
                }
            }

            else if(Mathf.Abs(rb.velocity.x) > 1.5f &amp;&amp; virusScript.maskLife >= 0)
            {
                state = State.running;
            }

            else if(virusScript.maskLife < 0)
            {   
                gameObject.GetComponent<PlayerController>().enabled = false;
                Debug.Log("dead");
                state = State.death;

                menuButton.gameObject.SetActive(true);
                retryButton.gameObject.SetActive(true);
                rb.constraints = RigidbodyConstraints2D.FreezePositionX;

                imageBorder.enabled = true;
            }

            else
            {
                state = State.idle;
            }
        }
        
        else if(gameObject.tag == "Finish")
        {
            if (state == State.jumping2)
            {
                if (rb.velocity.y < 0.1f)
                {
                    state = State.falling2;
                }
            }

            else if (state == State.falling2)
            {
                if (coll.IsTouchingLayers(ground))
                {
                    state = State.idle2;
                }
            }

            else if(state == State.hurt2)
            {
                if (Mathf.Abs(rb.velocity.x) < 0.1f)
                {
                    state = State.idle;
                }
            }

            else if (Mathf.Abs(rb.velocity.x) > 1.5f)
            {
                state = State.running2;
            }
                  
            else
            {
                state = State.idle2;
            }
        }
    }

Virüs

Virüs, hem gerçek hayatta hem de oyunda düşmanımızdır.

Maskesiz veya dezenfektansız halde virüs ile yaşanan temas oyuncuyu öldürmekte ve oyunu bitirmektedir.

Virüsler sağa sola ya da yukarı aşağı hareket halinde veya bekliyor olabilir.

Virüslere ait 3 çizimden oluşan bir animasyon vardır.

private void OnCollisionEnter2D(Collision2D collision) //Ana karakterin virüs ile etkileşime girmesini kontrol eden metot
    {
        if(collision.gameObject.tag == "Virus")
        {

            if(gameObject.tag == "Player")
            {
                state = State.hurt;
            }

            else if(gameObject.tag == "Finish")
            {
                state = State.hurt2;
            }

            if (collision.gameObject.transform.position.x > transform.position.x)
            {   
                rb.velocity = new Vector2(-5, rb.velocity.y);
            }

            else if(collision.gameObject.transform.position.x < transform.position.x)
            {
                rb.velocity = new Vector2(5, rb.velocity.y);
            }

            if(virusScript.maskLife != 0)
            {
                if(virusScript.maskLife >= 1 &amp;&amp; virusScript.maskLife <=5)
                {
                    virusScript.maskLife = 1;
                }

                else
                {
                    virusScript.maskLife -= 5;
                    Debug.Log(virusScript.maskLife);
                }
                
            }

            else if(virusScript.maskLife == 0)
            {
                virusScript.maskLife -= 1;
                imageBorder.gameObject.SetActive(true);
            }
        }
    }

Toplanabilir Objeler

Maske

Maske kullanmak virüsü öldüremez ancak belli bir süreliğine virüslerden koruma sağlar.

Oyunda maskelerin kullanım ömürleri 20 saniyedir. Bu oyun içinde bir gösterge ile kullanıcıya gösterilmektedir.

Maske virüslerle temas halinde oyuncuyu ölmekten kurtarır ancak bu temas maskenin kullanım ömrünü bir miktar azaltmaktadır.

Dezenfektan

Dezenfektan kullanmak, oyuncuyu hem virüslerden korur hem de temas halinde virüsleri öldürür.

Dezenfektan, oyuncuya saydam bir kalkan sağlar. Bu saydamlık oyun motoru ile sağlanır.

Dezenfektanların belli bir etki süresi vardır.

Virüslerle temas bu etki süresini düşürmez.

public class Bubble : MonoBehaviour //Kalkan script'i
{
    [SerializeField] private AudioSource audio;

    void Start()
    {
        gameObject.SetActive(false);
    }

    void Update()
    {
        if(gameObject.activeSelf)
        {
            StartCoroutine(Deactive());
        }
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if(collision.gameObject.tag == "Virus")
        {
            audio.Play();
            Virus virus = collision.gameObject.GetComponent<Virus>();
            virus.VirusDeath();
            //Destroy(collision.gameObject);
        }
    }

    private IEnumerator Deactive()
    {
        yield return new WaitForSeconds(10);
        gameObject.SetActive(false);
    }
}

Kullanıcı Arayüzü ve Sahneler

Başlangıç Ekranı

Talimatlar Ekranı

public class Opening : MonoBehaviour //Oyuna başlama ve oyundan çıkma sınıfı
{
    [SerializeField] private Button b1, b2;

    void Start()
    {
        b1.onClick.AddListener(TaskOnClick);
        b2.onClick.AddListener(TaskOnClick2);
    }

    void TaskOnClick()
    {
        SceneManager.LoadScene("LevelSelect");
    }

    void TaskOnClick2()
    {
        Application.Quit();
    }
}

public class Instructions : MonoBehaviour //Talimatlar sınıfı
{
    [SerializeField] private Button b1;
    [SerializeField] private Image image;
    [SerializeField] private Text text;

    void Start()
    {
        b1.onClick.AddListener(TaskOnClick);
        image.enabled = false;
        text.enabled = false;
    }

    private void TaskOnClick()
    {
        image.enabled = true;
        text.enabled = true;
    }
}

Oyun İçi Görüntüler ve Kontroller

Oyundaki Evler ve Alışveriş Merkezi

Mevlana Türbesi

Şehir Sahnesinin Perspektifli Görünümü

Oyun Sonu Ekranı