Arşiv

Etiketlenen yazılar update

XNA oyunlarında saniyedeki kare sayısını (FPS) hesaplamak

15 Temmuz 2011 Yorum yapılmamış

Hemen her oyun’da, saniyede çizilen ekran sayısı (FPSFrame Per Second) bilgisi oyun penceresinde gösterilir.

FPS nedir?

FPS, oyunun bir saniye içerisinde oyun penceresine çizebildiği ekran sayısıdır. Bizim animasyon olarak gördüğümüz akışlar aslında ardı ardına hızlı bir şekilde çizilen tek kare resimlerdir.

Sinema filmleri bile aslında ekranda sırayla gösterilen tek kare resimlerden oluşmaktadır.

İnsan gözü, saniye 25 kare’den büyük hızlarda tek kare resimleri, bir akış olarak algılar.

XNA Framework, saniyede 60 kare ekran çizmeye çalışır.

Oyunlarımızda FPS nasıl hesaplarız?

Formül aslında basit, Draw() method’unda bir değişkenin değerini 1 arttıracağız. Update() method’unda her saniye geçişinde değişkeni sıfırlayacağız.

FPS bilgisini ekranda nasıl gösteririz?

Draw() method’unda değişkenin değerini ekranda gösterirsek, bir saniye içerisinde kaç defa Update() method’unun çalıştırıldığını, yani saniyedeki ekran sayısını (FPS) göstermiş oluruz.

Şimdi yazacağımız örnek projede, klavyeden boşluk (space) tuşuna basıldığında FPS bilgisini ekranda göstereceğiz, tekrar basıldığında gizleyeceğiz.

Örnek proje

Öncelikle sınıf seviyesinde değişkenlerimizi oluşturalım;

int SaniyedeKareSayisi = 0;
double FPS = 0;
bool DetayGoster = false;
KeyboardState pks;

Update() method’unda FPS hesaplayalım;

KeyboardState ks = Keyboard.GetState();

if (pks.IsKeyDown(Keys.Space) && ks.IsKeyUp(Keys.Space))
{
	DetayGoster = !DetayGoster;
}

if (DetayGoster && gameTime.TotalGameTime.Milliseconds == 0)
{
	FPS = SaniyedeKareSayisi;
	SaniyedeKareSayisi = 0;
}

pks = ks;

Oyun penceresinde yazı gösterebilmek için, SpriteFont sınıfından bir değişkene ihtiyacımız olacak.

SpriteFont Arial;

Content projemize Arial isminde bir SpriteFont dosyası ekleyelim.

XNA Oyun Programlama - FPS Hesaplama / SpriteFont Ekleme Dialog Kutusu

<?xml version="1.0" encoding="utf-8"?>
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
  <Asset Type="Graphics:FontDescription">
    <FontName>Arial</FontName>
    <Size>24</Size>
    <Spacing>0</Spacing>
    <UseKerning>true</UseKerning>
    <Style>Regular</Style>
    <CharacterRegions>
      <CharacterRegion>
        <Start>&#32;</Start>
        <End>&#126;</End>
      </CharacterRegion>
    </CharacterRegions>
  </Asset>
</XnaContent>

LoadContent() method’unda Arial değişkenimize değer atayalım;

Arial = Content.Load("Arial");

Draw() method’unda hesaplanan FPS bilgisini ekranda gösterelim;

spriteBatch.Begin();

if (DetayGoster)
{
	SaniyedeKareSayisi++;

	spriteBatch.DrawString(Arial, "FPS : " + FPS.ToString(), new Vector2(50, 50), Color.Black);
}

spriteBatch.End();

Artık oyun penceremizde saniyedeki ekran sayısını (FPS) gösterebiliriz.

XNA Oyun Programlama - FPS Hesaplama Sonucu

Oyunun kodlarını indirmek için tıklayınız.

XNA ile Karakter Hareketi

11 Temmuz 2011 2 yorum

