Nisan 2010′da Bahçeşehir Üniversitesindeyim (XNA Seminerleri)
Nisan ayında Bahçeşehir Üniversitesinde XNA Seminerleri veriyor olacağım. 1 seminer, 6 tane de workshop planlıyoruz. Muhtemelen Mayıs ayına’da sarkacak.
Nisan ayında Bahçeşehir Üniversitesinde XNA Seminerleri veriyor olacağım. 1 seminer, 6 tane de workshop planlıyoruz. Muhtemelen Mayıs ayına’da sarkacak.
Geliştirdiğiniz bir uygulamada, geçici bir dosyaya ihtiyacınız olduğunu düşünelim. Ama daha önce oluşturulmuş bir dosyanın ismini vermediğinizden emin olmak istiyorsunuz.
adımlarını gerçekleştirmek yerine, Path.GetTempFileName() method’unu kullanabilirsiniz.
string GeciciDosya = Path.GetTempFileName(); /// GeciciDosya değişkeni kullanıcının Temp dizininde 0-byte boyutlu bir dosyanın tam dosya yolunu içerir.
using (StreamWriter sw = File.OpenText(GeciciDosya))
{
sw.WriteLine("Geçici Dosyaya yazılacak bilginin ilk satırı");
}
Benim kullandığım bilgisayarda, Path.GetTempFileName() methodu geriye “C:\Documents and Settings\EnginPolat\Local Settings\Temp\tmp3A.tmp” string değeri döndürdü.
Eğer rastgele dosyanın gerçekten oluşturulmasını değil, sadece dosya isminin üretilmesini istiyorsanız; Path.GetRandomFileName() methodunu kullanabilirsiniz;
string DosyaAdi = Path.GetRandomFileName(); /// DosyaAdi değişkeni sadece rastgele bir dosya ismini içerir.
Benim bilgisayarımda, Path.GetRandomFileName() methodu geriye “z4a2sa4a.49e” string değeri döndürdü.
Bu yazımı okumadan önce XNA konusundaki diğer makalelerimi okumanızı öneririm.
Her zamanki gibi, öncelikle ihtiyacımız olacak görselleri vereyim;
Ben kırmızı pedalı Oyuncu 1 için, mavi pedalı Oyuncu 2 için, yeşil kareyi ise Top olarak kullanacağım.
Visual Studio 2008 içerisinde yeni bir XNA projesi oluşturalım, Game1.cs‘in ismini GameLoop.cs ile değiştirelim ve class seviyesinde değişkenlerimizi tanımlayalım;
Texture2D Oyuncu1; Texture2D Oyuncu2; Texture2D Top; Vector2 Oyuncu1Yer; Vector2 Oyuncu2Yer; Vector2 TopYer; private int Oyuncu1Skor = 0; private int Oyuncu2Skor = 0; Vector2 TopYon; private const int PENCERE_GENISLIK = 800; private const int PENCERE_YUKSEKLIK = 600; private const string PENCERE_BASLIK = "XNA - Pong Oyunu"; private const bool TAM_EKRAN = false; private readonly Color ARKAPLAN_RENK = Color.Black;
GameLoop class‘ımızın contructor‘ına aşağıdaki kodları ekleyelim;
graphics.PreferredBackBufferWidth = PENCERE_GENISLIK; graphics.PreferredBackBufferHeight = PENCERE_YUKSEKLIK; graphics.IsFullScreen = TAM_EKRAN; this.Window.Title = PENCERE_BASLIK;
Şimdi LoadContent() method’unda görselleri hafızaya yükleyeceğimiz kodları ekleyelim;
Oyuncu1 = Content.Load<Texture2D>("Oyuncu1");
Oyuncu2 = Content.Load<Texture2D>("Oyuncu2");
Top = Content.Load<Texture2D>("Top");
Oyuncu1Yer = new Vector2((float)(graphics.GraphicsDevice.Viewport.Width * 0.07), (float)(graphics.GraphicsDevice.Viewport.Height / 2));
Oyuncu2Yer = new Vector2((float)(graphics.GraphicsDevice.Viewport.Width - (graphics.GraphicsDevice.Viewport.Width * 0.07)), (float)(graphics.GraphicsDevice.Viewport.Height / 2));
TopYer = new Vector2(graphics.GraphicsDevice.Viewport.Width / 2, graphics.GraphicsDevice.Viewport.Height / 2);
TopYon = new Vector2(3, 3);
Draw() methodunda ekrana çizim işlerini yapalım;
spriteBatch.Begin(SpriteBlendMode.AlphaBlend); spriteBatch.Draw(Oyuncu1, Oyuncu1Yer, Color.White); spriteBatch.Draw(Oyuncu2, Oyuncu2Yer, Color.White); spriteBatch.Draw(Top, TopYer, Color.White); spriteBatch.End();
Update() methodunda her iki oyuncunun ve top’un yerlerini hesaplayalım. Öncelikle klavyenin o andaki durumunu alalım;
KeyboardState ks = Keyboard.GetState();
Hangi tuşların basılı olduğunu kontrol edelim;
if (ks.IsKeyDown(Keys.Escape)) this.Exit(); if (ks.IsKeyDown(Keys.Up)) Oyuncu1Yer.Y -= 3; if (ks.IsKeyDown(Keys.Down)) Oyuncu1Yer.Y += 3; if (Oyuncu1Yer.Y < 0) Oyuncu1Yer.Y = 0; if (Oyuncu1Yer.Y > PENCERE_YUKSEKLIK - Oyuncu1.Height) Oyuncu1Yer.Y = PENCERE_YUKSEKLIK - Oyuncu1.Height; if (ks.IsKeyDown(Keys.E)) Oyuncu2Yer.Y -= 3; if (ks.IsKeyDown(Keys.D)) Oyuncu2Yer.Y += 3; if (Oyuncu2Yer.Y < 0) Oyuncu2Yer.Y = 0; if (Oyuncu2Yer.Y > PENCERE_YUKSEKLIK - Oyuncu2.Height) Oyuncu2Yer.Y = PENCERE_YUKSEKLIK - Oyuncu2.Height;
Top‘un ekrandan dışarı çıkmaması için, ekranın üstüne veya altına eriştiğinde, yönünü değiştirecek kodu ekleyelim;
if ((TopYer.Y < 0) || (TopYer.Y > PENCERE_YUKSEKLIK - Top.Height)) TopYon.Y *= -1; if ((TopYer.X < 0) || (TopYer.X > PENCERE_YUKSEKLIK - Top.Width)) TopYon.X *= -1;
Şimdi Oyuncu 1, Oyuncu 2 ve Top için konum ve boyut bilgilerini tutacağımız Rectangle değişkenlerini tanımlayalım;
Rectangle Oyuncu1Rect = new Rectangle((int)Oyuncu1Yer.X, (int)Oyuncu1Yer.Y, Oyuncu1.Width, Oyuncu1.Height); Rectangle Oyuncu2Rect = new Rectangle((int)Oyuncu2Yer.X, (int)Oyuncu2Yer.Y, Oyuncu2.Width, Oyuncu2.Height); Rectangle TopRect = new Rectangle((int)TopYer.X, (int)TopYer.Y, Top.Width, Top.Height);
Yapmamız gereken, Top‘un Oyuncu 1 veya Oyuncu 2 ile kesiştiği durumda yönünü ters çevirmek. Ayrıca eğer Oyuncu 1 veya Oyuncu 2‘nin arkasına geçerse diğer oyuncunun skor‘unu bir artırmak ve Top‘un yerini sıfırlamak;
if (TopRect.Intersects(Oyuncu1Rect) || TopRect.Intersects(Oyuncu2Rect))
TopYon.X *= -1;
if (TopYer.X < Oyuncu1Yer.X)
{
Oyuncu2Skor++;
TopYer.X = graphics.GraphicsDevice.Viewport.Width / 2;
}
if (TopYer.X > Oyuncu2Yer.X)
{
Oyuncu1Skor++;
TopYer.X = graphics.GraphicsDevice.Viewport.Width / 2;
}
TopYer += TopYon;
Şu anda elimizde oynayabileceğimiz bir Pong oyunu var. Her iki oyuncu için skor bilgisini de tutuyoruz. Fakat skor’u ekrana yazdırmadık.
Ekrana skor yazdırma işini bir sonraki yazıya bırakıyorum. Oyunun kodlarını da bir sonraki yazıda veriyor olacağım.
Yazdığınız bir sınıftan kalıtım yoluyla başka sınıflar üretilmesini engellemek istiyor olabilirsiniz.
Yapmanız gereken sınıfınızı sealed anahtar kelimesi ile “mühürlemek” olmalıdır. Böylece sınıfınızdan yeni sınıflar türetilemeyecektir.
sealed class AnaSinif
{
// Sınıf üyeleri
}
AnaSinif class‘ımız sealed olduğu için, yeni sınıf türetilirken base class olamayacaktır;
class TuretilmisSinif : AnaSinif
{
// Derleme zamanında hata oluşur (compile-time error)
}
Not : struct’lar her zaman sealed ile mühürlenmiş gibi davranırlar. struct’lar kalıtım (inheritance) desteklemez
Tüm sınıfın kalıtım yoluyla aktarılmasını engellemek yerine, tek bir method’un override edilmesini engellemek istiyor olabilirsiniz.
Bu durumda yapmanız gereken, sadece ilgili method‘u sealed ile “mühürlemek” olmalıdır;
class AnaSinif
{
public virtual void Goster()
{
}
}
class TuretilmisSinif : AnaSinif
{
// Bu kodda problem yok
// AnaSinif'tan gelen Goster() method'unu override eder
// Aynı zamanda sealed ile "mühürler"
public sealed override void Goster()
{
}
}
class TekrarTuretilmisSinif : TuretilmisSinif
{
// Bu kod derlenmez. Hata oluşur
// TuretilmisSinif class'ında Goster() method'u sealed anahtar kelimesi ile "mühürlenmişti"
public override void Goster()
{
}
}
Bu yazımı okumadan önce XNA konusundaki diğer makalelerimi okumanızı öneririm.
Öncelikle ihtiyacınız olacak iki görseli buradan indirebilirsiniz;
Yapmak istediğimiz;
Hemen başlayalım, ilk olarak yeni bir XNA projesi oluşturalım. Game1.cs dosyasının adını GameLoop.cs olarak değiştirelim.
Uzay.jpg ve UzayGemisi.png dosyalarını Content içerisine sürükleyip bırakalım. GameLoop.cs dosyasını açarak kod yazmaya başlayalım;
Sabitlerimizi class seviyesinde const ve readonly field’larda tanımlayalım;
private const int PENCERE_GENISLIK = 800; private const int PENCERE_YUKSEKLIK = 600; private const string PENCERE_BASLIK = "XNA - Uzay'da UzayGemisi Yönetelim"; private const bool TAM_EKRAN = false; private readonly Color ARKAPLAN_RENK = Color.Black;
GameLoop class‘ının constructor‘ında bu sabitleri kullanalım;
graphics.PreferredBackBufferWidth = PENCERE_GENISLIK; graphics.PreferredBackBufferHeight = PENCERE_YUKSEKLIK; graphics.IsFullScreen = TAM_EKRAN; this.Window.Title = PENCERE_BASLIK;
Uzay görselimizi 800 x 600 boyutlarındaki oyun penceremize sığdırmak için class seviyesinde Rectangle tipinde bir değişken tanımlayalım, Uzay ve UzayGemisi görsellerimiz için de birer tane Texture2D tipinde değişken tanımlayalım;
Rectangle Pencere; Texture2D Uzay; Texture2D UzayGemisi;
LoadContent() method’unda bu değişkenlerin değerlerini atayalım;
Pencere = new Rectangle(0, 0, PENCERE_GENISLIK, PENCERE_YUKSEKLIK);
Uzay = Content.Load<Texture2D>("Uzay");
UzayGemisi = Content.Load<Texture2D>("UzayGemisi");
Artık Uzayımızı ve UzayGemimizi oyun penceresine çizebiliriz. Ama madem uzay gemisini klavye tuşları ile yönetmek istiyoruz, o zaman uzay gemisinin kendi çevresinde dönebilmesini de sağlamamız gerekir.
Eğer bunu yapmazsak, Yukarı tuşu ile yukarı giden uzay gemisi, Aşağı tuşu ile aşağı gelirken yönünü düzeltmez, geri geri geliyormuş gibi gözükür. Hatta yanlara ve çağrazlara giderken iyice anlamsız görünmeye başlar.
Öncelikle uzay gemisinin o anda oyun penceresinin neresinde olduğunu tutacağımız Vector2 sınıfında bir değişkene class seviyesinde ihtiyacımız var, ayrıca uzay gemisinin gideceği yöne göre yönelmesi için, iki değişkene daha ihtiyacımız olacak;
Vector2 Konum = Vector2.Zero; Vector2 Merkez; float Yonelme = 0;
Uzay gemisinin doğru bir yönelme yapabilmesi için, ağırlık merkezini doğru vermemiz gerekiyor, LoadContent() methoduna aşağıdaki kodu ekleyelim;
Merkez = new Vector2(UzayGemisi.Width / 2, UzayGemisi.Height / 2);
Önce Draw() methodumuzu yazalım;
GraphicsDevice.Clear(ARKAPLAN_RENK); spriteBatch.Begin(SpriteBlendMode.AlphaBlend); spriteBatch.Draw(Uzay, Pencere, Color.White); spriteBatch.Draw(UzayGemisi, Konum, null, Color.White, Yonelme, Merkez, 1, SpriteEffects.None, 0); spriteBatch.End(); base.Draw(gameTime);
Son olarak Update() methodumuzu yazalım;
Öncelikle klavyenin o andaki durumunu tutacağımız değişkenimizi tanımlıyoruz;
KeyboardState ks = Keyboard.GetState();
Eğer Escape tuşuna basılıyorsa, oyunda çıkıyoruz;
if (ks.IsKeyDown(Keys.Escape)) this.Exit();
Eğer hem Yukarı, hem de Sağa tuşlarına basılıyorsa, uzay gemisinin X ve Y koordinatlarında güncellemeler yapıp, yönelmesini 45 derecenin radian karşılığına eşitliyoruz;
if (ks.IsKeyDown(Keys.Up) && ks.IsKeyDown(Keys.Right))
{
Konum.Y -= 3;
Konum.X += 3;
Yonelme = MathHelper.ToRadians(45);
}
MathHelper.ToRadians() parametre olarak derece cinsinden değer alır ve geriye float cinsinden radian döner.
Update() methodunun geri kalanında yön tuşlarına göre uzay gemisinin koordinatlarını ve yönelmesini güncelliyoruz;
if (ks.IsKeyDown(Keys.Up) && ks.IsKeyDown(Keys.Right))
{
Konum.Y -= 3;
Konum.X += 3;
Yonelme = MathHelper.ToRadians(45);
}
else if (ks.IsKeyDown(Keys.Up) && ks.IsKeyDown(Keys.Left))
{
Konum.Y -= 3;
Konum.X -= 3;
Yonelme = MathHelper.ToRadians(315);
}
else if (ks.IsKeyDown(Keys.Down) && ks.IsKeyDown(Keys.Right))
{
Konum.Y += 3;
Konum.X += 3;
Yonelme = MathHelper.ToRadians(135);
}
else if (ks.IsKeyDown(Keys.Down) && ks.IsKeyDown(Keys.Left))
{
Konum.Y += 3;
Konum.X -= 3;
Yonelme = MathHelper.ToRadians(225);
}
else if (ks.IsKeyDown(Keys.Up))
{
Konum.Y -= 3;
Yonelme = MathHelper.ToRadians(0);
}
else if (ks.IsKeyDown(Keys.Down))
{
Konum.Y += 3;
Yonelme = MathHelper.ToRadians(180);
}
else if (ks.IsKeyDown(Keys.Left))
{
Konum.X -= 3;
Yonelme = MathHelper.ToRadians(270);
}
else if (ks.IsKeyDown(Keys.Right))
{
Konum.X += 3;
Yonelme = MathHelper.ToRadians(90);
}
Son olarak Update() methodunda uzay gemisinin pencereden dışarı çıkmasını engelleyecek kontrol kodlarını da yazıyoruz;
if (Konum.X < 0) Konum.X = 0; if (Konum.X > PENCERE_GENISLIK - UzayGemisi.Width) Konum.X = PENCERE_GENISLIK - UzayGemisi.Width; if (Konum.Y < 0) Konum.Y = 0; if (Konum.Y > PENCERE_YUKSEKLIK - UzayGemisi.Height) Konum.Y = PENCERE_YUKSEKLIK - UzayGemisi.Height;
“Oyun” projemizin kodlarını buradan bilgisayarınıza indirebilirsiniz.
Projeyi çalıştırdığınızda aşağıdaki gibi bir sonuç almanız lazım;
System.IO namespace‘inde yer alan Path class‘ının
GetInvalidFileNameChars()
GetInvalidPathChars()
methodlarını kullanarak dosya veya dizin isimlendirirken kullanmamanız gereken karakterleri bulabilirsiniz.
Her iki method’dan da geriye char[] döner.
MSDN’de şuradaki makaleden GetInvalidFileNameChars() methodu ile ilgili ayrıntılı bilgiye ulaşabilirsiniz.
MSDN’de şuradaki makaleden GetInvalidPathChars() methodu ile ilgili ayrıntılı bilgiye ulaşabilirsiniz.
Yazdığımız uygulamalardan aynı anda sadece bir tane açık olmasını isteyebiliriz. Bunu garantilemek için, yapmamız gereken process’ler arası iletişim kanalı oluşturmak ve kullanmak olmalıdır.
C# dilinde process’ler arası iletişim (cross-process communication) Mutex sınıfı ile sağlanır.
Mutex sınıfının kullanımını hemen bir örnek ile inceleyelim;
[STAThread]
static void Main()
{
bool AcikUygulamaVar = false;
Mutex m = new Mutex(true, "UygulamanınAdı", out AcikUygulamaVar);
if (AcikUygulamaVar)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
else
{
MessageBox.Show("Uygulamadan aynı anda bir tane açabilirsiniz!");
}
}
Mutex sınıfı ile ilgili daha detaylı bilgiye MSDN‘deki şu makaleden ulaşabilirsiniz.
.Net 4.0 COM İyileştirmeleri başlığı altında birçok yeni yeteneğe sahiptir. Şubat ayında verdiğim seminerlerden C# 4.0 Yenilikleri – 2 seminerinde COM İyileştirmeleri başlığında özellikle bu yeniliklerden bahsettim.
BilgeAdam‘daki bir öğrencimin sorusu üzerine bu yazımda Excel ve Word kullanımına ilişkin bir örnek yapacağım.
Öncelikle yeni bir Console Application projesi oluşturalım ve referanslara
referanslarını ekleyelim.
Bu örnekte yapmak istediğimiz;
Hazırsanız, Program.cs dosyamıza aşağıdaki kodları yazmakla başlayalım;
using direktiflerini yazdığımz yere
using Excel = Microsoft.Office.Interop.Excel; using Word = Microsoft.Office.Interop.Word; using System.Diagnostics;
satırlarını ekleyelim
Yeni bir Excel dosyası oluşturmak ve görünür kılmak için;
var excel = new Excel.Application(); excel.Visible = true;
Bu Excel dosyasına yeni bir sheet eklemek ve tablonun başlıklarını yazmak için;
excel.Workbooks.Add(); excel.Cells[1, 1].Value = "Uygulama Adı"; excel.Cells[1, 2].Value = "Hafıza Kullanımı";
Tabloya en çok hafıza kullanan uygulamaları eklemek için;
int i = 2;
foreach (var p in Process.GetProcesses().OrderByDescending(p => p.WorkingSet64).Take(10))
{
excel.Cells[i, 1].Value = p.ProcessName;
excel.Cells[i, 2].Value = p.WorkingSet64;
i++;
}
Tabloyu Excel dosyasında yeni bir sheet içerisine chart olarak eklemek için;
Excel.Range range = excel.Cells[1, 1]; Excel.Chart chart = excel.ActiveWorkbook.Charts.Add(After: excel.ActiveSheet); chart.ChartWizard(Source: range.CurrentRegion, Title: Environment.MachineName + " Toplam Hafıza Kullanımı"); chart.ChartStyle = 45;
Tabloyu panoya kopyalamak, yeni bir Word dosyası açıp, içine yapıştırmak için;
chart.CopyPicture(Excel.XlPictureAppearance.xlScreen, Excel.XlCopyPictureFormat.xlBitmap, Excel.XlPictureAppearance.xlScreen); var word = new Word.Application(); word.Visible = true; word.Documents.Add(); word.Selection.Paste();
Tüm kodları tekrar yazarsak;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Excel = Microsoft.Office.Interop.Excel;
using Word = Microsoft.Office.Interop.Word;
using System.Diagnostics;
namespace COMIyilestirmeleri_OfficeUygulamasi
{
class Program
{
static void Main(string[] args)
{
var excel = new Excel.Application();
excel.Visible = true;
excel.Workbooks.Add();
excel.Cells[1, 1].Value = "Uygulama Adı";
excel.Cells[1, 2].Value = "Hafıza Kullanımı";
int i = 2;
foreach (var p in Process.GetProcesses().OrderByDescending(p => p.WorkingSet64).Take(10))
{
excel.Cells[i, 1].Value = p.ProcessName;
excel.Cells[i, 2].Value = p.WorkingSet64;
i++;
}
Excel.Range range = excel.Cells[1, 1];
Excel.Chart chart = excel.ActiveWorkbook.Charts.Add(After: excel.ActiveSheet);
chart.ChartWizard(Source: range.CurrentRegion, Title: Environment.MachineName + " Toplam Hafıza Kullanımı");
chart.ChartStyle = 45;
chart.CopyPicture(Excel.XlPictureAppearance.xlScreen, Excel.XlCopyPictureFormat.xlBitmap, Excel.XlPictureAppearance.xlScreen);
var word = new Word.Application();
word.Visible = true;
word.Documents.Add();
word.Selection.Paste();
}
}
}
Neden olduğunu anlayamadığım bir sebepten dolayı Microsoft tablodaki bir kolonun ismini değiştirmek için bir tool sunmuyor.
Peki bir kolonun ismini değiştirmek istersek ne yapmalıyız?
MSDN‘de yer alan şu makalede anlatıldığı gibi, sp_rename stored procedure‘ünü kullanabiliriz.
Örneğin;
EXEC sp_rename 'TabloAdi.KolonAdi', 'YeniKolonAdi', 'COLUMN';
Üçüncü parametrenin alabileceği diğer değerler;
COLUMN : Bir kolonun yeniden isimlendirileceğini belirtir
DATABASE : Veritabanının yeniden isimlendirileceği durumda kullanılır
INDEX : Kullanıcının oluşturduğu index yeniden isimlendirileceğinde kullanılır
FileStream sınıfına yazacağımız Save() method’u sayesinde, aşağıdaki kodu kolaylıkla yazabilir olacağız. Üstelik bir tane de overload yazarak, varolan dosyanın üstüne yazmasını engelleyip, yeni bir dosya adı oluşturup yazma işlemine devam ettirebileceğiz.
fs.Kaydet("c:\\dosya_adi.uzanti");
Eğer aynı kodu, ikinci bir boolean parametreye true değeri vererek çağırırsak, klasörde dosya_adi.uzanti dosyası varsa dosya_adi[1].uzanti dosyasına yazmayı deneyecek, eğer bu dosya da varsa, dosya_adi[2].uzanti dosyasına deneyecek, vs..
fs.Kaydet("c:\\dosya_adi.uzanti", true);
İşte kodumuz;
namespace ExtensionManager
{
public static class Extensions
{
public static string Kaydet(this FileStream Dosya, string Dizin)
{
return Dosya.Kaydet(Dizin, false);
}
public static string Kaydet(this FileStream Dosya, string Dizin, bool UstuneYaz)
{
int DosyaSayac = 1;
string _Dizin = Path.GetDirectoryName(Dizin);
if (!Directory.Exists(_Dizin))
Directory.CreateDirectory(_Dizin);
int DosyaBoyu = Convert.ToInt32(Dosya.Length);
string DosyaAdi = Path.GetFileName(Dosya.Name);
Byte[] b = new Byte[DosyaBoyu];
Dosya.Read(b, 0, DosyaBoyu);
string root = Path.GetDirectoryName(Dizin) + "\\" + Path.GetFileNameWithoutExtension(Dizin);
while (!UstuneYaz && File.Exists(Dizin))
Dizin = root + "[" + DosyaSayac++.ToString() + "]" + Path.GetExtension(Dizin);
File.WriteAllBytes(Dizin, b);
return Path.GetFileName(Dizin);
}
}
}
BilgeAdam Kadıköy Şubesinde gerçekleştirdiğim Şubat Seminerlerinin sonuncusu XNA Game Studio prezentasyonuna buradan erişebilirsiniz.
Bu seminerde değindiğim konular;
C# tarafında rastgele sayıya ihtiyacımız olduğunda Random class’ından yeni bir nesne üretip kullanabiliyoruz. Eğer rastgele sayıya Sql tarafında ihtiyacımız olursa yapmamız gereken, RAND() fonksiyonunu kullanmaktır.
RAND() fonksiyonu ile ilgili detaylı bilgiye MSDN‘de yeralan şu makaleden ulaşabilirsiniz.
RAND([seed]) fonksiyonu parametre olarak seed değeri alabilir ve geriye float tipinde sonuç döner.
seed parametresi int, smallint veya tinyint tipinde olabilir.
RAND() fonksiyonu aynı seed değeri ile her çalıştırıldığında aynı “rastgele” sayıyı döndürür. Eğer seed verilmezse, Sql Server rastgele bir seed değeri atayarak, “rastgele” sayı oluşturur.
Eğer RAND() fonksiyonundan float tipinde noktalı sayı değil, int tipinde tamsayı dönmesini istiyorsak, basit bir convert işlemine tabi tutabiliriz;
SELECT CONVERT(INT, RAND() * 100)
ASP.NET 4.0 ile aşağıdaki kod yardımıyla mobil kullanıcıları algılayabilir ve uygulamanın mobil sayfasına yönlendirebilirsiniz;
private static readonly Regex MobileRegex = new Regex(@"(nokia|sonyericsson|blackberry|IPHONE|samsung|sec-|windows ce|motorola|mot-|up.b|midp-)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
public bool IsMobile
{
get
{
HttpRequest r = HttpContext.Current.Request;
if (r.Browser.IsMobileDevice)
return true;
if (!string.IsNullOrEmpty(r.UserAgent) && MobileRegex.IsMatch(r.UserAgent))
return true;
return false;
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (IsMobile)
Response.RedirectPermanent("Mobile.aspx", true);
}
BilgeAdam Kadıköy Şubesinde gerçekleştirdiğim Şubat Seminerlerinin İleri Seviye C# prezentasyonuna buradan erişebilirsiniz.
Bu seminerde değindiğim konular;
Uygulamanızda sizin belirlediğiniz şablona göre rastgele üretilmiş bir string’e ihtiyaç duyarsanız, aşağıdaki kod işinizi görebilir;
Random r = new Random();
string KullanilabilecekKarakterler = "AzByCxDwEvFuGtHsIrJqKpLoMnNmOlPkQjRiShTgUfVeWdXcYbZa1234567890";
MatchEvaluator Rastgele = delegate (Match m) {
return KullanilabilecekKarakterler[r.Next(KullanilabilecekKarakterler.Length)].ToString();
};
Console.WriteLine(Regex.Replace("XXXX-XXXX-XXXX-XXXX", "X", Rastgele)); /// Lv2U-jHsa-TUep-NqKa
Console.WriteLine(Regex.Replace("Şifreniz : XXXX", "X", Rastgele)); /// Şifreniz : w6G0
Console.WriteLine(Regex.Replace("XXX.XXX-XX/XX", "X", Rastgele)); /// Fu8.c3Y-xT/6P
Console.WriteLine(Regex.Replace("XXXXXX", "X", Rastgele)); /// 8cPD2y
XNA ile geliştirdiğiniz oyunlar varsayılan olarak 800 x 600 boyutlarında bir pencerede oynatılır.
Eğer siz bu pencereyi boyutlandırmak ve hatta Tam Ekran seçeneği eklemek isterseniz yapmanız gereken, oyun sınıfınızın constructor‘ına aşağıdaki kodları eklemektir;
graphics.PreferredBackBufferWidth = 1024; /// Oyun penceresinin genişliği graphics.PreferredBackBufferHeight = 768; /// Oyun penceresinin yüksekliği graphics.IsFullScreen = true; /// Oyun pencerede mi oynatılacak, yoksa tam ekran mı olacak
Bu kodları XNA – Oyun Temelleri yazımda yaptığımız oyuna uygularsak;
public GameLoop()
{
this.Window.Title = "XNA - Oyun Temelleri";
graphics = new GraphicsDeviceManager(this);
graphics.PreferredBackBufferWidth = 1024;
graphics.PreferredBackBufferHeight = 768;
graphics.IsFullScreen = true;
Content.RootDirectory = "Content";
}
Base class‘ta tanımlanmış bir method‘u override etmemiz gerekiyor. Fakat method virtual yazılmamışsa, override edilemez. Türetilmiş class‘ta base class‘taki virtual olmayan method’u nasıl override edebiliriz?
Türetilmiş class’ta base class’taki method’u override etmek yerine new anahtar kelimesi ile baştan yazabiliriz. Böylece virtual yazılmamış ve dolayısıyla override edilemeyecek method’ları “bir çeşit” override etmiş oluruz.
class Base
{
public virtual void VirtualGoster()
{
Console.WriteLine(“Base.VirtualGoster”);
}
public void Goster()
{
Console.WriteLine(“Base.Goster”);
}
}
class Derived : Base
{
public override void VirtualGoster()
{
Console.WriteLine(“Derived.VirtualGoster”);
}
public new void Goster()
{
Console.WriteLine(“Derived.Goster”);
}
}
class Program
{
static void Main(string[] args)
{
Base base = new Derived();
base.VirtualGoster();
base.Goster();
Console.WriteLine();
Derived derived = new Derived();
derived.VirtualGoster();
derived.Goster();
}
}
Çıktı :
Derived.VirtualGoster
Base.Goster
Derived.VirtualGoster
Derived.Goster
XNA ile oyun geliştirmeye başlamadan önce, ekrana nasıl çizim yapabileceğimizi öğrenmemiz gerekiyor.
Not : Buradan ileriye devam etmeden önce XNA – Başlangıç yazımı okumanızı tavsiye ederim.
Öncelikle, ihtiyacımız olacak iki görseli bilgisayarınıza kopyalamanız gerekiyor;
Solution Explorer‘da Content üzerine sağ tuşla tıklayarak ari.png ve fil.png dosyalarını projeye ekleyelim.
GameLoop.cs dosyamızda class seviyesinde Texture2D tipinde iki değişken oluşturalım;
Texture2D ArkaPlan; Texture2D Ari;
Daha sonra bu değişkenlere resimleri yükleyeceğiz. Aynı yere bir tane de Rectangle tipinde değişken oluşturalım.
Rectangle OyunPencere;
Bu değişkene ekranımızın boyutlarını yüklüyor olacağız.
LoadContent() method’unda bu değişkenlerin değerlerini atayalım;
OyunPencere = new Rectangle(0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height);
ArkaPlan = Content.Load<Texture2D>("fil");
Ari = Content.Load<Texture2D>("ari");
GameLoop class’ının constructor‘ında oyunumuzun başlığını değiştirebiliriz;
public GameLoop()
{
this.Window.Title = "XNA - Oyun Temelleri";
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
Draw() method’unda resimlerin ekrana çizim işlerini yapacağız. Çizime işlemlerini Begin() ve End() methodları arasında yapmamız gerekiyor;
spriteBatch.Begin(SpriteBlendMode.AlphaBlend); spriteBatch.Draw(ArkaPlan, OyunPencere, Color.White); spriteBatch.Draw(Ari, Vector2D.Zero, Color.White); spriteBatch.End();
Bu durumda uygulamayı çalıştırırsak, karşımıza şöyle bir ekran gelir;
Şimdi arı resmini, klavye tuşlarını kullanarak ekranda hareket ettirelim. Öncelikle arı’nın ekrandaki konumunu tutan bir değişkene ihtiyacımız var, class seviyesindeki değişkenlere ekleyelim;
Vector2 Location = Vector2.Zero;
Draw() methodunda ari resmini çizdiğimiz satırı güncelleyelim;
spriteBatch.Draw(Ari, Location, Color.White);
Son olarak Update() method’umuzu güncelleyelim;
protected override void Update(GameTime gameTime)
{
KeyboardState ks = Keyboard.GetState();
if (ks.IsKeyDown(Keys.Escape))
this.Exit();
if (ks.IsKeyDown(Keys.Up))
Location.Y -= 3;
if (ks.IsKeyDown(Keys.Down))
Location.Y += 3;
if (ks.IsKeyDown(Keys.Left))
Location.X -= 3;
if (ks.IsKeyDown(Keys.Right))
Location.X += 3;
base.Update(gameTime);
}
Gördüğünüz gibi, klavyede o anda basılı tuşları Keyboard.GetState() ile ks değişkenine yüklüyoruz, sonra basit karşılaştırmalar ile Location değişkenimizin X ve Y değerlerini değiştiriyoruz.
Draw() method’unda ari’yi çizeceğimiz yer olarak Location değişkenini verdiğimiz için, klavyeyi kullanarak ari’yi hareket ettirebildiğimizi görüyoruz.
Oyunun kaynak kodlarını buradan indirebilirsiniz.
Senaryo : Uygulama çalışırken değeri değiştirilemeyecek değişken tanımlamanız gerekiyor.
Çözüm : Muhtemel iki çözüm var, const ve readonly değişken tanımlamak. Fakat aralarında önemli bir fark var;
const : Türkçe’ye Sabit olarak çevrilebilir. Class seviyesinde tanımlanır ve tanımlanma anında değeri verilmek zorundadır. Sonradan değeri değiştirilemez.
readonly : Sadece-Okunabilir anlamına gelir. Class seviyesinde tanımlanır. Tanımlandığı anda değeri verilebilir veya Class Constructor’ında değeri verilebilir. Sonradan değeri değiştirilemez.
public class Matematik
{
private const double PI = 3.14159;
}
public class Matematik
{
private readonly int PI; /// PI değişkeninin değerini burada da verebilirdim.
public Matematik()
{
PI = 22 / 7;
}
}
Mart 2010 ayı içerisinde BilgeAdam – Kadıköy Şube‘de Mart Ayı – Oyun Ayı seminerlerini veriyor olacağım.
Katılım ücretsizdir.