Keyboard.GetState | Engin Polat\'ın Windows 8 , Windows Phone 8 ve C# içerikli programcılık sitesi

Arşiv

Etiketlenen yazılar Keyboard.GetState

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

15 July 2011 1 yorum

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 July 2011 4 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 Oyunu / Çanakkale Geçilmez – 2

27 June 2011 Yorum yapılmamış

XNA ile Oyun Programlama serimize, daha önce başlayıp tamamlamadığımız Çanakkale Geçilmez oyununu tamamlayarak devam ediyoruz.

Bu yazıyı okumadan önce XNA konusunda diğer makaleler için XNA kategorisine bir göz atmanızı tavsiye ederim.

Düşman gemilerine yaptığımız atış miktarını ve isabet adedini tutacağımız iki değişkeni sınıf seviyesinde tanımlayalım;

int SKOR_ATIS = 0;
int SKOR_PUAN = 0;

Oyuna, düşman gemileri ve düşman gemilerine atacağımız gülleler eklemek için, sınıf seviyesinde GameObject sınıfında diziler oluşturacağız;

public GameObject[] Gemiler;
public GameObject[] Gulleler;

Ayrıca, düşman gemilerine ve onlara atacağımız güllelere sınırlama getirmek için iki sabiti (const) sınıf seviyesinde tanımlıyoruz;

public const int DUSMAN_ADET = 3;
public const int GULLE_ADET = 6;

Bu sayede, oyunun zorluk derecesini değiştirebilmek için iki alanımız oluyor; aynı anda savaşacağımız düşman gemisi adedi ve onlara atabileceğimiz gülle adedi. Aynı anda attığımız güllelerden bir tanesi hedefi bulmadan veya ekran dışına çıkmadan yeni gülle atamıyoruz.

Bu oyunda, düşman gemisi adedini 3 olarak, onlara aynı anda atabileceğimiz gülle adedini de 6 olarak belirledik.

LoadContent() methodunda bu değişkenlere başlangıç değerlerini atamalıyız;

Gemiler = new GameObject[DUSMAN_ADET];
for (int iLoop = 0; iLoop < DUSMAN_ADET; iLoop++)
{
	Gemiler[iLoop] = new GameObject(Content.Load<Texture2D>("DusmanGemi"));
}

Gulleler = new GameObject[GULLE_ADET];
for (int iLoop = 0; iLoop < GULLE_ADET; iLoop++)
{
	Gulleler[iLoop] = new GameObject(Content.Load<Texture2D>("Gulle"));
}

Update() method'unda boşluk tuşuna (Space) basılınca gülle atılmasını sağlayacak methodu çağıracak kodu ekliyoruz;

if (pks.IsKeyDown(Keys.Space) && ks.IsKeyUp(Keys.Space))
	GulleAtesle();

GulleAtesle() method’unda 6 gülle’nin herbirine tek tek bakarak, ekranda olmayan var mı kontrol ediyoruz.

Eğer o anda ekranda olmayan bir gülle bulursak (IsAlive özelliğinin false değer içermesinden) düşman gemisine doğru fırlatıyoruz.

Fırlatma işlemini yaparken güllenin fırlatma anındaki yeri ve fırlatma güzergahına dikkat etmeliyiz.

Güllenin Position özelliğine Top’umuzun X ve Y eksenindeki yerini veriyoruz, böylece, gülle tam olarak top’umuzun ucundan fırlatılacak.

Velocity özelliği ile güllenin güzergahını belirliyoruz; Top’umuzun baktığı açının sinus‘unu ve kosinus‘unu alarak, hız sabiti olan 5 değeri ile çarpıyoruz.

Not : Top’umuz ekranın altında, gemiler üstünde olduğu için Y eksenindeki hız sabitini -1 ile çarpıp, -5 değerini elde ediyoruz.

Ayrıca, SKOR_ATIS değişkeninin değerini de bir yükseltiyoruz.