Bu yazımı okumadan önce XNA ile Oyun Programlama konulu diğer yazılarımı okumanızı tavsiye ederim.

Her oyunda bir ana karakter vardır ve biz oyuncular olarak, bu ana karakteri mouse/klavye/joystik aracılığıyla oyun evreninde kontrol ederiz.

Bu yazımda önce bir oyun evreni oluşturacak, sonra da ana oyun karakterini bu evrende hareket ettireceğiz.

Önce oyunda kullanacağımız görselleri bilgisayarımıza indirelim;

XNA ile Oyun Programlama - Karakter Hareket Çim ArkaPlan XNA ile Oyun Programlama - Karakter Hareket Sprite

Öncelikle arkaplan ve ana karakterimiz için sınıf seviyesinde değişkenlerimizi oluşturalım;

Texture2D KarakterSprite;
Texture2D ArkaplanCim;

Klavye bilgisini alabilmek için KeyboardState sınıfından bir değişken ekleyelim;

KeyboardState ks;

Vector2 sınıfından bir değişken ile, ana karakterimizin oyun penceresinde konumunu tutalım;

Vector2 KarakterKonum;

Oyun sınıfının constructor‘ında (Game1 ismini GameLoop olarak değiştirelim) KarakterKonum değişkenine başlangıç değerini verelim;

public GameLoop()
{
	graphics = new GraphicsDeviceManager(this);
	Content.RootDirectory = "Content";

	KarakterKonum = new Vector2(50, 50);
}

LoadContent() method’unda ArkaplanCim ve KarakterSprite değişkenlerine değer atayalım;

protected override void LoadContent()
{
	spriteBatch = new SpriteBatch(GraphicsDevice);

	KarakterSprite = Content.Load<Texture2D>("KarakterSprite");
	ArkaplanCim = Content.Load<Texture2D>("Cim");
}

KarakterSprite görselinde, karakterimizin dört yöne yapacağı hareketlerin tek tek görüntüleri yer alıyor.

Karakterimize yürüme efekti vermek için, aslında birden fazla görselden oluşan tek bir görsel kullanıyoruz. (Böylece hafızaya tek bir görsel yüklendiği için hafıza kullanımını az tutmuş oluyoruz)

Sırayla görselin herbir parçasını ekranda karakterimiz olarak çizdiğimizde, karaktere yürüme efektini vermiş oluyoruz.

Bir Sprite‘ın bir parçasını ekrana çizdirmek için, SpriteBatch sınıfının Draw() method’undan faydalanırız;

SpriteBatch.Draw(Texture2D, Vector2, Rectangle, Color);

Bu method’un parametreleri;

  • Texture2D, ekrana çizdireceğimiz görselin bulunduğu görseli yüklediğimiz değişken
  • Vector2, görselin ekranda çizileceği konum
  • Rectangle, görselin ekrana çizilecek parçası (Left-Top-Width-Height isminde dört özelliği vardır)
  • Color, görsele uygulanacak baskın renk değişkeni

Sınıf seviyesine aşağıdaki değişkenleri ekleyerek devam edelim;

Rectangle Arkaplan;
Rectangle Karakter;

int Kare = 0;

int Yon = 0;

GameLoop sınıfının constructor‘ına;

Arkaplan = new Rectangle(0, 0, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight);

ekleyelim. Böylece, arkaplan görselinin çizileceği alanı tanımlamış olduk.

Oyun kodlarımızın en önemli iki methodundan biri, Update() method’udur;

ks = Keyboard.GetState();

if (ks.IsKeyDown(Keys.Escape))
{
	this.Exit();
}

if (ks.IsKeyDown(Keys.Down))
{
	Yon = 0;
	Kare++;
	KarakterKonum.Y += 3;
}
else if (ks.IsKeyDown(Keys.Up))
{
	Yon = 1;
	Kare++;
	KarakterKonum.Y -= 3;
}
else if (ks.IsKeyDown(Keys.Left))
{
	Yon = 2;
	Kare++;
	KarakterKonum.X -= 3;
}
else if (ks.IsKeyDown(Keys.Right))
{
	Yon = 3;
	Kare++;
	KarakterKonum.X += 3;
}

