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

Arşiv

Etiketlenen yazılar update

Unity3D ile sahneye saat ve gerisayım eklemek

27 January 2016 Yorum yapılmamış

Bu makaleyi okumadan önce Unity3D Kategorisindeki diğer makalelerimi okumanızı tavsiye ederim.

Bu makale sonunda sahneye saati ve 60 saniyeden geri sayımı gösteren iki yazı koyabileceksiniz.

Öncelikle Unity3D‘yi açarak bir oyun projesi oluşturuyoruz;

Hierarchy panelinden Main Camera nesnesini seçiyor ve Projection özelliğinde Ortographic değeri olduğunu kontrol ediyoruz. Scene alanında tam kamera’nın arkasından bakmak için GameObject menüsü altından Align View to Selected menüsüne tıklıyoruz.

Sahneye bir Text nesnesi eklemek için Hierarchy panelinde boş bir yere sağ tuşla tıklıyor ve UI kategorisi altından Text menüsünü seçiyoruz.

Oluşturulan Canvas ve Text‘in kamera’nın gördüğü alanın içerisinde olmasını sağlamak için Canvas seçili iken Render Mode özelliğine Screen Space – Camera değerini giriyoruz. Ayrıca Render Camera özelliğine Hierarchy panelinden Main Camera nesnesini sürükleyip bırakıyoruz.

Hierarchy panelinden Text nesnesini seçip Inspector panelinde gözüken Rect Transform kategorisi altından sahnede gözükeceği konumu belirliyoruz. Örneğin sahnenin sol üst köşesinde olması için left sütunu ile top satırının kesiştiği hücreye tıklıyoruz.

Hierarchy panelinde gözüken Text nesnesine isim olarak TimerText değerini verdikten sonra Edit menüsü altından Duplicate seçeneğini seçerek aynı nesneden bir tane daha oluşturuyoruz.

Yeni oluşturduğumuz Text nesnesine isim olarak CountdownText verip, sahnenin sağ üst köşesine hizalıyoruz.

Her iki Text nesnesinin de Inspector panelinden erişilebilen Font, Font Size ve Color değerlerini değiştirerek, sahnede büyük beyaz harfler gösterecek hale getiriyoruz.

Hierarchy panelinden Canvas nesnesini seçip Inspector panelinden Add Component butonuna tıklıyoruz ve New Script seçeneğini seçiyoruz.

Canvas nesnesine eklediğimiz yeni script’e TimeManager ismini verebiliriz.

TimeManager.cs dosyasını açarak için aşağıdaki kodları yazıyoruz;

using System;
using UnityEngine;
using UnityEngine.UI;

public class TimeManager : MonoBehaviour
{
	Text timerText;
	Text countdownText;

	float countdownTo = 60.0F;

	void Start()
	{
		timerText = GameObject.Find("TimerText").GetComponent<Text>();
		countdownText = GameObject.Find("CountdownText").GetComponent<Text>();
	}

	void Update()
	{
		countdownTo -= Time.deltaTime;

		if (countdownTo > 0)
		{
			countdownText.text = countdownTo.ToString();
		}

		timerText.text = DateTime.Now.ToString("hh:MM:ss");
	}
}

Öncelikle Start() methodunda ismi TimerText ve CountdownText olan iki nesneyi bulup içlerindeki Text elementlerine erişiyoruz ve bunları birer değişkende saklıyoruz. Böylece daha sonra bu nesnelere kolay bir şekilde erişebileceğiz.

Update() methodunda 60 saniyeden geri sayma yapabilmek için countdownTo değişkeninden geçen süreyi çıkartıyoruz ve elde ettiğimiz değeri sahnedeki CountdownText nesnesinde gösteriyoruz.

Son olarak Update() methodunda DateTime sınıfının Now özelliğinden elde ettiğimiz değeri saat:dakika:saniye formatına çeviriyoruz ve sahnedeki TimerText nesnesinde gösteriyoruz.

Eğer oyunu başlatacak olursak 60 saniyeden geri sayım ve bilgisayarın saati ekranda gözükecek;

Unity3D ile kendi etrafında dönen Cube yapmak

23 January 2016 Yorum yapılmamış

Bu makaleyi okumadan önce Unity3D Kategorisindeki diğer makalelerimi okumanızı tavsiye ederim.

Bu makale sonunda sahneye koyacağınız bir Cube nesnesini kendi ekseni etrafında istediğiniz hızda döndürebileceksiniz.

