February, 2013 | Engin Polat'ın Windows, Web, Mobile ve Game içerikli programcılık sitesi

Arşiv

2013 February ayı için arşiv

URI şemaları üzerinden Windows Phone 8 uygulamaları çalıştırmak

20 February 2013 Yorum yapılmamış

Windows Phone 8 işletim sisteminin çeşitli ayarlarının ekranlarını veya üzerinde yüklü gelen uygulamaları çalıştırmak isterseniz aşağıdaki adresleri LaunchUriAsync() method’u ile çağırmanız yeterlidir.

URI şema Açıklama
http:[URL] Web tarayıcıyı açar ve belirtilen adrese yönlenir
mailto:[email address] EMail istemcisini açar, To alanında belirtilen email adresinin olduğu yeni bir mail gönderme ekranına yönlenir. Kullanıcı Gönder butonuna basmadan email gönderilmez
ms-settings-accounts: Hesap Ayarlar ekranını açar
ms-settings-airplanemode: Uçuş Modu Ayarlar ekranını açar
ms-settings-bluetooth: Bluetooth Ayarlar ekranını açar
ms-settings-cellular: Hücresel Veri Ayarlar ekranını açar
ms-settings-emailandaccounts: EMail ve Hesaplar Ayarlar ekranını açar
ms-settings-location: Konum Ayarlar ekranını açar
ms-settings-lock: Kilit Ekranı Ayarlar ekranını açar
ms-settings-wifi: Wi-Fi Ayarlar ekranını açar
zune:navigate?appid=[app ID] Windows Phone Store uygulamasını açar ve parametre ile verilen ApplicationID’ye ait uygulamanın detay ekranına yönlenir
zune:reviewapp?appid=app[app ID] Windows Phone Store uygulamasını açar ve parametre ile verilen ApplicationID’ye ait uygulamanın incelemeler ekranına yönlenir
zune:search?keyword=[search keyword]&publisher=[publisher name]&contenttype=app Windows Phone Store uygulamasını açar ve parametre ile verilen yayınlayıcı adı ve/veya arama kriteri için uygun uygulamaları listeler
zune:search?keyword=[search keyword]&contenttype=app Windows Phone Store uygulamasını açar ve parametre ile verilen arama kriteri için uygun uygulamaları listeler
zune:search?publisher=[publisher name] Windows Phone Store uygulamasını açar ve parametre ile verilen yayınlayıcı adı için uygun uygulamaları listeler

Örnek çalıştırma kodu;

Windows.System.Launcher.LaunchUriAsync(new Uri("ms-settings-bluetooth:"));

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.

Windows Phone 8 için Maps kullanımı

16 February 2013 Yorum yapılmamış

Yeni Maps API sayesinde Windows Phone 8 için harita tabanlı uygulamalar geliştirebiliyoruz.

Öncelikle WindowsPhoneMaps isimli yeni bir Windows Phone App projesi oluşturalım;

Windows Phone 8 App Project : Windows Phone Maps

Proje oluşturduktan sonra gelen Windows Phone Platform versiyon seçim penceresinde Windows Phone OS 8.0 seçeneğinin seçili olduğundan emin olmalıyız;

Windows Phone 8.0 SDK

Windows Phone 8 projemizde Map kontrolünü kullanabilmek için öncelikle ID_CAP_MAP Capability‘sini WMAppManifest.xml dosyasında etkinleştirmeliyiz;

WMAppManifest.xml : ID_CAP_MAP Capability

İlk olarak MainPage.xaml dosyasında phone:PhoneApplicationPage tag’ına

xmlns:maps="clr-namespace:Microsoft.Phone.Maps.Controls;assembly=Microsoft.Phone.Maps"

xml namespace‘ini eklememiz gerekiyor.

Artık Map kontrolünü ekranımıza ekleyebiliriz;

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,12">
	<maps:Map />
</Grid>

Ekrana eklediğimiz Map kontrolünün belli bir koordinatı göstermesi için Center özelliğini ayarlamamız gerekmektedir. İstanbul için örnek;