if (Kare > 5)
{
	Kare = 0;
}

Her bir yön tuşuna basıldığında Yon değişkenini farklı bir değere atadık. Ayrıca Kare değişkeninin değerini de bir artırdık.

KarakterSprite görselinde karakter’in yürüme efekti için yana doğru 6 görsel kullanıldığını görüyoruz. Kare değişkeni 5 değerinden büyük bir değere ulaştığında 0 değerine eşitleyip değişkeni sıfırlamış oluyoruz.

Her yön tuşuna basıldığında Yon değişkenine verdiğimiz değer, KarakterSprite görselinde ilgili tuşa ait yönün yukarıdan aşağıya sıra numarası aynı zamanda.

Son adımda, Draw() method’unu yazıyoruz;

GraphicsDevice.Clear(Color.CornflowerBlue);

Karakter = new Rectangle(Kare * 24, Yon * 32, 24, 32);

spriteBatch.Begin();

spriteBatch.Draw(ArkaplanCim, Arkaplan, Color.White);
spriteBatch.Draw(KarakterSprite, KarakterKonum, Karakter, Color.White);

spriteBatch.End();

Öncelikle Rectangle tipinde Karakter değişkenine, KarakterSprite değişkeninin hangi parçasını ekrana çizmek istediğimizi belirteceğimiz değeri atıyoruz.

Sonra arkaplan ve karakterimizi oyun penceresine çizdiriyoruz.

XNA ile Oyun Programlama - Karakter Hareket Oyun Ekranı

Oyunun kodlarını indirmek için tıklayınız.

XNA ile Hareketli Arkaplan

29 Haziran 2011 Yorum yapılmamış

Bu yazımı okumadan önce XNA ile Oyun Programlama kategorisindeki diğer makalelerimi okumanızı tavsiye ederim.

Birçok oyunda arkaplan görselinin yavaşça kaydığını görmüşüzdür. Bu tarz bir etkiyi kendi oyunlarımızda nasıl sağlayacağımızı bu yazımda inceliyor olacağım.

Her zamanki gibi öncelikle görselleri paylaşarak başlıyorum;

XNA ile Oyun Programlama - Uzay Arkaplan Resmi XNA ile Oyun Programlama - Uçak Resmi

Öncelikle sınıf seviyesinde birkaç değişken/sabit (readonly, const) ile oyun penceremizin özelliklerini ayarlayalım;

private const int PENCERE_GENISLIK = 800;
private const int PENCERE_YUKSEKLIK = 600;

private readonly Color PENCERE_ARKAPLAN = Color.Black;

Oyun sınıfının constructor‘ında ilgili sabitleri kullanalım;

graphics.PreferredBackBufferWidth = PENCERE_GENISLIK;
graphics.PreferredBackBufferHeight = PENCERE_YUKSEKLIK;

Oyun projemize, Uzay ve Ucak isimli iki tane sınıf (class) ekleyelim. Böylece arkaplan’da kayacak uzay görseli ile ilgili işleri Uzay sınıfında, klavye ile yöneteceğimiz uçak ile ilgili işleri de Ucak sınıfında gerçekleştirebileceğiz.

Ucak.cs dosyasında yeralan Ucak sınıfının yapacağı işler çok basit;

public class Ucak
{
	public Vector2 Position;
	public readonly Vector2 Size;

	public Texture2D Texture { get; private set; }

	public Ucak(Texture2D Texture)
	{
		this.Texture = Texture;
		this.Size = new Vector2(Texture.Width, Texture.Height);
	}
}