Öncelikle Unity3D‘yi açarak bir oyun projesi oluşturuyoruz;

Unity3D Editor açıldıktan sonra, sahneye bir tane Cube nesnesi ekliyoruz;

  • Hierarchy panelinde boş bir yere sağ tuşla tıklanır
  • 3D Object menüsü altından Cube seçeneği seçilir
  • Hierarchy paneline eklenen Cube nesnesine çift tıklanır ve Scene alanında Cube nesnesine odaklanılır

Sahnedeki nesnelerin gözükebilmesi için üzerlerine ışık tutmak gerekir;

  • Hierarchy panelinde boş bir yere sağ tuşla tıklanır
  • Light menüsü altından Directional Light seçeneği seçilir

Kamera bakış açısını Scene alanında gördüğümüz gibi yapmak için Main Camera nesnesi seçili iken GameObject menüsünden Align with View alt menüsü seçilir.

Hierarchy panelinden Cube nesnesi seçilir, Inspector panelinde gözüken Add Component butonuna tıklanır, New Script menüsüne tıklanır ve SpinningCube yazılır.

Project Assets panelinde gözüken SpinningCube.cs dosyasına çift tıklanır ve Cube nesnesine eklediğimiz script dosyası açılır.

SpinningCube.cs dosyası içinde iki method yer almaktadır;

using UnityEngine;
using System.Collections;

public class SpinningCube : MonoBehaviour {

	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
	
	}
}

Start() methodu, Cube nesnesi oyunda ilk oluşturulduğunda bir defa çalıştırılır. Update() methodu ise oyunun her “kare“sinde tekrar tekrar çalıştırılır. Örneğin, 60fps hızında bir oyunda Update() methodu saniyede 60 defa çalışacaktır.

Update() methodu içerisinde Cube nesnesini yukarı-aşağı eksen etrafında hareket ettirmemiz gerekiyor. Böylece kendi ekseni etrafında dönüyormuş gibi gözükecek.

void Update () {
	transform.Rotate(Vector3.up, Time.deltaTime * 30);
}

Vector3.up ile, yukarı-aşağı yönlü ekseni belirliyoruz, Time.deltaTime ile oyunun çalıştığı cihazın hızından bağımsız olarak hareket etmesini garantiliyoruz, böylece hızlı cihazlarda hızlı, yavaş cihazlarda yavaş dönmeyecek. Son olarak 30 ile çarparak bir miktar hızlı dönmesini sağlıyoruz.

Şimdi oyunu çalıştırarak Cube nesnesinin kendi ekseni etrafında döndüğünü görelim;

Windows Phone 8 – XNA Oyunu / MiniCar

22 January 2015 Yorum yapılmamış

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

Önce görseller ve oyunun arkaplan ses dosyası;

MiniCar : BackgroundMiniCar : MainCarMiniCar : Car1MiniCar : Car2MiniCar : Car3MiniCar : Car4MiniCar : Car5MiniCar : Car6MiniCar : Car7MiniCar : Car8

İlk olarak XNA Game Studio 4.0 grubundaki Windows Phone Game şablonundan MiniCarGame isimli projeyi oluşturalım;

Windows Phone : XNA Game Project Template

Game1.cs dosyasının ismini GameLoop.cs olarak değiştirdikten sonra, EnemyCar isminde yeni bir class ekleyelim;

public class EnemyCar
{
	public Texture2D Texture;

	public Vector2 Position;

	public float Velocity;

	public Rectangle Area;

	Random r = new Random();

	public EnemyCar(Texture2D CarTexture)
	{
		this.Texture = CarTexture;

		this.Position = new Vector2(r.Next(450, 850), 1);

		this.Velocity = (float)(r.NextDouble() * 4) + 3f;

		this.Area = new Rectangle((int)this.Position.X, (int)this.Position.Y, this.Texture.Width, this.Texture.Height);
	}
}

EnemyCar sınıfı sayesinde, ekrana getireceğimiz diğer araçların görsellerini, konumlarını, çarpışma testi yapabilmek için ekranda kapladığı alanı ve hızlarını bileceğiz.

GameLoop sınıfına geri dönelim ve sınıf seviyesindeki değişkenlere aşağıdakileri ekleyelim;

GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;

const int PENCERE_GENISLIK = 800;
const int PENCERE_YUKSEKLIK = 480;

