Yılan oyunu projesinde farklı bir sınıf yardımıyla yılan ve yemi kontrol ettirirken iki farklı oyun modu ekleme şansımız da oldu.
Yılan oyunu için ilk başta bir tane baş belirliyoruz. Her şey bu baş üzerinden yapılacaktır. Baş ve gövde için Button, PictureBox vb. türlerde nesne tanımlanabilir, hiç fark etmez. Ancak ben numaralandırma adımını kolaylaştırmak adına Button kullanmayı tercih ettim.
Yön Tanımlama
Yılan oyunumuz 2 boyutlu bir düzlemde oynanmakta ve yönünü tanımlayacağımız 4 çeşit durum söz konusu olmaktadır.
1 2 3 4 | public enum Yon { YUKARI, ASAGI, SAG, SOL } |
Yon adında enum (numaralandırma tipi) oluşturuldu. Bu tip tanımlaması ile eskiYon ve yilaninYonu oluşturuldu. Bu kod bloğu olmasaydı yılan kontrol edilemezdi ve oyunun amacı yerine getirilemezdi.
Yılanın Yönünü Tespit Etme
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | public void YonTespitEt(KeyEventArgs e) { if (yonDegisti) return; Yon eskiYon = yilaninYonu; if (yilaninYonu != Yon.YUKARI) { if (e.KeyCode == Keys.Down || e.KeyCode == Keys.S) { yilaninYonu = Yon.ASAGI; } } if (yilaninYonu!=Yon.SOL) { if (e.KeyCode == Keys.Right || e.KeyCode == Keys.D) { yilaninYonu = Yon.SAG; } } if (yilaninYonu!=Yon.SAG) { if (e.KeyCode == Keys.Left || e.KeyCode == Keys.A) { yilaninYonu = Yon.SOL; } } if (yilaninYonu != Yon.ASAGI) { if (e.KeyCode == Keys.Up || e.KeyCode == Keys.W) { yilaninYonu = Yon.YUKARI; } } if (eskiYon != yilaninYonu) { yonDegisti = true; } } |
Bu kod bloğu ile tuşları algılayıp nereye gideceğini belirliyoruz. Ayrıca yılanın kendi üstünden geçmesi engelleniyor. Örneğin sağ tarafa doğru giderken sol tarafa gitmesi için öncelikle ya ukarıya ya da aşağıya doğru gidilmesi gerekiyor, doğrudan sola gitmesi mümkün olmuyor. Bu kod bloğunun çağırılması gereken yer formun KeyDown özelliğidir.
Yılanı Yönlendirme
Bu kod bloğu yukarıda belirlediğimiz yöne göre yılanın hareket etmesini sağlıyor. Bu metotu sürekli çağırmamız gerekiyor. Bu nedenle sonsuz bir döngü veya Timer’ın içinde çağrılmalıdır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public void Yonlendir() { switch (yilaninYonu) { case Yon.YUKARI: Bas.Top -= adim; break; case Yon.ASAGI: Bas.Top += adim; break; case Yon.SAG: Bas.Left += adim; break; case Yon.SOL: Bas.Left -= adim; break; } yonDegisti = false; } |
yonDegisti isimli değişkenin kullanım nedeni, ilerletme işleminin Timer ile yapılması sebebiyle henüz yılan bir kare ilerleyemeden zıt yöne doğru ilerlemesini engellemektir. Aksi yılan kendi üzerinden zıt yönde geçmeye çalışacak ve doğal olarak çarpışma algılanacaktı.
Yemin Konumlandırılması
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public void YemKonumlandir() { Random rnd = new Random(); bool yemYerlestir=true; YEM_YERLESTIR: yem.Top = rnd.Next(0, f.Height - 100); yem.Left = rnd.Next(0, f.Width - 100); for (int i = 0; i < yilan.Count; i++) { //Çakışma var if (yilan[i].Bounds.IntersectsWith(yem.Bounds)) { goto YEM_YERLESTIR; } } } |
Yılanın amacını yerine getirebilmesi için bir yemin konumu belirliyoruz. Burada dikkat edilecek yer döngü ve içerisindeki kontroldür. Bu kontrol olmasaydı yem oyun içerisinde yılanımızın kuyruğu üstünde çıkabilirdi. Burada söz konusu olan yem ise herhangi bir nesne olabilir ancak ben PictureBox kullandım. Eğer oluşturulan yem ile yılan üzerinde herhangi bir noktada çakışma var ise yem yeniden oluşturulur.
Sonsuz Geçiş Özelliği
Sonsuz geçiş, her yılan oyununda bulunan bir köşeye girince diğer köşeden çıkma olayıdır. Bu kod bloğu oyunumuzu daha esnek yürütmemizi sağlar. Bu kodu kullanma ilgili formdan çağırma zorunluluğu yoktur. Ancak eğer duvar koymadıysak kenarlardan geçen yılan görüş açımızdan kaybolacaktır. Bunu engellemek için duvar eklenebilir ve başın duvarla teması kontrol edilir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public void SonsuzGecis() { if (Bas.Top <= f.Top) { Bas.Top = f.Bottom; } else if (Bas.Top >= f.Bottom) { Bas.Top = f.Top; } if (Bas.Right > f.Right) { Bas.Left = f.Left; } else if (Bas.Left <= f.Left) { Bas.Left = f.Right; } } |
Duvar ve Labirent Ekleme
Yukarıda bahsi geçen duvar kontrol olayı esnek olarak aşağıdaki kodlar ile tanımlanabilir:
1 2 3 4 5 6 7 | public void DuvarYerlestirme(params PictureBox[] eklenecek_duvarlar) { foreach (PictureBox duvar in eklenecek_duvarlar) { this.duvarlar.Add(duvar); } } |
Form yüklenirken (Form_Load) Panel ile oluşturduğumuz duvarlarımızı parametre yardımıyla gönderiyoruz. Bu sayede duvarlarımız 1000 adet olsa bile kontrolümüz gayet basit olacaktır. Duvarların ilgili metoda gönderimi şu şekilde yapılmaktadır:
1 | yilan.DuvarYerlestirme(pictureBox1, pictureBox2, pictureBox3, pictureBox4); |
Eğer bunların yanında labirent gibi çeşitli PictureBox nesneleri de eklenecekse aynı metot şu şekilde kullanılabilir:
1 | yilan.DuvarYerlestirme(pictureBox1, pictureBox2, pictureBox3, pictureBox4, pictureBox5, pictureBox6); |
Bir metotun değişken sayıda parametre alması params ifadesi ile sağlanmaktadır.
Duvar veya Labirente Çarpma Kontrolü
Artık kontrol etmemiz gereken yere geldik. Şu an yapmamız gereken Bas adlı nesnemizin duvarlar ile temasının olup olmadığını kontrol etmektir. C#’ın bize bu açıdan çok kolaylık sağlayacak hazır bir komutu vardır: IntersectsWith()
1 2 3 4 5 6 7 8 9 10 11 12 | public bool DuvaraCarpti() { foreach (PictureBox duvar in duvarlar) { //Döngü ile tüm duvarlara çarpma kontrolü if (Bas.Bounds.IntersectsWith(duvar.Bounds)) { return true; } } return false; } |
IntersectsWith() metodu yardımıyla iki nesnenin birbiri üstine gelip gelmediği kontrol edilebilir.
Eğer yukardan TRUE dönerse yılanın başının duvara çarptığı anlaşılacaktır, dolayısıyla oyun sona erecektir.
1 2 3 4 5 6 7 | if (yilan.DuvaraCarpti()) { timer5.Stop(); MessageBox.Show("Yandınız Skorunuz :" + label1.Text); this.Close(); frm.Show(); } |
Yem Yeme Kontrolü
Bu kod bloğunda yapılan işlem yılanın başının yem ile temasının olup olmadığının kontrol edilmesidir.
1 2 3 4 5 6 | public bool YemiYedi() { if (Bas.Bounds.IntersectsWith(yem.Bounds)) return true; return false; } |
Form içerisinde ise yemin yenip yenmediği kontrol edilecektir. Yukarıdan TRUE gelirse yemin yendiği anlaşılıyor ve yemi yeniden konumlandırıp skoru arttırıyoruz. Oyunun daha da zorlaşması için Timer’ın hızını düşürüyoruz, böylece yılanın hızı artıyor.
Yem Yedikçe Yılanın Büyümesi
Şu ana kadar yılan oyunumuz çalışıyor, yem yeniyor, skor artıyor ancak yılan büyümüyor.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | public Button YilanBuyut() { Button yeniKutu = new Button(); if (renkliYilan) { Renklendir(); yeniKutu.BackColor = Color.FromArgb(x, y, z); } else { yeniKutu.BackColor = yilan.Last().BackColor; } yeniKutu.Width = yeniKutu.Height = yilan.Last().Width; yeniKutu.Top = yilan.Last().Top; yeniKutu.Left = yilan.Last().Left; yeniKutu.Enabled = false; switch (yilaninYonu) { case Yon.YUKARI: yeniKutu.Top += adim; break; case Yon.ASAGI: yeniKutu.Top -= adim; break; case Yon.SAG: yeniKutu.Left += adim; break; case Yon.SOL: yeniKutu.Left -= adim; break; } yeniKutu.Text = (yilan.Count() + 1) + ""; yilan.Add(yeniKutu); return yeniKutu; } |
Yukarıda yeni bir dinamik Button tanımlıyoruz ve bu nesnenin Top, Left, Height ve Width’ini belirliyoruz. Yılanın gideceği yöne göre son kısma bu nesneyi konumlandırarak yilan isimli listeye bu nesneyi ekliyoruz.
Yılan oyunu ana işlemleri ve mantığı açıklanmıştır. C# ile yapılmış yılan oyunu projesine https://github.com/EmirhanSeyhan/YilanOyunu adresinden ulaşabilirsiniz.