Uzay.cs dosyasında yeralan Uzay sınıfı ise, kendi Update() ve Draw() method’larına sahip olacak. Draw() method’unda sürekli arkaplan görselini kaydırarak oyun penceresine çizdirecek.

Bunu yapabilmek için, SpriteBatch sınıfından bir instance’a ihtiyaç duyacağız.

Uzay sınıfının constructor‘ında ihtiyacımız olacak SpriteBatch tipinden bir parametre alacak ve sınıf seviyesinde bir değişkende saklayacağız;

public class Uzay
{
	private readonly Texture2D _Texture;
	private readonly Texture2D _TextureSecond;

	private float _Position = 0f;

	private readonly int _Width;

	private readonly SpriteBatch _SpriteBatch;

	public Uzay(Texture2D Texture, SpriteBatch SpriteBatch)
	{
		this._SpriteBatch = SpriteBatch;

		this._Texture = Texture;
		this._TextureSecond = Texture;

		this._Width = _Texture.Width;

		this._Position = 0;
	}

	public void Update()
	{
		_Position -= 0.5f;

		if (_Position < -_Width)
		{
			_Position += _Width;
		}
	}

	public void Draw()
	{
		_SpriteBatch.Draw(_Texture, new Vector2(_Position, 0), Color.White);
		_SpriteBatch.Draw(_TextureSecond, new Vector2(_Position + _Width, 0), Color.White);
	}
}

Uzay sınıfının Update() method'unda, arkaplan görselini sürekli 0.5 birim sola kaydırıyoruz.

Not : Arkaplan görseli kaydıkça ekrandan dışarı çıkıyor olacak, arkaplansız kalmamak için aslında ekrana yanyana iki tane arkaplan görseli çizdiriyoruz.

Gelelim bu sınıflardan değişkenlerimizi oluşturmaya ve oyun sınıfımıza eklemeye;

private Uzay Arkaplan;
private Ucak SavasUcagi;

protected override void LoadContent()
{
	spriteBatch = new SpriteBatch(GraphicsDevice);

	Arkaplan = new Uzay(Content.Load<Texture2D>("Uzay"), spriteBatch);
	SavasUcagi = new Ucak(Content.Load<Texture2D>("Ucak"));
	SavasUcagi.Position = new Vector2(50, PENCERE_YUKSEKLIK / 2);
}

Oyunumuzun Update() method’unda, klavye tuş vuruş durumlarına göre uçağımızı kontrol ediyor olacağız. Ayrıca Arkaplan değişkeninde bulunan Uzay sınıfının instance‘ından Update() method’unu çağırıyor olacağız. Böylece arkaplan görseli 0.5 birim sola kaymış olacak ve oyun penceresine yeni yerinde çizilecek.

protected override void Update(GameTime gameTime)
{
	KeyboardState ks = Keyboard.GetState();

	if (ks.IsKeyDown(Keys.Escape))
		this.Exit();

	if (ks.IsKeyDown(Keys.Left))
		SavasUcagi.Position.X -= (ks.IsKeyDown(Keys.LeftShift) || ks.IsKeyDown(Keys.RightShift)) ? 6 : 3;

	if (ks.IsKeyDown(Keys.Right))
		SavasUcagi.Position.X += (ks.IsKeyDown(Keys.LeftShift) || ks.IsKeyDown(Keys.RightShift)) ? 6 : 3;

	if (ks.IsKeyDown(Keys.Up))
		SavasUcagi.Position.Y -= 3;

	if (ks.IsKeyDown(Keys.Down))
		SavasUcagi.Position.Y += 3;

	if (SavasUcagi.Position.X < 0)
		SavasUcagi.Position.X = 0;

	if (SavasUcagi.Position.X > PENCERE_GENISLIK - SavasUcagi.Size.X)
		SavasUcagi.Position.X = PENCERE_GENISLIK - SavasUcagi.Size.X;

	if (SavasUcagi.Position.Y < 0)
		SavasUcagi.Position.Y = 0;

	if (SavasUcagi.Position.Y > PENCERE_YUKSEKLIK - SavasUcagi.Size.Y)
		SavasUcagi.Position.Y = PENCERE_YUKSEKLIK - SavasUcagi.Size.Y;

	Arkaplan.Update();

	base.Update(gameTime);
}