Texture2D BackgroundTexture1;
Texture2D BackgroundTexture2;

Vector2 BackgroundPosition1 = new Vector2(0, -PENCERE_YUKSEKLIK);
Vector2 BackgroundPosition2 = new Vector2(0, 0);

Texture2D MainCarTexture;
Vector2 MainCarPosition = new Vector2(300, 300);

float KatedilenMesafe = 0f;

Rectangle ScreenArea = new Rectangle(0, 0, PENCERE_GENISLIK, PENCERE_YUKSEKLIK);
Rectangle MainCarArea = new Rectangle(300, 300, 67, 134);

TimeSpan TotalElapsedTime;

List<EnemyCar> CarList = new List<EnemyCar>();

Random r = new Random();

Texture2D[] CarTextures = new Texture2D[8];

Klavyedeki hangi tuşlara basıldığını kontrol edebilmek için KeyboardState değişkenlerimizi, arkaplanda sürekli tekrar eden ses çaldırmak için SoundEffectInstance değişkenimizi ve oyunun bittiğini takip edeceğimiz bool değişkeni de sınıf seviyesinde ekleyelim;

KeyboardState ks;
KeyboardState pks;

SoundEffectInstance BackgroundLoop;

bool IsGameOver = false;

İlk yapacağımız iş GameLoop sınıfının constructor‘ında gerekli atamaları yapmak olacak;

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

	graphics.PreferredBackBufferWidth = PENCERE_GENISLIK;
	graphics.PreferredBackBufferHeight = PENCERE_YUKSEKLIK;
	graphics.IsFullScreen = true;
}

LoadContent() methodunda değişkenlerimiz aracılığıyla ses ve resim dosyalarını hafızaya yüklüyoruz;

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

	BackgroundTexture1 = Content.Load<Texture2D>("BackgroundRoad");
	BackgroundTexture2 = BackgroundTexture1;
	MainCarTexture = Content.Load<Texture2D>("MainCar");

	MesafeFont = Content.Load<SpriteFont>("Verdana14");

	for (int i = 0; i < CarTextures.Length; i++)
	{
		CarTextures[i] = Content.Load<Texture2D<("Car" + (i + 2));
	}

	BackgroundLoop = Content.Load<SoundEffect>("BackgroundLoop").CreateInstance();

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

	BackgroundLoop.IsLooped = true;
	BackgroundLoop.Play();
}

Update() method'unda ilk olarak oyundan çıkma ve baştan başlama durumunu sağlayacak kodları yazıyoruz;

ks = Keyboard.GetState();

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

if (IsGameOver && ks.IsKeyDown(Keys.Enter))
{
	IsGameOver = false;
	BackgroundLoop.Play();
	KatedilenMesafe = 0f;
	MainCarPosition = new Vector2(600, 600);
	MainCarArea.X = (int)MainCarPosition.X;
	MainCarArea.Y = (int)MainCarPosition.Y;
	CarList.Clear();
}

Eğer oyun sonlanmadıysa, klavyedeki tuşların durumuna göre arabamızı hareket ettiriyoruz, en son araba eklediğimiz zamandan itibaren belli bir sürenin üzerinde geçtiyse yeni EnemyCar ekliyoruz, EnemyCar listesindeki her bir arabayı hareket ettiriyoruz, yol görselini içeren arkaplanı hareket ettiriyoruz, katedilen mesafeyi güncelleyip, bizim arabamız ile diğer arabaların çarpışma testini yapıyoruz;

if (!IsGameOver)
{
	if (ks.IsKeyDown(Keys.Left))
	{
		MainCarPosition.X -= 3;
		MainCarArea.X -= 3;
	}
	if (ks.IsKeyDown(Keys.Right))
	{
		MainCarPosition.X += 3;
		MainCarArea.X += 3;
	}
	if (ks.IsKeyDown(Keys.Up))
	{
		MainCarPosition.Y -= 3;
		MainCarArea.Y -= 3;
	}
	if (ks.IsKeyDown(Keys.Down))
	{
		MainCarPosition.Y += 3;
		MainCarArea.Y += 3;
	}

	TotalElapsedTime += gameTime.ElapsedGameTime;

	if (TotalElapsedTime > TimeSpan.FromMilliseconds(1500))
	{
		EnemyCar car = new EnemyCar(CarTextures[r.Next(0, 8)]);

		CarList.Add(car);

		TotalElapsedTime = TimeSpan.Zero;
	}

	foreach (EnemyCar car in CarList)
	{
		car.Position.Y += car.Velocity;
		car.Area.Y = (int)car.Position.Y;
	}

	BackgroundPosition1.Y += 2;
	BackgroundPosition2.Y += 2;

	if (BackgroundPosition2.Y > PENCERE_YUKSEKLIK)
	{
		BackgroundPosition1.Y = -PENCERE_YUKSEKLIK;
		BackgroundPosition2.Y = 0;
	}

	KatedilenMesafe += 0.005f;

	foreach (EnemyCar car in CarList)
	{
		if (car.Area.Intersects(MainCarArea))
		{
			IsGameOver = true;
			BackgroundLoop.Stop();
		}
	}
}

