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

Arşiv

Etiketlenen yazılar play

XNA Oyunu / Vahşi Batı

25 June 2012 3 yorum

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

Her zamanki gibi önce görseller;

XNA Oyun - Vahşi Batı - Cursor XNA Oyun - Vahşi Batı - Tombstone XNA Oyun - Vahşi Batı - Horse XNA Oyun - Vahşi Batı - Background

Bir tane silah sesi dosyamız var;

Magnum Gunshot

Bir tane de Sprite Font dosyamız var;

SkorFont.spritefont ismini verdiğim dosyanın, “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>Segoe UI Mono</FontName>
		<Size>18</Size>
		<Spacing>0</Spacing>
		<UseKerning>true</UseKerning>
		<Style>Regular</Style>
		<CharacterRegions>
			<CharacterRegion>
				<Start>&#32;</Start>
				<End>&#126;</End>
			</CharacterRegion>
		</CharacterRegions>
	</Asset>
</XnaContent>

Başlayalım oyunumuzu yazmaya; VahsiBati projemizi oluşturduktan ve Game1.cs‘in ismini GameLoop.cs olarak değiştirdikten sonra, Target isminde bir sınıf oluşturalım;

public class Target
{
	public const int FrameWidth = 104;

	public Vector2 Position;

	private Rectangle _Area = new Rectangle(0, 0, FrameWidth, FrameWidth);
	public Rectangle Area
	{
		get
		{
			_Area.X = (int)Position.X;
			_Area.Y = (int)Position.Y;

			return _Area;
		}
	}

	public bool ToLeft;

	public float RunSpeed;

	public int FrameIndex;

	public SpriteEffects SpriteEffect;

	public TimeSpan LastFrameChange = TimeSpan.Zero;

	public TimeSpan FrameChangeBuffer = TimeSpan.Zero;

	public bool IsDead = false;
}

Target sınıfı sayesinde, ekrana getireceğimiz hedef‘lerin ekranın neresinden çıkıp, hangi yöne doğru gideceğini bileceğiz, hedefin vurulup/vurulmadığını bileceğiz, çarpışma testi yapabilmek için ekranda kapladığı alanı bileceğiz, hızını bileceğiz, ayrıca hedef‘imizin harekete sahip olmasını sağlayabileceğiz (bknz; XNA ile Karakter Hareketi)

GameLoop.cs dosyasına geri dönelim, ilk önce arkaplanımızın hareketli olması için (bknz; XNA ile Hareketli Arkaplan) sınıf seviyesinde şu değişkenleri tanımlayalım;

Rectangle Screen;

Texture2D Background1;
Texture2D Background2;

Rectangle Background1Position;
Rectangle Background2Position;

GameLoop constructor‘ında Screen değişkenine;

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

LoadContent method’unda Background değişkenlerine değer atayalım;

Background1 = Content.Load<Texture2D>("Background");
Background2 = Content.Load<Texture2D>("Background");

Background1Position = new Rectangle(0, 0, Background1.Width, Background1.Height);
Background2Position = new Rectangle(Background1.Width, 0, Background2.Width, Background2.Height);

Update method’unda Background‘un yerini güncelleyelim;

Background1Position.X -= 1;
Background2Position.X -= 1;

if (Background1Position.X < -Background1.Width)
{
	Background1Position.X = Background2Position.X + Background2.Width;
}

if (Background2Position.X < -Background2.Width)
{
	Background2Position.X = Background1Position.X + Background1.Width;
}

Son olarak Draw method'unda Background'u ekrana çizelim;

spriteBatch.Begin();

spriteBatch.Draw(Background1, Background1Position, Color.White);
spriteBatch.Draw(Background2, Background2Position, Color.White);

spriteBatch.End();

Ekrana işaretçi çizdirmek için, sınıf seviyesinde aşağıdaki değişkenleri ekleyelim;

Texture2D Cursor;

Vector2 CursorPosition = Vector2.Zero;
Vector2 CursorCenter = Vector2.Zero;

Rectangle CursorZone;

MouseState ms;
MouseState pms;

GameLoop constructor‘ında CursorZone değişkenini dolduralım;

CursorZone = new Rectangle(0, 0, 5, 5);

LoadContent method‘unda Cursor değişkenlerine değer atayalım;