Uçağı sağa/sola yönetmek için kullandığımız ok tuşlarına (LeftRight) basılırken, Shift tuşlarından birine (LeftShiftRightShift) basılıyorsa, uçağı normalin iki katı hızlı ilerletiyoruz (3 birim yerine 6 birim)

Son olarak, Draw() method’unda uçağı ekrana çizdirecek ve Uzay sınıfının instance‘ının (Arkaplan değişkeni) Draw() method’unu çağıracağız;

protected override void Draw(GameTime gameTime)
{
	GraphicsDevice.Clear(PENCERE_ARKAPLAN);

	spriteBatch.Begin();

	Arkaplan.Draw();
	spriteBatch.Draw(SavasUcagi.Texture, SavasUcagi.Position, Color.White);

	spriteBatch.End();

	base.Draw(gameTime);
}

Sonuç olarak, yukarıdaki kodları yazdıktan sonra oyun projemizi başlatırsak;

XNA ile Oyun Programlama - Hareketli Arka Plan Ekran Görüntüsü

Hareketli ArkaPlan oyun projemizin kodlarını buradan indirebilirsiniz.

XNA – Kısa sorular, Kısa cevaplar

28 Haziran 2011 1 yorum

Mouse ikonumu bulamıyorum?

Evet, varsayılan olarak XNA, oyun penceresi içerisinde mouse ikonunu gizler. Eğer mouse’u görmek istiyorsanız;

this.IsMouseVisible = true;

kodunu eklemeniz gerekir.

Oyunu farklı çözünürlükte çalıştırmak istiyorum

XNA ile oyun geliştirmeye çalışan her programcının çok kısa süre sonra merak ettiği bir sorudur bu.

Çözüm;

public Game1()
{
	graphics = new GraphicsDeviceManager(this);

	Content.RootDirectory = "Content";

	/// Oyun penceresinin çözünürlüğünü 1920x1080 ayarlar
	this.graphics.PreferredBackBufferWidth = 1920;
	this.graphics.PreferredBackBufferHeight = 1080;
}

Not : Bu konu ile ilgili XNA – Oyun ekranının boyutlarını belirlemek yazımı okumanızı tavsiye ederim.

Oyunumu tam ekran oynatmak istiyorum

Çözünürlüğü değiştirdikten hemen sonra, tam ekran oyun nasıl oynatılır? sorusu gelir;

protected override void Initialize()
{
	/// Eğer tam ekran değilse, tam ekran moduna geç!
	if (!graphics.IsFullScreen)
	{
		graphics.ToggleFullScreen();
	}

	base.Initialize();
}

Not : Bu konu ile ilgili XNA – Oyun ekranının boyutlarını belirlemek yazımı okumanızı tavsiye ederim.

Oyun penceremin aktif olup/olmadığını nasıl anlarım?

Windows oyunları o anda çalışan tek uygulama olmayabilirler. Oyuncular, oyun oynarken, email adreslerini kontrol etmek, internette bir kelime araştırmak veya diğer oyuncular ile farklı ortamlarda sohbet etmek isteyebilirler.

Oyun penceresinden başka bir uygulamaya geçtiklerinde (yani oyun penceresi focus kaybettiğinde) oynadıkları oyunun durmasını (pause moduna geçmesini) isterler.

Oyun penceresinin Active veya InActive olduğunu kontrol etmemiz, Active değilse, Pause moduna geçmemiz gerekmektedir;

Not : Bu konu ile ilgili XNA Oyunu / Çanakkale Geçilmez – 1 yazımı okumanızı tavsiye ederim.