Son olarak Update() methodunun son satırında KeyboardState‘i pks değişkenine atyoruz;

pks = ks;

Draw() methodunda kendi arabamızı, diğer arabaları ve katettiğimiz mesafeyi ekrana çiziyoruz;

GraphicsDevice.Clear(Color.CornflowerBlue);

spriteBatch.Begin();

spriteBatch.Draw(BackgroundTexture1, BackgroundPosition1, Color.White);
spriteBatch.Draw(BackgroundTexture2, BackgroundPosition2, Color.White);

spriteBatch.Draw(MainCarTexture, MainCarPosition, Color.White);

spriteBatch.DrawString(MesafeFont, "Katedilen Mesafe: " + KatedilenMesafe.ToString("N2") + " km", new Vector2(51, 51), Color.Black);
spriteBatch.DrawString(MesafeFont, "Katedilen Mesafe: " + KatedilenMesafe.ToString("N2") + " km", new Vector2(50, 50), Color.White);

foreach (EnemyCar car in CarList)
{
	spriteBatch.Draw(car.Texture, car.Position, Color.White);
}

if (IsGameOver)
{
	spriteBatch.DrawString(GameOverFont, "GAME OVER", new Vector2(433, 353), Color.Yellow);
	spriteBatch.DrawString(GameOverFont, "GAME OVER", new Vector2(430, 350), Color.Red);
}

spriteBatch.End();

Windows Phone 8 – XNA Oyunu / Savaşa Hayır

12 January 2014 1 yorum

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

Önce görseller;

Savaşa Hayır : BackgroundSavaşa Hayır : Drop 1 0Savaşa Hayır : Drop 1 1Savaşa Hayır : Drop 2 0Savaşa Hayır : Drop 2 1Savaşa Hayır : Plane 0Savaşa Hayır : Plane 1Savaşa Hayır : Plane 2Savaşa Hayır : Plane 3Savaşa Hayır : Plane 4Savaşa Hayır : Plane 5

İlk olarak XNA Game Studio 4.0 grubundaki Windows Phone Game şablonundan SavasaHayir isimli projeyi oluşturalım;

Windows Phone : XNA Game Project Template

Game1.cs dosyasının ismini GameLoop.cs olarak değiştirdikten sonra, Plane isminde yeni bir class ekleyelim;

public class Plane
{
	public Texture2D Texture;

	public int Location;

	public int Speed;
}

Plane sınıfı sayesinde, ekrana getireceğimiz uçakların telefon ekranındaki konumlarını, hızlarını ve görsellerini bileceğiz.

Drop isminde yeni bir class daha ekleyelim ve aşağıdaki kod parçası ile güncelleyelim;

public class Drop
{
	public bool IsBox;

	public bool IsParachute;

	public Vector2 Location;
}

GameLoop sınıfına geri dönelim ve sınıf seviyesindeki değişkenlere aşağıdakileri ekleyelim;

GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;

Random r = new Random();

Texture2D BackgroundTexture;

Texture2D BoxTexture;
Texture2D BoxParachuteTexture;

Texture2D HumanTexture;
Texture2D HumanParachuteTexture;

Texture2D[] PlaneTextures = new Texture2D[6];

List<Plane> PlaneList = new List<Plane>();

List<Drop> DropList = new List<Drop>();

TimeSpan LastPlaneDate = TimeSpan.Zero;

int PlaneCount;
int DropCount;
int HelpCount;

Yukarıdaki kodlar için daha önce yazmış olduğum Windows Phone ve XNA konusundaki diğer makalelerimi okumanızı öneririm.