Center="41.0205, 29.0865"

Kodumuzun son hali;

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,12">
	<maps:Map Center="41.0205, 29.0865" />
</Grid>

Yakınlaşma miktarını ayarlamak için de ZoomLevel özelliğini kullanmamız gerekmektedir;

ZoomLevel="14"

ZoomLevel özelliği 1 ile 20 arasında değer almaktadır. 1 değeri ile en yakın zoom, 20 ile en uzak zoom ayarlamış oluruz.

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,12">
	<maps:Map Center="41.0205, 29.0865" ZoomLevel="14" />
</Grid>

Haritanın gösterim modunu CartographicMode özelliğine atayacağımız değer ile belirleyebiliriz. Varsayılan değeri Road olan CartographicMode özelliğine MapCartographicMode enum’ından şu değerler atanabilir;

  • Road
  • Aerial
  • Hybrid
  • Terrain
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,12">
	<maps:Map Center="41.0205, 29.0865" ZoomLevel="14" CartographicMode="Terrain" />
</Grid>

MapCartographicMode.RoadMapCartographicMode.AerialMapCartographicMode.HybridMapCartographicMode.Terrain

Ayrıca ColorMode özelliğine MapColorMode enum’ından Light veya Dark değerlerinden birini atayarak harita’nın aydınlık veya karanlık gözükmesini sağlayabiliriz.

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,12">
	<maps:Map ColorMode="Dark" />
</Grid>

MapColorMode.LightMapColorMode.Dark

Ayrıca Heading özelliğine 0 ile 360 arası değer atayarak haritanın yukarısında hangi yönün bulunacağını belirleyebiliriz. Örneğin, 0 değerini atayarak haritanın yukarısında Kuzey yönünün gözükmesini, 90 değerini atayarak Batı yönünün gözükmesini, 180 değerini atayarak Güney yönünün gözükmesini, 270 değerini atayarak Doğu yönünün gözükmesini sağlayabiliriz.

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,12">
	<maps:Map Center="41.0205, 29.0865" ZoomLevel="14" Heading="270" />
</Grid>

Son olarak Pitch özelliğine 0 ile 75 arası değer atayarak haritaya bakış açımızı değiştirebiliriz. Örneğin haritada 60 derecelik açı ile İstanbul şöyle gözüküyor;

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,12">
	<maps:Map Center="41.0205, 29.0865" ZoomLevel="14" Pitch="60" />
</Grid>

Pitch

Not : Harita kontrolü üzerinde daha fazla geliştirme seçeneği elde etmek için (örneğin Pushpin) Windows Phone Toolkit‘i indirip projenize ekleyebilirsiniz.

Windows Phone 8 uygulamasına Network Connection ayarları sayfası eklemek

14 February 2013 Yorum yapılmamış

Windows Phone 8 uygulamanıza Network Connection ayarları sayfalarını (örneğin; Airplane, Bluetooth, Cellular, WiFi) açan butonlar/linkler mi eklemek istiyorsunuz?

Bu yazıda ilgili ayarlar ekranlarını nasıl açacağımıza bakacağız.

Kullanmaya başlamadan önce Microsoft.Phone.Tasks namespace‘inde yeralan ConnectionSettingsTask sınıfını inceleyelim;

namespace Microsoft.Phone.Tasks
{
	public sealed class ConnectionSettingsTask
	{
		public ConnectionSettingsTask();
		public ConnectionSettingsType ConnectionSettingsType { get; set; }
		public void Show();
	}

	public enum ConnectionSettingsType
	{
		WiFi = 0,
		Bluetooth = 1,
		Cellular = 2,
		AirplaneMode = 3,
	}
}

Gördüğünüz gibi sealed anahtar kelimesi ile kalıtıma kapatılmış sınıf‘ın constructor haricinde ConnectionSettingsType tipinde ConnectionSettingsType isminde bir property’si, Show isminde bir method‘u bulunmakta.

ConnectionSettingsType enum’ı 4 adet değer içermektedir; WiFi, Bluetooth, Cellular ve AirplaneMode