protected override void Update(GameTime gameTime)
{
	if (this.IsActive)
	{
		/// Sadece oyun penceresi aktif iken yapılması gereken işleri
		/// buraya yazıyoruz

		/// Joystik, klavye, mouse hareketlerini algılamak
		/// Yapay zeka görevlerini yürütmek gibi
	}

	base.Update(gameTime);
}

Oyun penceresinin başlığını nasıl değiştiririm?

protected override void Initialize()
{
	this.Window.Title = "Oyun oynamak içindir!";

	base.Initialize();
}

XNA ile Pong oyunu yazalım – 2

11 Mart 2010 Yorum yapılmamış

XNA ile Pong oyunu yazalım – 1 yazıma bu yazı ile devam ediyorum.

XNA ile ekrana yazı yazdırmak için öncelikle Content projesi içerisinde bir spritefont dosyası oluşturmalıyız.

Pong projesi için ben Arial.spritefont ismini verdiğim dosyayı oluşturdum, “yorum satırları kaldırılmış halini” aşağıdaki gibi düzenledim;

<?xml version="1.0" encoding="utf-8"?>
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
	<Asset Type="Graphics:FontDescription">
		<FontName>Arial</FontName>
		<Size>16</Size>
		<Spacing>0</Spacing>
		<UseKerning>true</UseKerning>
		<Style>Regular</Style>
		<CharacterRegions>
			<CharacterRegion>
				<Start>&#32;</Start>
				<End>&#126;</End>
			</CharacterRegion>
		</CharacterRegions>
	</Asset>
</XnaContent>

Gördüğünüz gibi, font dosyası aslında font’un özelliklerini yazdığımız bir Xml dosyası.

GameLoop sınıfının değişkenlerine Arial font dosyamızı yükleyeceğimiz değişkeni de ekleyelim;

SpriteFont Arial;

LoadContent() method’unda Arial.spritefont dosyasını Arial değişkenine yükleyelim;

Arial = Content.Load<SpriteFont>("Arial");

Şimdi Draw() method‘una aşağıdaki kodları ekleyerek, oyuncuların skorlarını ekrana yazdıralım;

spriteBatch.DrawString(Arial, "Oyuncu 1 : " + Oyuncu1Skor, new Vector2((float)(PENCERE_GENISLIK * 0.05), 30), Color.Yellow);
spriteBatch.DrawString(Arial, "Oyuncu 2 : " + Oyuncu2Skor, new Vector2((float)(PENCERE_GENISLIK * 0.80), 30), Color.Yellow);

Bu kod parçası ile, spriteBatch değişkeninde yeralan DrawString() method’unu kullandık. DrawString() method’unun parametrelerine bakacak olursak;

  • Birinci parametre olarak, spritefont tipinde bir değişken alır
  • İkinci parametre, ekrana yazdırmak istediğimiz yazıdır
  • Üçüncü parametre olarak Vector2 tipinde yazıyı nereye yazacağımız bilgisini ister
  • Son olarak, yazının rengini verdiğimiz dördüncü parametre vardır

Biz, Pong oyununda ilk oyuncunun skorunu ekranın %5 kadar içine, ikinci oyuncunun skorunu ise ekranın %20 kadar içine yazdırdık.

Gelelim, oyunda ses çıkartmaya;

Öncelikle wav formatında iki ses dosyasını Content içerisine sürükleyip bırakalım.

Class seviyesindeki değişkenlere iki tane daha ekleyelim;

SoundEffectInstance ArkaplanSes;
SoundEffectInstance SkorSes;

LoadContent() method’unda bu değişkenlerin değerlerini atayalım;

ArkaplanSes = Content.Load<SoundEffect>("Pong").CreateInstance();
SkorSes = Content.Load<SoundEffect>("recycle").CreateInstance();

Gördüğünüz gibi, SoundEffectInstance tipinde iki değişken tanımladık. Bu değişkenlere Content içindeki ses dosyalarını yüklerken, SoundEffect tipinin CreateInstance() method‘unu kullandık.