GameLoop sınıfının constructor‘ında aşağıdaki atama işlerini yapalım;

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

	TargetElapsedTime = TimeSpan.FromTicks(333333);

	InactiveSleepTime = TimeSpan.FromSeconds(1);

	graphics.PreferredBackBufferWidth = 480;
	graphics.PreferredBackBufferHeight = 800;

	graphics.IsFullScreen = true;
}

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

spriteBatch = new SpriteBatch(GraphicsDevice);

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

for (int iLoop = 0; iLoop < 6; iLoop++)
{
	PlaneTextures[iLoop] = Content.Load<Texture2D>("Plane" + iLoop);
}

BoxTexture = Content.Load<Texture2D>("Drop1_0");
BoxParachuteTexture = Content.Load<Texture2D>("Drop1_1");

HumanTexture = Content.Load<Texture2D>("Drop2_0");
HumanParachuteTexture = Content.Load<Texture2D>("Drop2_1");

Update method'unda Plane ve Drop listesindeki elemanların yerlerini güncelliyoruz;

foreach (var plane in PlaneList)
{
	plane.Location += plane.Speed;
}

foreach (var drop in DropList)
{
	drop.Location.Y += 4;
}

Son uçak üretme zamanımızdan itibaren 5000ms (5sn) geçtiyse yeni uçak üretme kodunu ekliyoruz;

LastPlaneDate += gameTime.ElapsedGameTime;

if (LastPlaneDate > TimeSpan.FromMilliseconds(5000))
{
	var plane = new Plane();

	plane.Texture = PlaneTextures[r.Next(0, 6)];

	plane.Speed = r.Next(3, 8);

	PlaneList.Add(plane);

	PlaneCount++;

	LastPlaneDate = TimeSpan.Zero;
}

Windows Phone oyunlarında, oyuncunun ekrana dokunduğu noktaların listesini TouchPanel sınıfının static GetState methodundan dönen TouchCollection ile alabilmekteyiz.

TouchCollection koleksiyonunun her bir elemanı TouchLocation tipindedir, State özelliğinin TouchLocationState enum’ından Pressed değerinde olduğunu kontrol ederek, ilgili noktaya dokunulduğu durumu yakalayabiliriz.

Eğer dokunulan nokta bir Plane ile kesişiyorsa, rastgele yeni bir Drop düşürebiliriz, Drop ile kesişiyorsa paraşütünün açılmasını sağlayabiliriz;

foreach (var tl in TouchPanel.GetState())
{
	if (tl.State == TouchLocationState.Pressed)
	{
		var touchArea = new Rectangle((int)tl.Position.X, (int)tl.Position.Y, 1, 1);

		foreach (var plane in PlaneList)
		{
			var planeArea = new Rectangle(plane.Location, 20, plane.Texture.Width, plane.Texture.Height);

			if (planeArea.Intersects(touchArea))
			{
				var drop = new Drop();

				drop.Location = new Vector2(tl.Position.X, 20);

				drop.IsBox = (r.Next(0, 2) == 0);

				DropList.Add(drop);

				DropCount++;

				return;
			}
		}

		foreach (var drop in DropList)
		{
			var dropArea = new Rectangle((int)drop.Location.X, (int)drop.Location.Y, 100, 200);

			if (!drop.IsParachute && dropArea.Intersects(touchArea))
			{
				drop.IsParachute = true;

				HelpCount++;

				return;
			}
		}
	}
}

Son olarak Draw method’unda elimizdeki arkaplan görselini, ekrandaki uçakları, paraşütü açılmış ve açılmamış nesneleri ekrana çizdireceğiz;

GraphicsDevice.Clear(Color.CornflowerBlue);

spriteBatch.Begin();

spriteBatch.Draw(BackgroundTexture, Vector2.Zero, Color.White);

foreach (var plane in PlaneList)
{
	spriteBatch.Draw(plane.Texture, new Vector2(plane.Location, 20), Color.White);
}

foreach (var drop in DropList)
{
	if (drop.IsBox && drop.IsParachute)
	{
		spriteBatch.Draw(BoxParachuteTexture, drop.Location, Color.White);
	}
	else if (drop.IsBox && !drop.IsParachute)
	{
		spriteBatch.Draw(BoxTexture, drop.Location, Color.White);
	}
	else if (!drop.IsBox && drop.IsParachute)
	{
		spriteBatch.Draw(HumanParachuteTexture, drop.Location, Color.White);
	}
	else
	{
		spriteBatch.Draw(HumanTexture, drop.Location, Color.White);
	}
}

