XNA Oyun Programlama yazı dizime bu yazımla başlıyorum. Öncelikle XNA nedir? biraz bundan bahsetmek istiyorum.
XNA, .Net ortamında 2D ve 3D oyun geliştirmek için, Microsoft tarafından üretilmiş bir framework‘tür. XNA bir programalama dili veya tekniği değildir, yüzlerce class’tan oluşan bir framework’tür.
XNA temelinde, Xbox platformu için .Net Compact Framework 2.0 ve Windows platformu için .Net Framework 2.0 vardır.
DirectX veya OpenGL‘in low-level fonksiyonlarıyla uğraşmak yerine programcıya, daha kolay yönetilebilir, kullanılabilir, OOP sınıflar sunacak şekilde kodlanmıştır.
Haliyle, oyun geliştirmeye başlamak isteyenler için güzel bir başlangıç noktasıdır.
Microsoft tarafından ilk olarak 14 Mart 2006 tarihinde San Jose California’da düzenlenen Game Developers Conference‘ta duyurulmuştur.
XNA ile geliştirilmiş oyunlar, .Net Compiler aracılığıyla MSIL‘e derlendiği için, ya olduğu gibi ya da çok az modifikasyonla framework kurulu tüm platformlarda çalıştırılabilir.
XNA geliştirmek için yapmamız gereken, bilgisayarımıza XNA Game Studio kurmak. Şu anda en güncel versiyon olan XNA Game Studio 3.1 şuradan indirilebilir.
Ne yazık ki XNA Game Studio 3.1 ve Visual Studio 2010 birbirlerini pek sevmiyorlar. O yüzden Visual Studio 2008 içerisinde XNA Game Project Template’lerinin nasıl göründüğüne bakalım;
Gördüğünüz gibi XNA ile Windows, Xbox ve Zune için oyun geliştirebiliyorsunuz.
Eminim hepimiz, kendi aramızda, “Kelimenin Son Harfi ile Başlayan Kelime Oyunu“nu oynamışızdır.
Oyunun kuralları basittir, iki “oyuncu” karşılıklı oturur, oyunculardan biri, bir kelime söyleyerek oyunu başlatır. Sonra oyuncular sırayla, diğerinin söylediği kelimenin son harfi ile başlayan başka bir kelime söylemek zorundadır. Söyleyecek kelime bulamayan oyuncu “oyunu” kaybeder.
Gelin bu basit oyunu C# ile yazalım. Hemen ekran görüntüsü vererek başlıyorum;
Oyunu, bir Oyuncu, bir Bilgisayar Oyuncusuna karşı oynayacak. İhtiyacımız olan ilk şey, Bilgisayar Oyuncusu’nun içinden kelime seçeceği sözlük. Sözlük oluşturmak için daha önce yazdığım Web Sayfasından Sözlük Oluşturma ve Dizi Karıştırma makalelerini birleştirip kullanacağız.
btnYeniOyun butonunun Click olayında, txtAdres kontrolüne yazılmış olan web sayfasındaki kelimeler bir listeye dolduruluyor, ayıklanıyor, karıştırılıyor ve lbKullanilabilecekKelimeler ListBox kontrolünde gösteriliyor.
public static class ExtensionManager { private static Random r = new Random();
public static List<T> ListeKaristir<T>(this List<T> Liste)
{
List<T> tmpList = Liste.GetRange(0, Liste.Count);
List<T> arrReturn = new List<T>();
while (tmpList.Count > 0)
{
int rastgele = r.Next(0, tmpList.Count);
arrReturn.Add(tmpList[rastgele]);
tmpList.RemoveAt(rastgele);
}
return arrReturn;
} }</pre>
private void btnYeniOyun_Click(object sender, EventArgs e) { lbKullanilabilecekKelimeler.Items.Clear(); lbKullanilabilecekKelimeler.BeginUpdate(); WebRequest wr = WebRequest.Create(txtAdres.Text); WebResponse ws = wr.GetResponse(); StreamReader sr = new StreamReader(ws.GetResponseStream(), Encoding.UTF8); string response = sr.ReadToEnd(); sr.Close(); ws.Close(); List<string> arrKelime = new List<string>(); Regex r = new Regex("<(.|\n)*?>"); foreach (string satir in r.Replace(response, "").Split(" \t\r\n({[]}),.;:*-+/?<>&%'#@=\"\\_".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)) if (satir.Trim().Length > 5 && !arrKelime.Contains(satir.Trim())) arrKelime.Add(satir.Trim()); lbKullanilabilecekKelimeler.Items.AddRange(arrKelime.ListeKaristir().ToArray()); lbKullanilabilecekKelimeler.EndUpdate(); txtYeniKelime.Clear(); txtOyunTarihce.Clear(); }
Oyun, birinci oyuncunun txtYeniKelime kontrolüne yazdığı kelime ile başlıyor.
string OncekiKelimeninSonHarfi = string.Empty; private void btnYeniKelime_Click(object sender, EventArgs e) { if (txtYeniKelime.Text != "" && txtYeniKelime.Text.StartsWith(OncekiKelimeninSonHarfi)) { string Kelime = txtYeniKelime.Text.Trim(); txtOyunTarihce.Text = string.Format("(O): {0}{1}{2}", Kelime, Environment.NewLine, txtOyunTarihce.Text); txtYeniKelime.Clear(); KelimeSec(Kelime); txtYeniKelime.Focus(); } }
Bilgisayar Oyuncusu Sözlük’ten kelimenin son harfi ile başlayan kelimelerden bir tanesini rastgele olarak seçiyor.
Kullandığı her kelimeyi lbKullanilabilecekKelimeler ListBox kontrolünden çıkartıp, lbKullanilmisKelimeler ListBox listesine ekliyor.
private void KelimeSec(string OncekiKelime) { Random r = new Random(); var Kelimeler = (from k in lbKullanilabilecekKelimeler.Items.OfType<string>() where k.StartsWith(OncekiKelime.Substring(OncekiKelime.Length - 1, 1)) select k).ToList<string>(); if (Kelimeler.Count == 0) { MessageBox.Show(lbKullanilmisKelimeler.Items.Count + ". Kelimede Bilgisayar Oyuncusu oynayacak Kelime bulamadı!.", "Oyun Bitti!", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); return; } int Sira = r.Next(0, Kelimeler.Count); string Kelime = Kelimeler[Sira]; OncekiKelimeninSonHarfi = Kelime.Substring(Kelime.Length - 1, 1); lbKullanilabilecekKelimeler.Items.Remove(Kelime); lbKullanilmisKelimeler.Items.Add(Kelime); txtOyunTarihce.Text = string.Format("(B): {0}{1}{2}", Kelime, Environment.NewLine, txtOyunTarihce.Text); } ![](/assets/uploads/2010/01/KSHBKO_3.png "KSHBKO_3") Oyun, Bilgisayar Oyuncusu'nun kelime bulamamasına kadar devam ediyor. ![](/assets/uploads/2010/01/KSHBKO_4.png "KSHBKO_4") Oyunun kaynak kodlarını buradan indirebilirsiniz.
Database’de şu scripti çalıştıralım;
CREATE TABLE T_PERSONEL ( ADSOYAD VARCHAR(50), DOGUM_TARIHI SMALLDATETIME )
INSERT INTO T_PERSONEL VALUES (‘Engin POLAT’, ‘1981-01-12’) INSERT INTO T_PERSONEL VALUES (‘Emre ERKAN’, ‘1979-03-14’) INSERT INTO T_PERSONEL VALUES (‘Ozan ÇAĞLARGİL’, ‘1982-09-27’) INSERT INTO T_PERSONEL VALUES (‘Fatih DURGUT’, ‘1978-06-23’) INSERT INTO T_PERSONEL VALUES (‘Burhan İNEGÖL’, ‘1980-11-08’)</pre> Aşağıdaki stored procedure’i yazalım.
CREATE PROCEDURE PR_PERSONEL_LISTE ( @SIRALAMA INT ) AS BEGIN SELECT ADSOYAD, DOGUM_TARIHI FROM T_PERSONEL ORDER BY CASE @SIRALAMA WHEN 1 THEN DOGUM_TARIHI WHEN 2 THEN ADSOYAD END END Bu procedure'ü 1 parametresi vererek çalıştırıyoruz, ve beklediğimiz sonucu alamıyoruz. Nerede hata yaptık? (İpucu; parametre olarak 2 vermeyi deneyin) Yorumlarınızı bekliyorum...
VB.NET programcılarının kullanabildiği, ama C#‘ta bulunmayan isNumeric() fonksiyonunu kendimiz yazacağız;
public static class ExtensionManager { public static bool isNumeric(this string value) { double oReturn = 0; return double.TryParse(value, out oReturn); } }</pre>
Artık C# kodumuzun herhangi bir yerinde
string Deger = "5"; bool Rakamsal = Deger.isNumeric();
veya
string Deger = "5"; bool Rakamsal = ExtensionManager.isNumeric(Deger); kullanabiliriz.
Bilgeadam’da öğrencilerimden birinin sorduğu soru üzerine, bir dizinin, belli sayıda elemanlardan oluşan alt dizilere bölünmesi ile ilgili aşağıdaki uygulamayı yazdım.
Uygulama şöyle çalışıyor; rastgele kelimelerden oluşan bir dizimiz var, bu diziyi, n elemanlı alt dizilere bölmek istiyoruz.
Hemen kolları sıvayalım ve kod yazmaya başlayalım.
Öncelikle rastgele kelime oluşturma fonksiyonunu yazalım;
const string Harfler = “abcdefghijklmnopqrstuvwxyz”; Random r = new Random();
public string RastgeleKelimeUret(int HarfAdet) { char[] arrReturn = new char[HarfAdet];
Parallel.For(0, HarfAdet, iLoop => {
arrReturn[iLoop] = Harfler[r.Next(0, Harfler.Length - 1)];
});
return new string(arrReturn); }</pre>
Bu fonksiyonu C# ile Dizi Karıştırma yazımdan hatırlayacaksınız. Şimdi bu fonksiyonu kullanarak List<string> tipinde bir diziye 25 eleman dolduran kodumuzu yazalım;
List<string> BolunecekDizi = new List<string>(); Parallel.For(5, 25, iLoop => { BolunecekDizi.Add(RastgeleKelimeUret(iLoop)); });
Parallel For kullanarak Multi-Core ve Multi-Thread destekli kod yazdığımıza dikkat edelim. Bölümleme fonksiyonunu ExtensionMethod olarak yazacağız.
public static class ExtensionManager { public static List<T>[] Bolumle<T>(this List<T> Dizi, int ParcaAdet) { if (Dizi == null) throw new Exception("Dizi boş olamaz.."); if (ParcaAdet < 1) throw new Exception("Parça Adet 1'den küçük olamaz.."); int DiziBoyu = (int)Math.Floor(Dizi.Count / (double)ParcaAdet) + 1; List<T>[] arrReturn = new List<T>[DiziBoyu]; int Adim = 0; Parallel.For(0, Dizi.Count, iLoop => { if (iLoop % ParcaAdet == 0 && iLoop > 0) Adim += 1; if (arrReturn[Adim] == null) arrReturn[Adim] = new List<T>(); arrReturn[Adim].Add(Dizi[iLoop]); }); return arrReturn; } }
Artık tek yapmamız gereken List<T> generic tipinde nesnelerde Bolumle() fonksiyonunu kullanmak olacak.
List<string>[] Bolumler = BolunecekDizi.Bolumle(3); Uygulamanın kaynak kodlarını buradan indirebilirsiniz.
Senior Software Engineer, @Microsoft
Ada ve Ege'nin babası ;)
Makale Adedi: 484