Cursor = Content.Load<Texture2D>("Cursor");
CursorCenter = new Vector2(Cursor.Width / 2, Cursor.Height / 2);

Update method‘unda işaretçinin ekranda görüntüleneceği yeri hesaplayalım;

ms = Mouse.GetState();

CursorPosition = new Vector2(ms.X, ms.Y);

pms = ms;

Draw method’unda Cursor nesnemizi ekrana çizdirelim;

spriteBatch.Draw(Cursor, CursorPosition, null, Color.White, 0f, CursorCenter, 0.6f, SpriteEffects.None, 0f);

Sınıf seviyesinde aşağıdaki değişkenleri tanımlayalım;

Texture2D Horse;

Texture2D Tombstone;

SpriteFont SkorFont;
Vector2 SkorPosition;

SoundEffect Gunshot;

Random r;

int Score = 0;

Böylece hedef‘in görselini, vurulduğunda dönüşeceği mezarlık görselini, ateş etme sırasında duyulacak silah sesini, kaç hedef vurduğumuzu tutabileceğimiz değişkenlerimiz tanımlamış olduk.

Constructor‘da r değişkenine değer ataması yapalım;

r = new Random();

LoadContent method’unda diğer değişkenlerimize değer atayalım;

Horse = Content.Load<Texture2D>("Horse");
Tombstone = Content.Load<Texture2D>("Tombstone");

SkorFont = Content.Load<SpriteFont>("SkorFont");
SkorPosition = new Vector2(20, 10);

Gunshot = Content.Load<SoundEffect>("Magnum");

Henüz ekranda hedefleri göremesek‘te oyunumuzun önemli kısımlarının hazırlıklarını tamamladık. Artık hedef listesini tanımlayabilir, Update ve Draw method’larında kullanabiliriz. Sınıf seviyesinde aşağıdaki değişkenleri tanımlayalım;

TimeSpan LastHorseSpawn = TimeSpan.Zero;
TimeSpan SpawnHorseBuffer = TimeSpan.FromSeconds(3);

List<Target> TargetList = new List<Target>();

Update method’unda son hedef üretilme zamanından itibaren yeterli süre geçmişse, yeni hedef oluşturmamız lazım;

if (gameTime.TotalGameTime - LastHorseSpawn > SpawnHorseBuffer)
{
	Target t = new Target();
	t.FrameIndex = 0;
	t.ToLeft = r.Next(0, 2) == 0;
	t.RunSpeed = Convert.ToSingle(r.Next(20, 70)) / 10;
	t.FrameChangeBuffer = TimeSpan.FromMilliseconds(100 + -t.RunSpeed);

	if (t.ToLeft)
	{
		t.Position = new Vector2(graphics.PreferredBackBufferWidth - t.Area.Width, r.Next(200, 400));
		t.SpriteEffect = SpriteEffects.FlipHorizontally;
	}
	else
	{
		t.Position = new Vector2(0, r.Next(200, 400));
		t.SpriteEffect = SpriteEffects.None;
	}

	TargetList.Add(t);

	LastHorseSpawn = gameTime.TotalGameTime;
}

Hedef’in ekranın solundan sağına/sağından soluna gideceğine rastgele karar veriyoruz (ToLeft alanı sayesinde)

Hedef’in ekranda koşma hızına rastgele karar veriyoruz (RunSpeed alanı sayesinde)

Update method’unda hedef listesindeki hedeflerin hala ekranda göründüğünü kontrol ediyoruz, eğer ekrandan çıkmışlarsa hedef listesinden de çıkartıyoruz. Ekranda kalan hedefleri, koşma hızları kadar koşturuyoruz;

foreach (var t in TargetList)
{
	if (!Screen.Intersects(t.Area))
	{
		TargetList.Remove(t);
		break;
	}

	if (gameTime.TotalGameTime - t.LastFrameChange > t.FrameChangeBuffer)
	{
		t.FrameIndex += 1;
		t.LastFrameChange = gameTime.TotalGameTime;
	}

	if (t.FrameIndex > 3)
	{
		t.FrameIndex = 0;
	}

	if (t.ToLeft)
	{
		t.Position.X -= t.RunSpeed;
	}
	else
	{
		t.Position.X += t.RunSpeed;
	}
}