spriteBatch.End();

Oyun’dan bir ekran görüntüsü;

Savaşa Hayır : Screenshot

Windows Phone 8 – XNA Oyunu / PlaneHunter

18 February 2013 3 yorum

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

Her zamanki gibi önce görseller;

PlaneHunter : BackgroundPlaneHunter : CoinPlaneHunter : Target1PlaneHunter : Target2PlaneHunter : Target3PlaneHunter : Target4PlaneHunter : Target5PlaneHunter : Target6PlaneHunter : Target7

Bir tane de Sprite Font dosyamız var, HitCountFont.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>14</Size>
		<Spacing>0</Spacing>
		<UseKerning>true</UseKerning>
		<Style>Regular</Style>
		<CharacterRegions>
			<CharacterRegion>
				<Start> </Start>
				<End>~</End>
			</CharacterRegion>
		</CharacterRegions>
	</Asset>
</XnaContent>

İlk olarak XNA Game Studio 4.0 grubundaki Windows Phone Game şablonundan PlaneHunter isimli projeyi oluşturalım;

Windows Phone : XNA Game Project Template

Game1.cs dosyasının ismini GameLoop.cs olarak değiştirdikten sonra, Target isminde yeni bir class ekleyelim;

public class Target
{
	public Texture2D Texture;

	public Vector2 Position;

	public Vector2 Velocity;

	public Rectangle Area;

	public SpriteEffects Effect;

	public bool IsAlive;

	public Target(Texture2D texture)
	{
		this.Texture = texture;

		this.IsAlive = true;

		this.Area = new Rectangle(0, 0, texture.Width, texture.Height);
	}
}

Target sınıfı sayesinde, ekrana getireceğimiz hedef‘lerin ekranın neresinden çıkıp, hangi yöne doğru gideceğini, hedefin vurulup/vurulmadığını, çarpışma testi yapabilmek için ekranda kapladığı alanı ve hızını bileceğiz.

GameLoop sınıfına geri dönelim ve sınıf seviyesindeki değişkenlere aşağıdakileri ekleyelim;

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

private Texture2D backgroundTexture;

private readonly Texture2D[] targetTextures = new Texture2D[7];

private Texture2D coinTexture;
private Rectangle coinPart;
private int coinPartIndex = 0;

private SpriteFont hitCountFont;
private int targetHitCount = 0;

private readonly List targetList = new List();

private TimeSpan lastTargetSpawnTime = TimeSpan.Zero;

private readonly Rectangle screenArea = new Rectangle(0, 0, PENCERE_GENISLIK, PENCERE_YUKSEKLIK);

private readonly Random r = new Random();

Yukarıdaki kodlar için daha önce yazmış olduğum Windows Phone ve XNA konusundaki diğer makalelerimi okumanızı öneririm.

GameLoop sınıfının constructor‘ında aşağıdaki atama işlerini yapalım;

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

graphics.SupportedOrientations = DisplayOrientation.LandscapeLeft | DisplayOrientation.LandscapeRight;

SupportedOrientations özelliğine DisplayOrientation enum’ından LandscapeLeft ve LandscapeRight değerlerini atayarak, oyun ekranının telefon dikey değil, yatay tutulduğunda düzgün görüntüleneceğini tanımlamış olduk.

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

backgroundTexture = Content.Load<Texture2D>("PlaneHunterBackground");

coinTexture = Content.Load<Texture2D>("PlaneHunterCoin");
hitCountFont = Content.Load<SpriteFont>("PlaneHunterHitCountFont");

for (int i = 0; i < targetTextures.Length; i++)
{
	targetTextures[i] = Content.Load<Texture2D>("PlaneHunterTarget" + (i + 1));
}

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

lastTargetSpawnTime += gameTime.ElapsedGameTime;