private void GulleAtesle()
{
	foreach (GameObject Gulle in Gulleler)
	{
		if (!Gulle.IsAlive)
		{
			SKOR_ATIS++;
			Gulle.IsAlive = true;
			Gulle.Position = new Vector2(Top.Position.X - Gulle.Center.X, Top.Position.Y);
			Gulle.Velocity = new Vector2((float)Math.Sin(Top.Rotation) * 5, (float)Math.Cos(Top.Rotation) * -5);
			break;
		}
	}
}

Böylece, her boşluk (Space) tuşuna basıldığında 6 gülleden birisi topumuzun ucundan düşman gemisine doğru gönderilecektir. Eğer o anda ekranda 6 gülle varsa, gülle gönderilmeyecektir.

Update() method’unda, düşman gemilerini de yönetiyoruz;

foreach (GameObject Gemi in Gemiler)
{
	if (Gemi.IsAlive)
	{
		Gemi.Position += Gemi.Velocity;

		if (Gemi.Position.X < 0)
			Gemi.IsAlive = false;
	}
	else
	{
		Gemi.IsAlive = true;
		Gemi.Position = new Vector2(PENCERE_GENISLIK, MathHelper.Lerp(0, (float)(PENCERE_YUKSEKLIK * 0.6), (float)Rastgele.NextDouble()));
		Gemi.Velocity = new Vector2(MathHelper.Lerp(-2, -4, (float)Rastgele.NextDouble()), 0);
	}
}

Tüm düşman gemileri (DUSMAN_ADET sabitinden dolayı 3 adet) içerisinde dönen bir foreach döngüsü ile ilgili düşman gemisinin o anda hayatta olup/olmadığına bakıyoruz;

Eğer hayatta ise; gemi'nin yerini, gidiş yönünde hızı kadar ilerletiyoruz. Eğer gemi'nin yeni yeri pencere dışında ise, bir sonraki ekran güncellemesinde gemi'yi tekrar kullanabilmek için öldürüyoruz.

Eğer hayatta değilse; Gemi'yi ekrana çıkartabilmek için hayatta durumuna getiriyoruz, rastgele bir yer ve hız veriyoruz.

Rastgele yer belirlerken, pencerenin en üstünden itibaren %60'lık kısmını kullanıyoruz.

Rastgele hız belirlerken, MathHelper sınıfının Lerp() methodundan faydalanıyoruz.