Böylece ses değişkenlerimiz kullanıma hazır hale geldi.

LoadContent() method’una aşağıdaki kodları da ekleyerek, arkaplanda çalacak ses değişkeninin sesini %20 oranına düşürelim ve loop olmasını sağlayalım (Böylece ses dosyasının sonuna geldiğinde başa dönüp çalmaya devam edecek).

Son olarak Play() methodu ile, ses dosyasını çalmaya başlayalım;

ArkaplanSes.Volume = 0.2f;
ArkaplanSes.IsLooped = true;
ArkaplanSes.Play();

Update() method’unda oyuncuların skor kazandığı kodlara aşağıdaki satırı da ekleyelim;

SkorSes.Play();

Böylece oyuncular skor yaptıkça, SkorSes değişkeninde yüklü olan ses dosyası çalınacak.

İşte Pong oyunundan ekran görüntüsü. Oyunun kaynak kodlarını buradan indirebilirsiniz.

XNA Pong oyunun bitmiş hali

XNA ile Pong oyunu yazalım – 1

07 Mart 2010 6 yorum

Bu yazımı okumadan önce XNA konusundaki diğer makalelerimi okumanızı öneririm.

Her zamanki gibi, öncelikle ihtiyacımız olacak görselleri vereyim;

XNA - Pong Oyunu - Oyuncu 1 XNA - Pong Oyunu - Oyuncu 2 XNA - Pong Oyunu - Top

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.

XNA ile ekranda UzayGemisi yönetmek

06 Mart 2010 3 yorum

Bu yazımı okumadan önce XNA konusundaki diğer makalelerimi okumanızı öneririm.

Öncelikle ihtiyacınız olacak iki görseli buradan indirebilirsiniz;

XNA - Oyun Programlama - Uzay Arkaplanı XNA - Oyun Programlama - Uzay Gemisi

Yapmak istediğimiz;

  • 800 x 600 pencere içerisinde arkaplanda Uzay.jpg görselini göstermek
  • Pencerenin ortasına UzayGemisi.png dosyasını konumlandırmak
  • Klavyenin tuşlarına görevler atayarak, UzayGemisi‘ni Uzay içerisinde yönetmek

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;

XNA - Uzay Oyunu Sonuç Penceresi

XNA – Oyun Temelleri

22 Şubat 2010 Yorum yapılmamış

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;

Fil Resmi - Arkaplan olarak kullanılacak Arı Resmi

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;

XNA Oyun Temelleri

Ş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.

XNA Oyun Temelleri

Oyunun kaynak kodlarını buradan indirebilirsiniz.

XNA – Başlangıç

18 Şubat 2010 Yorum yapılmamış

XNA serimizin ikinci yazısında, Visual Studio 2008‘lerimizi açıyoruz ve yeni bir Windows Game projesi oluşturuyoruz.

Solution Explorer‘a baktığımızda, proje içindeki dosyaları görüyoruz.

XNA Projesi Solution Explorer Penceresi

XNA Oyununu çalıştırdığımızda, başlangıç noktası olarak Program.cs‘deki Program class’ının static void Main() methodu çalıştırılır.

Main() method’unun yaptığı iş basittir;

static void Main(string[] args)
{
	using (GameLoop game = new GameLoop())
	{
		game.Run();
	}
}

GameLoop class’ından instance oluşturup, Run() method’unu çağırır.

GameLoop class’ına bakarsak;

public class GameLoop : Microsoft.Xna.Framework.Game
{
	GraphicsDeviceManager graphics;
	SpriteBatch spriteBatch;

	public GameLoop()
	{
		graphics = new GraphicsDeviceManager(this);
		Content.RootDirectory = "Content";
	}

	protected override void Initialize()
	{
		base.Initialize();
	}

	protected override void LoadContent()
	{
		spriteBatch = new SpriteBatch(GraphicsDevice);
	}