if (lastTargetSpawnTime > TimeSpan.FromMilliseconds(1500))
{
	Target t = new Target(targetTextures[r.Next(0, 7)]);
	switch (r.Next(0, 4))
	{
		case 0:
		default:
			t.Position = new Vector2(r.Next(100, 300), 480);
			t.Velocity = new Vector2((float)r.NextDouble() * 8 + 2, (float)r.NextDouble() * -4 - 2);
			t.Effect = SpriteEffects.FlipHorizontally;
			break;
		case 1:
			t.Position = new Vector2(r.Next(500, 700), 480);
			t.Velocity = new Vector2((float)r.NextDouble() * -8 - 2, (float)r.NextDouble() * -4 - 2);
			t.Effect = SpriteEffects.None;
			break;
		case 2:
			t.Position = new Vector2(r.Next(100, 300), 0);
			t.Velocity = new Vector2((float)r.NextDouble() * 8 + 2, (float)r.NextDouble() * 4 + 2);
			t.Effect = SpriteEffects.FlipHorizontally;
			break;
		case 3:
			t.Position = new Vector2(r.Next(500, 700), 0);
			t.Velocity = new Vector2((float)r.NextDouble() * -8 - 2, (float)r.NextDouble() * 4 + 2);
			t.Effect = SpriteEffects.None;
			break;
	}

	targetList.Add(t);

	lastTargetSpawnTime = TimeSpan.Zero;
}

Yeni hedef ekleyeceğimiz zaman öncelikle hedef’i ekranın dört köşesinden rastgele birtanesine koyup, rastgele hız veriyoruz. Böylece hedefler ekranın rastgele bir yerinden çıkıp rastgele hızla rastgele bir yöne doğru hareket edecek.

Update method’unda o esnada ekranda olan hedeflerin yerlerini ve ekranda kapladıkları alanı güncelliyoruz;

foreach (Target hedef in targetList)
{
	hedef.Position += hedef.Velocity;

	hedef.Area.X = (int)hedef.Position.X;
	hedef.Area.Y = (int)hedef.Position.Y;
}

Windows Phone oyunlarında, oyuncunun ekrana dokunduğu noktaların listesini TouchPanel sınıfının static GetState methodundan dönen TouchCollection ile alabilmekteyiz.

TouchCollection koleksiyonunun her bir elemanı TouchLocation tipindedir, State özelliğinin TouchLocationState enum’ından Pressed değerinde olduğunu kontrol ederek, ilgili noktaya dokunulduğu durumu yakalayabilir, eğer bir hedef ile kesişiyorsa, hedefi öldürebiliriz;

TouchCollection tc = TouchPanel.GetState();
foreach (TouchLocation tl in tc)
{
	if (tl.State == TouchLocationState.Pressed)
	{
		Rectangle touchArea = new Rectangle((int)tl.Position.X, (int)tl.Position.Y, 1, 1);

		foreach (Target hedef in targetList)
		{
			if (hedef.Area.Intersects(touchArea))
			{
				hedef.Velocity = Vector2.Zero;

				hedef.IsAlive = false;

				targetHitCount++;
			}
		}
	}
}

Update method’unda, ekran sınırları dışına çıkan hedefleri listeden çıkartmalıyız. Eğer ekran dışına çıkan hedefleri listeden temizlemezsek, liste zamanla çok büyüyecek, telefonun kısıtlı olan hafızasını dolduracak ve oyunun önce yavaşlamasına sonra kapanmasına yol açabilecektir.

foreach (Target hedef in targetList)
{
	if (!hedef.Area.Intersects(screenArea))
	{
		targetList.Remove(hedef);

		break;
	}
}

Draw method’unda elimizdeki arkaplan görselini, hayatta olan hedefleri, hayatta olmayan hedefler için kendi etrafında dönen altın görselini ve toplam kaç hedefin vurulduğunu gösteren skor‘u ekrana çizdireceğiz;

spriteBatch.Begin();

spriteBatch.Draw(backgroundTexture, Vector2.Zero, Color.White);

foreach (Target hedef in targetList)
{
	if (hedef.IsAlive)
	{
		spriteBatch.Draw(hedef.Texture, hedef.Position, null, Color.White, 0, Vector2.Zero, 1, hedef.Effect, 0);
	}
	else
	{
		spriteBatch.Draw(coinTexture, hedef.Position, coinPart, Color.White);
	}
}

spriteBatch.DrawString(hitCountFont, "Hit Count : " + targetHitCount, new Vector2(10, 10), Color.Black);
spriteBatch.DrawString(hitCountFont, "Hit Count : " + targetHitCount, new Vector2(9, 9), Color.White);

spriteBatch.End();

Oyunumuzdan bir kare;

Windows Phone - XNA Oyunu : PlaneHunter

Oyunun kodlarını buradan indirebilirsiniz.