Lerp() method'u, 3 parametre alır;

  • Değer 1 (Kaynak değer)
  • Değer 2 (Kaynak değer)
  • Büyüklük (0 ile 1 arası değer, Değer 2'nin ağırlığı)

Büyüklük parametresine 0 değer vermek, Değer 1'i, 1 değer vermek, Değer 2'yi döndürür.

Biz bu örnek'te düşman gemilerinin ekranın sağında belirmesi ve ekranın soluna doğru ilerlemesi için, -2 ve -4 arası hız'a sahip olmalarını sağladık.

Update() method'unda, ekrandaki gülleleri de yönetiyoruz;

foreach (GameObject Gulle in Gulleler)
{
	if (Gulle.IsAlive)
	{
		Gulle.Position += Gulle.Velocity;
		if (!Pencere.Contains(Gulle.TextureRectangle))
			Gulle.IsAlive = false;

		foreach (GameObject Gemi in Gemiler)
		{
			if (Gemi.TextureRectangle.Contains(Gulle.TextureRectangle))
			{
				SKOR_PUAN++;
				GemiVurulduSes.Play();
				Gemi.IsAlive = false;
				Gulle.IsAlive = false;
				break;
			}
		}
	}
}

Sadece hayatta olan güllelere teker teker bakıyoruz; (GULLE_ADET sabitinden dolayı en fazla 6 adet)

Gülle’nin yerini, hızı ve doğrultusu kadar ilerletiyoruz. Eğer pencere dışına çıktı ise, gülle’yi öldürüyoruz.

Hayatta olan her gülle için, hayatta olan her gemi ile çarpışma testi yapıyoruz. Eğer ilgili gülle gemi’lerden bir tanesi ile çarpışıyorsa, gülle’yi ve gemi’yi öldürüp, SKOR_PUAN değişkenini bir yükseltiyoruz.

Draw() method’unda, Arkaplan, Top, hayatta olan gemiler ve hayatta olan gülleleri ekrana çizdiriyoruz;

GraphicsDevice.Clear(Color.CornflowerBlue);

spriteBatch.Begin(SpriteBlendMode.AlphaBlend);

spriteBatch.Draw(Arkaplan, Pencere, Color.White);

spriteBatch.Draw(Top.Texture, Top.Position, null, Color.White, Top.Rotation, Top.Center, 1, SpriteEffects.None, 0);

foreach (GameObject Gemi in Gemiler)
{
	if (Gemi.IsAlive)
	{
		spriteBatch.Draw(Gemi.Texture, Gemi.Position, Color.White);
	}
}

foreach (GameObject Gulle in Gulleler)
{
	if (Gulle.IsAlive)
	{
		spriteBatch.Draw(Gulle.Texture, Gulle.Position, Color.White);
	}
}

Skor tablosunu çizdirebilmek için, sınıf seviyesinde iki yeni değişken eklememiz lazım;

Texture2D Karakterler;
Texture2D Sayilar;

LoadContent() method’unda bu değişkenlere değer atıyoruz;

Karakterler = Content.Load("Karakterler");
Sayilar = Content.Load("Sayilar");

Karakterler imajı’nın (0, 0) noktasından itibaren (113, 25) büyüklüğündeki alanı arasında kalan kısmı ekrana çizdirmek için, Draw() method’una;

spriteBatch.Draw(Karakterler, new Vector2((float)(PENCERE_GENISLIK * 0.05), (float)(PENCERE_YUKSEKLIK * 0.90)), new Rectangle(0, 0, 113, 25), Color.White);

Karakterler imajı’nın (0, 25) noktasından itibaren (113, 25) büyüklüğündeki alanı arasında kalan kısmı ekrana çizdirmek için, Draw() method’una;

spriteBatch.Draw(Karakterler, new Vector2((float)(PENCERE_GENISLIK * 0.75), (float)(PENCERE_YUKSEKLIK * 0.90)), new Rectangle(0, 25, 113, 25), Color.White);

Atış adedimizi ve Skor adedimizi ekrana çizdirmek için gerekli method çağrılarını (DrawAtis(), DrawSkor()) Draw() method’unda yapıyoruz.

private void DrawAtis()
{
	string Atis = SKOR_ATIS.ToString();
	for (int iLoop = 0; iLoop < Atis.Length; iLoop++)
	{
		int Rakam = Convert.ToInt32(Atis.Substring(iLoop, 1));
		spriteBatch.Draw(Sayilar, new Vector2((float)(PENCERE_GENISLIK * 0.05) + (23 * iLoop) + 120, (float)(PENCERE_YUKSEKLIK * 0.90)), new Rectangle(Rakam * 23, 0, 23, 25), Color.White);
	}
}

private void DrawSkor()
{
	string Atis = SKOR_PUAN.ToString();
	for (int iLoop = 0; iLoop < Atis.Length; iLoop++)
	{
		int Rakam = Convert.ToInt32(Atis.Substring(iLoop, 1));
		spriteBatch.Draw(Sayilar, new Vector2((float)(PENCERE_GENISLIK * 0.75) + (23 * iLoop) + 120, (float)(PENCERE_YUKSEKLIK * 0.90)), new Rectangle(Rakam * 23, 0, 23, 25), Color.White);
	}
}

Böylece, oyunumuzun kodlamasını bitirmiş olduk.

XNA ile Oyun Programlama - Çanakkale Geçilmez Oyunu

Oyunu tüm kodlarını buradan indirebilirsiniz.

XNA ile Pong oyunu yazalım – 1

07 March 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.