Uygulama içerisinden ilgili ayarlar ekranını açmak için, örneğin bir buton‘un veya bir hyperlink‘in Click event‘ine aşağıdaki kodları yazmak lazım;

WiFi ayarlar ekranı açmak için;

ConnectionSettingsTask task = new ConnectionSettingsTask();
task.ConnectionSettingsType = ConnectionSettingsType.WiFi;
task.Show();

Bluetooth ayarlar ekranını açmak için;

ConnectionSettingsTask task = new ConnectionSettingsTask();
task.ConnectionSettingsType = ConnectionSettingsType.Bluetooth;
task.Show();

Cellular ayarlar ekranını açmak için;

ConnectionSettingsTask task = new ConnectionSettingsTask();
task.ConnectionSettingsType = ConnectionSettingsType.Cellular;
task.Show();

AirplaneMode ayarlar ekranını açmak için;

ConnectionSettingsTask task = new ConnectionSettingsTask();
task.ConnectionSettingsType = ConnectionSettingsType.AirplaneMode;
task.Show();

C# CallerMemberName attribute

12 February 2013 Yorum yapılmamış

.Net 4.5 ve C# 5 ile duyurulan CallerMemberName attribute’unun Loglama ve OnPropertyChanged method’unu daha kolay tetiklemek dışında ne işe yarayacağını uzun süre düşündükten sonra, internette gördüğüm bir makale ile aklıma bir fikir geldi. CallerMemberName attribute‘unun kullanım alanlarını inceleyelim;

Loglama

public static void LogException(string message,
	[CallerMemberName] string callerName = null,
	[CallerLineNumber] int lineNumber = 0,
	[CallerFilePath] string filePath = null)
{
	Console.WriteLine("Hata oluştu : {0}. Method : {1} Satır : {2} Dosya : {3}", message, callerName, lineNumber, filePath);
}

private static void Calculate()
{
	try
	{
		/// Veritabanına bağlan, sorgulama yap, hesapla
	}
	catch (Exception ex)
	{
		LogException(ex.Message);
	}
}

OnPropertyChanged

OnPropertyChanged method’unu C# 5‘ten önce şöyle tetikleriz;

protected virtual void OnPropertyChanged(string propertyName)
{
	PropertyChangedEventHandler handler = PropertyChanged;
	if (handler != null)
	{
		handler(this, new PropertyChangedEventArgs(propertyName));
	}
}

private string _productName;
public string ProductName
{
	get { return _productName; }
	set
	{
		_productName = value;
		OnPropertyChanged("ProductName");
	}
}

C# 5 ile birlikte gelen CallerMemberName attribute’unu kullanarak aynı işi şu şekilde yapabiliriz;

protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
	PropertyChangedEventHandler handler = PropertyChanged;
	if (handler != null)
	{
		handler(this, new PropertyChangedEventArgs(propertyName));
	}
}
 
private string _productName;
public string ProductName
{
	get { return _productName; }
	set
	{
		_productName = value;
		OnPropertyChanged();
	}
}

Strategy Pattern

CallerMemberName attribute‘unun yukarıdakilerden farklı kullanımı aşağıdaki gibi olabilir;

public class CustomSerializer
{
	public Func<string> Serialize { get; private set; }

	public CustomSerializer([CallerMemberName] string memberName = "")
	{
		if (memberName.Contains("Xml"))
		{
			Serialize = () => { return "xml"; };
		}
		else
		{
			Serialize = () => { return "json"; };
		}
	}
}

public static void WriteXml()
{
	var serializer = new CustomSerializer();
	Console.WriteLine(serializer.Serialize()); /// xml
}

public static void WriteJson()
{
	var serializer = new CustomSerializer();
	Console.WriteLine(serializer.Serialize()); /// json
}

Böylece, CustomSerializer class’ında bulunan Serialize method’unu çağıran method’un adında Xml anahtar kelimesi varsa Serialize method’u xml serialization yapacak, yoksa json serialization yapacak.

Kaynak : Makaleyi tekrar bulamadım :(