Update method’unda ayrıca, mouse‘un sol tuşuna basıldığında ateş edilmesini sağlamamız gerekiyor. Öncelikle sol tuşa ilk basıldığı anı buluyoruz, silah sesi çıkartıyoruz, hedef listesindeki hedefleri kontrol ediyoruz. Eğer vurulan hedef varsa, mezarlık görseline döndürüyoruz, Skor‘umuzu 1 arttırıyoruz;

if (ms.LeftButton == ButtonState.Pressed && pms.LeftButton == ButtonState.Released)
{
	Gunshot.Play();

	CursorZone.X = ms.X - 2;
	CursorZone.Y = ms.Y - 2;

	foreach (var t in TargetList)
	{
		if (!t.IsDead && t.Area.Intersects(CursorZone))
		{
			Score++;
			t.Position += new Vector2(20, 20);
			t.IsDead = true;
			t.ToLeft = true;
			t.RunSpeed = 1;
			break;
		}
	}
}

Son olarak Draw method’unda, hala hedef listesinde olan hedefleri ve skorumuzu ekrana çizdirmemiz gerekiyor;

foreach (var t in TargetList)
{
	if (t.IsDead)
	{
		spriteBatch.Draw(Tombstone, t.Position, Color.White);
	}
	else
	{
		spriteBatch.Draw(Horse, t.Position, new Rectangle(t.FrameIndex * Target.FrameWidth, 0, Target.FrameWidth, Target.FrameWidth), Color.White, 0f, Vector2.Zero, Vector2.One, t.SpriteEffect, 0);
	}
}

spriteBatch.DrawString(SkorFont, "Skor : " + Score, SkorPosition + Vector2.One, Color.Black);
spriteBatch.DrawString(SkorFont, "Skor : " + Score, SkorPosition, Color.White);

İşte Vahşi Batı oyunundan bir ekran görüntüsü. Oyunun kaynak kodlarını buradan indirebilirsiniz.

XNA Oyun : Vahşi Batı

XNA ile Video Oynatmak

01 July 2011 Yorum yapılmamış

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

Belli bir seviyenin üstündeki her oyunda, oyunu tanıtan, oyuna alışmanızı sağlayan, oyunun hikayesini anlatan veya bölümler arasında bilgi veren videolar vardır.

Oyunun kullanıcılarına, oyunun konusunu okumaları için sayfalarca yazı vermektense, kısa bir video ile anlatmak her zaman daha iyidir.

XNA ile bir video nasıl oynatılır?

Öncelikle oyunumuza ekleyeceğimiz video’nun formatına dikkat etmemiz gerekiyor. Varsayılan olarak, XNA Content Pipeline sadece WMV formatındaki videoları destekler.

XNA ile Oyun Programlama - Content Pipeline Desteklenen Video Formatları

Bir video’yu oyun penceresinde oynatmak için, öncelikle Video sınıfından bir instance‘a oynatacağımız video‘yu yüklememiz lazım.

Daha sonra, XNA Framework ile birlikte gelen VideoPlayer sınıfından bir instance ile, yüklediğimiz video‘yu oynatmaya başlayabiliriz.

Sınıf seviyesinde iki değişken tanımlayarak işe başlıyoruz;

Video v;
VideoPlayer vp;

LoadContent() method’unda değişkenlerimize değer atamalarını yapıyoruz;

v = Content.Load<Video>("OyunBaslangicVideo");
vp = new VideoPlayer();

vp.Play(v);

VideoPlayer tipindeki değişkenin Play() method’unu çağırarak video dosyamızın oynatılmasını sağlıyoruz.

Artık tek yapmamız gereken, Draw() method’unda, oynatılan video‘yu kare kare oyun penceresine çizmek;

spriteBatch.Begin();

spriteBatch.Draw(vp.GetTexture(), Vector2.Zero, Color.Blue);

spriteBatch.End();

XNA, VideoPlayer sınıfının GetTexture() method’u ile oynatılan video’nun o anki karesini Texture2D tipinde kullanmamızı sağlar.

SpriteBatch sınıfının Draw() method’u sayesinde ilgili video karesini oyun penceresine çizebiliriz.

XNA ile Pong oyunu yazalım – 2

11 March 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