	protected override void UnloadContent()
	{
	}

	protected override void Update(GameTime gameTime)
	{
		if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
			this.Exit();

		base.Update(gameTime);
	}

	protected override void Draw(GameTime gameTime)
	{
		GraphicsDevice.Clear(Color.CornflowerBlue);

		base.Draw(gameTime);
	}
}

LoadContent() method’u oyunda kullanacağımız grafikleri – sesleri – vs. hafızaya yüklediğimiz yerdir.

UnloadContent() method’u ise, LoadContent() method’unda yüklediğimiz kaynakları hafızadan sildiğimiz yerdir.

Oyun çalıştığı zaman LoadContent() method’u bir defa çalıştırılır. Oyun’dan çıkılırken de UnloadContent() method’u bir defa çalıştırılır.

Update() method’u, ekrana çizilecek nesnelerin, konum-boy-saydamlık-vs. değerlerinin hesaplandığı yerdir.

Draw() method’u ise, nesnelerin ekrana çizim işlemlerinin gerçekleştirildiği yerdir.

.Net Framework sabit olarak saniyede 60 kare çizim yapmayı hedefler. Update() ve Draw() method’larının saniyede 60 kere çalıştırılmasını beklemeliyiz.

Sql Server İstatistiklerin Son Güncellenme Zamanını Bulma

31 Ocak 2010 Yorum yapılmamış

İstatistikler, verinin veritabanı nesnelerinde (tablo, index, vs) nasıl dağıldığı bilgisini içerdiği için, veritabanında en önemli nesnelerden biridir.

Veritabanı Yöneticilerinin (Database Administrators) eskimiş istatistiklerden şikayetlerini çok duydum. Yapılması gereken istatistikleri güncellemektir.

Eğer bir tablodaki indexlere ait istatistiklerin son güncelleme zamanını öğrenmek istiyorsanız, aşağıdaki sql sorgusunu çalıştırabilirsiniz;

SELECT
	NAME AS INDEX_ADI,
	STATS_DATE(OBJECT_ID, INDEX_ID) AS SON_GUNCELLEME
FROM
	SYS.INDEXES
WHERE
	OBJECT_ID = OBJECT_ID('HumanResources.Department')

Eğer tüm indexler için aynı bilgiyi almak istiyorsanız, WHERE filtresini kaldırmanız yeterli.

Benim test bilgisayarımda aldığım sonuç;

PK_Department_DepartmenID 2010-01-20 15:30:17:200
AK_Department_Name 2010-01-20 15:30:26:053

Eğer istatistiklerinizin zamanı geçmiş olduğunu düşünüyorsanız ve güncellemek istiyorsanız, aşağıdaki sql komutunu çalıştırabilirsiniz;

UPDATE STATISTICS HumanResources.Department

Bu komutu çalıştırdığınızda ilgili tablonun istatistik verilerinin güncellendiğini göreceksiniz. Eğer komutu WITH FULLSCAN komutu ile birlikte çalıştırırsanız, tablodaki tüm kayıtlar baştan taranacak ve istatistik baştan oluşturulacaktır.

UPDATE STATISTICS HumanResources.Department
WITH FULLSCAN

Dikkat : İstatistikleri güncellemek için yukarıdaki komutları, sadece istatistiklerinizin gerçekten eskimiş olduğuna inandığınızda, sorgularınız için oluşturulan query plan’ların hatalı olduğunu gördüğünüzde ve sql server’ın yoğun olmadığı zamanlarda çalıştırmanızı tavsiye ederim.

Kendi test bilgisayarımda, istatistik güncelleme komutunu çalıştırdıktan sonra, aşağıdaki sonuçları elde ettim;

PK_Department_DepartmenID 2010-01-30 21:10:06:560
AK_Department_Name 2010-01-30 21:10:06:594

Gördüğünüz gibi, ilgili tablodaki indexlerin istatistikleri güncellendi.