XNA etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
XNA etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

12 Aralık 2010

Windows Phone 7 ' de XNA Game Component

Merhaba, bu makalemizde Windows Phone 7 'de XNA 'Game Component' kullanımını inceleyeceğiz. Oyunumuz için 'Game Component Template' kullanarak örnek bir button kontrol sınıfı oluşturacağız. Oluşturacağımız button sınıfını kullanarak dilediğimiz kadar button nesnesi oluşturup, oyunumuzda istediğimiz yere ekleyebilir, yerini değiştirebilir ve istediğimiz zaman da silebilir olacağız.
Oyunlarda sıklıkla ya da birden fazla kullanımı gerektiren nesneler için component kullanımı, kodlarımızın karışmasını engelleyecek, kodların daha modüler ve daha okunabilir bir yapıya kavuşmasını sağlayacaktır. Makalemize başlamadan önce Windows Phone 7 ' de XNA , LoadContent, Update, Draw methodları hakkında bilgilere erişmek isteyenler burdan erişebilirler.

Visual Studio 2010 / File / New Project / XNA Game Studio 4.0 / Windows Phone Game Template seçip yeni bir proje oluşturarak örneğimizi geliştirmeye başlayalım. Projemizi oluşturduğumuzda default olarak Game1.cs isimli sınıf ile birlikte ayrıca bir de Content projesinin, otomatik olarak oluştuğunu göreceğiz. Content projesi oyunumuz içerisinde kullanacağımız nesnelerimizi (imaj, spritefont v.s. gibi) eklediğimiz projedir. Ana projemize 'WindowsPhoneGameComponent' adını verelim. Oluşturduğumuz projenin Solution Explorer 'daki ilk görüntüsü aşağıdaki gibi olacaktır.



























'Button Component' imizi eklemek için hemen WindowsPhoneGameComponent Projesine sağ tıklayıp Add / New Item / XNA Game Studio 4.0 / Game Component Template seçelim ve kontrolümüzün adına 'ButtonControl' adını verelim.



























ButtonControl ilk oluşturulduğunda aşağıdaki kod satırlarının otomatik olarak eklenmiş oduğunu göreceğiz. Bu sınıfın içinde Constractor, Initialize ve Update methodları yer almaktadır. Component sınıfımız bu haliyle override Draw methodunu kullanamayacaktır. Base sınıf GameComponent içerisinde Draw methodu yer almamaktadır.


public class ButtonControl : GameComponent
{
    public ButtonControl(Game game)
        : base(game) { }
    public override void Initialize()
    {
        base.Initialize();
    }
    public override void Update(GameTime gameTime)
    {
        base.Update(gameTime);
    }
}
ButtonControl için base sınıf olarak kullanılan GameComponent sınıfını silerek yerine DrawableGameComponent sınıfını yazıyoruz. DrawableGameComponent ' in eklenmesi ile bu sınıfa ait virtual methodları override şekilde kullanmamız mümkün olacaktır. ButtonControl sınıfımızın son hali de aşağıdaki gibi olsun. Ayrıca override yazıldığında base sınıfdan gelen virtual methodlar da aşağıdaki gibi listelenecektir.







public class ButtonControl : DrawableGameComponent
{
    public ButtonControl(Game game)
        : base(game) { }
    public override void Initialize()
    {
        base.Initialize();
    }
    protected override void LoadContent()
    {
        base.LoadContent();
    }
    public override void Update(GameTime gameTime)
    {
        base.Update(gameTime);
    }
    public override void Draw(GameTime gameTime)
    {
        base.Draw(gameTime);
    }
 }
ButtonControl sınıfımızı DrawableGameComponent' den türettikten sonra sınıfımıza özellikler ekleyerek devam edelim. Button nesnesi oluşturmak amacı ile kullanacağımız için bir constractör daha ekleyerek butonumuzun Text değerini buradan belirtebiliriz. Sınıfımıza ait, text özelliği için bir Texture2D ve Vektör2 nesneleri, ayrıca butonumuzu ekrana çizdirebilmek için de SpriteBatch nesnesinden faydalanacağız. Butonumuzun ekranın neresinde yer alacağını, font değerini ve Text'ini public olarak dışarıya açarak, diğer sınıfların değiştirebilmesine imkan vereceğiz. Ayrıca butonumuza tıklanıldığında click eventı yakalayabilmek için de bir Click EventHandler kullanacağız.

private, public ve constractörümüz aşağıdaki gibi olsun;

private SpriteBatch spriteBatch;
private Texture2D aTexture;
private Vector2 textPosition;
public event EventHandler Click;
public Rectangle Destination { setget; }
public SpriteFont SpriteFont { setget; }
public string Text { setget; }
public ButtonControl(Game game, string buttonText)
    : base(game)
{ 
    Text = buttonText; 
}
private değişkenlerimizi, public özelliklerimizi ve bir de Click isimli event ' ı ekledikten sonra, şimdi de LoadContent methodumuzun içeriğini oluşturalım. SpriteBatch nesnesini oluşturup, hemen ardından buton çerçevesini belirleyece bir de texture nesnesi oluşturuyoruz;

protected override void LoadContent()
{
    spriteBatch = new SpriteBatch(this.GraphicsDevice);
    aTexture = new Texture2D(this.GraphicsDevice, 1, 1);
    aTexture.SetData<uint>(new uint[] { Color.White.PackedValue });
    base.LoadContent();
}
Şimdi de sırasıyla Update ve Draw methodlarımızın içeriğini oluşturalım.  Butonumuzun ekranda yalnızca bir yerde çakılı kalmaması, oyunun akışı içerisinde  dilersek yerini değiştirebilmek için Update methodu içerisinde Destination  özelliğimizden faydalanıyoruz. Update ' den hemen sonra çalışacak Draw methodumuz  içerisinde de ekrana çizim yapacağımız kod satırlarımızı ekleyelim.


public override void Update(GameTime gameTime)
{
    if (SpriteFont != null && !String.IsNullOrEmpty(Text))
    {
        Vector2 textSize = SpriteFont.MeasureString(Text);
        textPosition = 
        new Vector2((int)(Destination.Left + (Destination.Width - textSize.X) / 2),
                    (int)(Destination.Top + (Destination.Height - textSize.Y) / 2));
    }
    base.Update(gameTime);
}
 
public override void Draw(GameTime gameTime)
{
    spriteBatch.Begin();
         
    if (Destination != null) {
        spriteBatch.Draw(aTexture, Destination , Color.Black);
    }
 
    if (SpriteFont != null && !String.IsNullOrEmpty(Text))
    {
        spriteBatch.DrawString(SpriteFont, Text, textPosition, Color.White);
    }
    spriteBatch.End();
    base.Draw(gameTime);
}
Click event ' ımızı oluşturmak için public bir method hazırlayacağız.  Methodumuz bir TouchLocation nesne parametresi alacak. Parametre olarak gelen  TouchLocation, eğer bizim butonumuzun bulunduğu yerin (Destination) içinde ise  Click event'ımızı burada oluşturacağız. Aynı zamanda bu methodumuz Click  event'ın oluşup oluşmadığına dair bool bir değer dönecek. Bu methodumuz için bir  de interface kullanarak tıklanan kontrolün aynı zamanda bir button olduğunu da  daha rahat bir şekilde anlayabileceğiz. Methodumuz ve interface aşağıdaki gibi  olsun;


public bool ButtonTouch(Microsoft.Xna.Framework.Input.Touch.TouchLocation touch)
{
    bool touchHandled = false;
    bool isInside = Destination.Contains((int)touch.Position.X, (int)touch.Position.Y);
    if (isInside && Click != null)
    {
        touchHandled = true;
        Click(thisnull);
    }
    return touchHandled;
}
public interface IButtonTouch
{
    bool ButtonTouch(TouchLocation touch);
}
public class ButtonControl : Microsoft.Xna.Framework.DrawableGameComponentIButtonTouch


ButtonControl sınıfımız DrawableGameComponent ve IButtonTouch interface'ini base olarak kullanacak.
Artık ButtonControl' ümüzü kullanabilir durumdayız. Game1.cs içinde private bir ButtonControl değişken olarak tanımlayarak ana sınıfımız içerisinde bu kontrolü kullanmaya başlayalım. Game1.cs isimli ana sınıfımız ve private değişkenleri aşağıdaki gibi olsun;


public class Game1 : Microsoft.Xna.Framework.Game
private GraphicsDeviceManager graphics;
private SpriteBatch spriteBatch;
private ButtonControl btnTamam;
private bool exitTheGame;
Content projemiz içerisine de bir SpriteFont dosyası eklemeyi unutmayalım.  ButtonFont, Font Size özelliğini de 18 olarak değiştirelim.









Game1.cs içindeki methodların içerisine de aşağıdaki kod satırlarını ekleyelim. Initialize methodumuzdan başlıyoruz. Burada button kontrölümüzü oluşturarak Game1 components collection içerisine ekliyoruz.


protected override void Initialize()
{
    btnTamam = new ButtonControl(this"Oyundan Cikis");
    btnTamam.Click += new EventHandler(btnTamam_Click);
    this.Components.Add(btnTamam);
    base.Initialize();
}
btnTamam isminde bir ButtonControl nesnesi oluşturduk. Butonumuzun Text özelliğinde "Oyundan Cikis" yazacak ve eğer bu butona tıklanırsa öncelikle bir onay mesajı gelecek. Evet seçilirse oyundan çıkılacak hayır seçilirse oyunda kalacağız. btnTamam_Click event handler içerisindeki kod satırlarını da aşağıdaki gibi oluşturalım.


private void btnTamam_Click(object sender, EventArgs e)
{
    if (Guide.IsVisible)
        return;
 
 
    List<string> msgBoxButtons = new List<string>();
    msgBoxButtons.Add("evet");
    msgBoxButtons.Add("hayır");
 
    string msg = "Oyundan çıkılacak.\nÇıkmak istiyor musunuz?";
    Guide.BeginShowMessageBox("Onay", msg, msgBoxButtons, 0, MessageBoxIcon.Alert, 
                              result =>
                              {
                                  int? response = Guide.EndShowMessageBox(result);
                                  if (response.HasValue && response.Value == 0)
                                      exitTheGame = true;
                                  else
                                      exitTheGame = false;
                              }, 
                              null );
}
Guide.BeginShowMessage methoduna parametre olarak IEnumarable tipinde 'evet' ve 'hayır' string değerlerini gönderdik. ilk gönderdiğimiz string değerinin indeksi 0 ve diğerleri 1 artarak devam edecektir. Kullanıcı hangi değeri sonuç onun indeksini dönecektir. Yukarıdaki kod satırlarında Responce.Value == 0 ise evet, 1 ise hayır seçildiği anlamına gelmektedir.


























Şimdi de sırasıyla Game1.cs sınıfının LoadContent, Update ve Draw methodları kod satırlarını da ekleyerek Game1.cs sınıfını tamamlayalım. LoadContent içerisinde kullandığımız content dosyasını ve butonumuzun açılışta ekranın neresinde konumlanacağını (Destination) belirtelim. Update methodu her çalıştığında ekrana tıklanma durumunu da elde edeceğiz. Ekran üzerindeki her bir kontrolü döngü içinde gezerek bu kontrolün IButtonTouch türünden olup olmadığını ve eğer aradığımız kontrol buton türünde bir kontrol ise bu kontrolün ButtonTouch methoduna parametre olarak elde edilen TouchLocation değerini göndereceğiz. Bool ButtonTouch methodu bize true değerini dönerse kontrole tıklanıldığı anlamına gelecek ve Click event handler da yakalanacaktır. Onay mesajında evet denilirse exitTheGame private değişkenimize true atayarak bir sonraki Update methodunda oyunu Exit() ile sonlandıracağız.


protected override void LoadContent()
{
    spriteBatch = new SpriteBatch(GraphicsDevice);
 
    SpriteFont fontTamam = Content.Load<SpriteFont>("ButtonFont");
    btnTamam.SpriteFont = fontTamam;
 
    Vector2 vektorTamam = fontTamam.MeasureString(btnTamam.Text);
 
    int buttonWith = (int)vektorTamam.X;
    int buttonHeight = (int)vektorTamam.Y;
 
    Viewport vport = GraphicsDevice.Viewport;
    btnTamam.Destination = new Rectangle(vport.Bounds.Left + 10,
                                         vport.Bounds.Top + 10,
                                         buttonWith + 60,
                                         buttonHeight + 20);
}
 
protected override void Update(GameTime gameTime)
{
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || exitTheGame)
        this.Exit();
 
    TouchCollection touches = TouchPanel.GetState();
            
    foreach (TouchLocation touch in touches)
    {
 
        bool touchHandled = false;
        foreach (GameComponent component in this.Components)
            if (component is IButtonTouch && (component as IButtonTouch).ButtonTouch(touch))
            {
                touchHandled = true;
                break;
            }
        if (touchHandled)
            continue;
    }
 
    base.Update(gameTime);
}
Uygulamamızı emulatör üzerinde F5 ile çalıştırarak buton kontrolümüzü  belirlediğimiz koordinatda, renkte ve büyüklükte görebiliriz.























Kolay gelsin.
gokhanmanduz@hotmail.com
gmanduz@gmail.com

5 Aralık 2010

Windows Phone 7' de XNA - 2 (2D Rectangle & Per-Pixel Collisions)

Bu makalemizde Windows Phone 7 'de XNA başlıklı yazdığımız makalemize kaldığımız yerden devam ediyoruz. XNA Game Studio 4 kütüphanelerinden faydalanarak Texture2D nesnesini ve bu nesnelerimize Windows Phone 7 cihazımızın ekranında hareket kabiliyeti kazandırmak için de Vektor2D nesnesini kullanmıştık. Önceki makalemizde olduğu gibi konuyu temel düzeyde ele alarak kullandığımız Texture nesnelerinin çarpışmasını (Collision Detection) 2D Rectangle Collision ve 2D Per-Pixel Collision olarak ele alacağız.
Oyunlarda nesnelerin çarpışması (ya da kesişmesi diyebiliriz) kritik öneme sahiptir. Özellikle yarış oyunlarında oyuncuların çarpışmamak, ya da yoldan çıkmamak için ne ölçüde çaba harcadıklarını, hırslandıklarını gözlemleyebiliriz. Böyle bir oyunda elbette çarpışmanın kalitesi ve gerçeğe yakın olması da oyuncuyu daha az çileden çıkaracaktır.
Bu makalemizde de örnek bir senaryo üzerinden devam edeceğiz. Ekran üzerinde bulunacak 2 adet kırmızı topun ekranın farklı yerlerinden rastgele çıkarak aracımızın üzerine doğru farklı hızlarda hareket etmesini sağlayacağız. Aracımızı (car.png) ekranın üzerinde parmağımızla hareket ettirerek bu toplardan kaçırmaya çalışacağız. Toplar ile aracın çarpışması durumunda oyundan 1 hakkımız eksilecek. Toplam 3 hakkımız olacak ve 3 hakkımızı da kaybedersek oyun sonlanmış olacak.


2D Rectangle Collision

Adından da anlaşılacağı üzere 2 boyutlu düzlemde 2 dikdörtgenin kesişmesi durumudur. Nesnelerimizin görüntüsünün dikdörgen olmamasının bir önemi yoktur. Burada önemli olan imaj nesnesinden dikdörtgen veya dikdörtgenler elde edilmesidir. Aşağıdaki resimlerde 2 boyutlu düzlemde dikdörtgenlerin kesişme durumlarına örnekler görebiliriz ya da resimde gösterdiğimiz uçak imajında olduğu gibi bir imajı birden fazla dikdörtgene bölebiliriz.
Aşağıdaki araç ve kırmızı top resimlerinde açıkça görüldüğü gibi dikdörtgenlerin kesişmesinde, asıl kesişim noktaları nesnelerin ekranda görünen yanlarından farklı olarak imajın dikdörtgen olarak belirlenen kısımlarının kesişmesidir.



Araç için car.png, toplar için ball-red-48.png ve yol kenar çizgileri içinde blackLine.png imajlarını kullanacağız. Aşağıdaki dosyaları sağ tıklayarak bilgisayarınıza kaydedebilirsiniz.




Windows Phone 7'de XNA konulu ilk makalemizde olduğu gibi nesnelerimizi solution explorer altında oluşturulan content projesi içerisine ekliyoruz. Ayrıca Imaj dosyaları dışında bir de spritefont dosyasını content projemize ekleyelim. Bu dosyanın nasıl ekleneceğini de Windows Phone 7'de XNA konulu ilk makalemizde belirtmiştik.
Şimdi C# ile ön hazırlığımızı yaparak, oyunumuz için gerekli olacak kodlarımızı yazmaya başlayalım. Öncelikle private olarak Game1.cs sınıfımızda kullanacağımız Texture2D , Vektor2D ve SpriteFont nesnelerimizi oluşturalım.

 GraphicsDeviceManager graphics;
 SpriteBatch spriteBatch;
 
 // Araba objesi için kullanılacak Texture ve Vektörü
 Texture2D carTexture;
 Vector2 carPosition;
 
 //Top 1 objesi için kullanacağımız Texture ve Vektörü
 Texture2D ball_1Texture;
 Vector2 ball_1Position;
 
 //Top 2 objesi için kullanacağımız Texture ve Vektörü
 Texture2D ball_2Texture;
 Vector2 ball_2Position;
 
 //Ekrana ekleyeceğimiz text bilgi için SpriteFont ve Vektörü
 SpriteFont textFont;
 Vector2 textPosition;
 const string TEXT_TEMPLATE = "Gokhan Manduz Car Game - {0} ";
 string TEXT = "";
 
 //Yolu belirtmek için kullanılacak Texture ve Vektörler
 Texture2D line1Texture;
 Vector2 line1Position;
 Texture2D line2Texture;
 Vector2 line2Position;
 
 bool collisionDetected;
 short game = 3;
 Random random = new Random();
 int ballSpeed = 10;
Game1 constractor içerisinde herhangi bir değişiklik yapmıyoruz. Default  olarak belirtilen TargetElapsedTime zaman aralığı ile update ve  draw methodlarımız 30 fps zaman aralığı ile sürekli çalışacaktır.


 public Game1()
 {
     graphics = new GraphicsDeviceManager(this);
     Content.RootDirectory = "Content";
     TargetElapsedTime = TimeSpan.FromTicks(333333);
 }
Şimdide Content projemize eklediğimiz nesnelerimizi LoadContent override  methodumuz içerisinde oyunumuzda kullanmak üzere hazırlayarlayalım oyun  içerisinde bu nesnelerin hangi pozisyonda (koordinatta) başlayacağını  belirleyelim.

 protected override void LoadContent()
 {
     spriteBatch = new SpriteBatch(GraphicsDevice);
 
     carTexture = Content.Load<Texture2D>("car");
     Viewport viewPort = graphics.GraphicsDevice.Viewport;
     carPosition = new Vector2( (viewPort.Width - carTexture.Width) / 2,  (viewPort.Height - carTexture.Height) / 2 );
 
     ball_2Texture = ball_1Texture = Content.Load<Texture2D>("Ball-red-48");
     ball_1Position = new Vector2(-150, 30);
     ball_2Position = new Vector2(-150, 260);
 
     textFont = this.Content.Load<SpriteFont>("CarGameFont");
     textPosition = new Vector2(2, 25);
 
     line2Texture = line1Texture = Content.Load<Texture2D>("blackLine");
     line1Position = new Vector2(-800, 0);
     line2Position = new Vector2(-800, 470);
 }
Tabiki oyunumuzun kilit kodları Update override methodu içerisinde yer  alacaktır. Update methodu her çalıştırıldığında nesnelerimizin yeni pozisyonunu, yer  değiştirmelerden sonra herhangi bir çarpışma olup olmadığını ve bir takım  hesaplamalarımızı buraya yazacağız. Öncelikle Update methodumuz içerisinde 2D  Rectangle ile çarpışma olup olmadığını kontrol edelim. Eğer çarpışma meydana  gelmiş ise ekranımızın arka plan rengini de kırmızıya boyayalım. 3 çarpışmadan  sonra oyunumuz sonlanacaktır. Kırmızı toplarımız X koordinatında soldan sağa  doğru farklı hızlarda ve her defasında farklı Y koordinatından gelerek aracımıza  doğru ilerleyecektir. Aracımıza bir yol üzerinde gidiyormuş izlenimi kazandımak  için de yol kenarlarında bulunan çizgilerimizi sürekli olarak X koordinatında  soldan sağa doğru hareket ettireceğiz. Update methodu içerisindeki kod  satırlarını comment satırlarına dikkat ederek inceleyelim.


 protected override void Update(GameTime gameTime)
 {
     if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
         this.Exit();
 
     switch (game)
     {
         case 3:
             //-- 3 oyun hakkımız var.
             TEXT = string.Format(TEXT_TEMPLATE, "|||");
             break;
         case 2:
             //-- 2 oyun hakkımız kaldı.
             TEXT = string.Format(TEXT_TEMPLATE, "||");
             break;
         case 1:
             //-- 1 oyun hakkımız kaldı.
             TEXT = string.Format(TEXT_TEMPLATE, "|");
             break;
         case 0:
             //-- 0 oyun hakkı. Oyundan çıkılacak :)
             this.Exit();
             break;
     }
            
     //-- 13 ve 20 birim arasında rastgele topların hızlarını değiştirelim.
     //   (X koordinatında)
     ballSpeed = random.Next(13, 20);
     ball_1Position.X += ballSpeed;
     ball_2Position.X += (ballSpeed - 3);
     //-- 
 
 
     //-- X koordinatındaki pozisyon 900'den fazla ise toplar X'de tekrar başa dönsün.
     //   ve Y ekseninde toplar rasgele bir pozisyonda başlasın.
     if (ball_1Position.X > 900) {
         ball_1Position.X = -60;
         int ball1_Y = random.Next(ball_1Texture.Height, (480 - ball_1Texture.Height));
         ball_1Position.Y = ball1_Y;
     }
     if (ball_2Position.X > 900)
     {
         ball_2Position.X = -60;
         int ball2_Y = random.Next(ball_2Texture.Height, (480 - ball_1Texture.Height));
         ball_2Position.Y = ball2_Y;
     }
     line1Position.X += 10;
     line2Position.X += 10;
     if (line1Position.X > -2)
     {
         line1Position.X = -800;
         line2Position.X = -800;
     }
          
     //-- Ekrana dokunulduysa hangi pozisyona dokunulduğu bilgisi alınır.
     //   ve aracı o yönde ve mesafeye göre hızı ayarlanarak aracın X,Y değerleri arttırılır.
     TouchCollection touchCollection = TouchPanel.GetState();
     if (touchCollection.Count > 0) {
         TouchLocation t1 = touchCollection[0];
         double x = t1.Position.X - (carPosition.X + (carTexture.Width / 2));
         double y = t1.Position.Y - (carPosition.Y + (carTexture.Height / 2));
         double speed = Math.Sqrt(x * x + y * y) / 10;
         double angle = (float)Math.Atan2(y, x);
         carPosition.X += (float)(speed * Math.Cos(angle));
         carPosition.Y += (float)(speed * Math.Sin(angle));
     }
 
 
     //-- Collision Detaction kod satırları
     Rectangle carRectangle = new Rectangle((int)carPosition.X, (int)carPosition.Y, carTexture.Width, carTexture.Height);
     Rectangle ball1Rectangle = new Rectangle((int)ball_1Position.X, (int)ball_1Position.Y, ball_1Texture.Width, ball_1Texture.Height);
     Rectangle ball2Rectangle = new Rectangle((int)ball_2Position.X, (int)ball_2Position.Y, ball_2Texture.Width, ball_2Texture.Height);
     if (carRectangle.Intersects(ball1Rectangle) || carRectangle.Intersects(ball2Rectangle))
     {
         collisionDetected = true;
     }
     else {
         if (collisionDetected) {
             //Oyun hakkımızı 1 azaltıyoruz
             game--;
         }
         collisionDetected = false;
     }
     //--
 
     base.Update(gameTime);
 }
Yukarıdaki kod satırlarına dikkat edecek olursak çarpışma olup olmadığını  rectangle nesnemizin Intersects methodunu kullanarak gerçekleştiriyoruz. 
Şimdi de aynı örneğimiz üzerinden yalnızca Collision Detection kod satırlarımızı düzenleyerek 2D Per-Pixel Collision Detaction ile çarpışma olup olmadığını kontrol edeceğiz.


2D Per-Pixel Collision

2 boyutlu düzlemde yer alan nesnelerimizin piksel piksel kontrol edilmesiyle çarpışma olup olmadığının anlaşıldığı yöntemdir. Bu yöntem Rectangle Collision yöntemine göre çok daha sağlıklı sonuçlar verecektir. Hatta tam olarak istediğimiz şekillerin çarpışmasını en ince detaya kadar kontrol edebiliriz. Bu yöntemde imaj içerisinde yer alan nesnelerimizi piksel bazında üst üste gelecek renk değişimini kontrol ederek çarpışma oldup olmadığını belirleyeceğiz. Aşağıdaki resimlerde imaj dosyalarımızın içeriğini piksel bazında detaylı olarak görebiliriz. (VS 2010 content projemiz içerisindeki imaj dosyalarına çift tıklayarak hangi renge sahip piksellerden oluştuğunu görebiliyoruz.)





Piksel piksel bölünmüş olan nesnelerimizin aslında bazı piksel renklerinin transparent, bazılarının ise transparent dan farlı olarak bir renge sahip olduğunu görebiliyoruz. Per-Pixel Collision da nesnelerimizin kesişmesini piksellerindeki renk farklılıklarını kontrol ederek yakalayacağız. Imajlar kesiştiğinde kesişen bölgelerdeki renklerin transparent ya da saydam olması muhtemeldir. Bu sebepten dolayı imajların kesişiminde transparent renkten farklı olan renklerin aynı piksel üzerinde yer almasını dikkate alacağız. C# kodlarımızı bu özelliğe uygun şekilde hazırlayalım.




Öncelikle private olan değişkenlerimizin olduğu kısıma Color array olarak carTextureData, ball1TextureData ve ball2TextureData isimli nesnelerimizi tanımlıyoruz. Hemen ardından LoadContent override methodumuz içerisinde de color array nesnelerimizi aşağıdaki gibi oluşturalım.

private değişkenler;

 Color[] carTextureData;
 Color[] ball1TextureData;
 Color[] ball2TextureData;
LoadContent methoduna eklememiz gereken c# kod satırlarımız.

carTextureData = new Color[carTexture.Width * carTexture.Height];
ball2TextureData = ball1TextureData = new Color[ball_1Texture.Width * ball_1Texture.Height];
 
carTexture.GetData(carTextureData);
ball_1Texture.GetData(ball1TextureData);
ball_2Texture.GetData(ball2TextureData);
Ve Update override methodumuzun son hali ile static bool IntersectPixel  (Piksel çakışması) methodumuzu aşağıdaki gibi hazırlayalım.

protected override void Update(GameTime gameTime)
{
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
        this.Exit();
 
    switch (game)
    {
        case 3:
            //-- 3 oyun hakkımız var.
            TEXT = string.Format(TEXT_TEMPLATE, "|||");
            break;
        case 2:
            //-- 2 oyun hakkımız kaldı.
            TEXT = string.Format(TEXT_TEMPLATE, "||");
            break;
        case 1:
            //-- 1 oyun hakkımız kaldı.
            TEXT = string.Format(TEXT_TEMPLATE, "|");
            break;
        case 0:
            //-- 0 oyun hakkı. Oyundan çıkılacak :)
            this.Exit();
            break;
     }
            
    //-- 13 ve 20 birim arasında rastgele topların hızlarını değiştirelim.
    //   (X koordinatında)
    ballSpeed = random.Next(13, 20);
    ball_1Position.X += ballSpeed;
    ball_2Position.X += (ballSpeed - 3);
    //-- 
 
 
    //-- X koordinatındaki pozisyon 900'den fazla ise toplar X'de tekrar başa dönsün.
    //   ve Y ekseninde toplar rasgele bir pozisyonda başlasın.
    if (ball_1Position.X > 900) {
        ball_1Position.X = -60;
        int ball1_Y = random.Next(ball_1Texture.Height, (480 - ball_1Texture.Height));
        ball_1Position.Y = ball1_Y;
    }
    if (ball_2Position.X > 900)
    {
        ball_2Position.X = -60;
        int ball2_Y = random.Next(ball_2Texture.Height, (480 - ball_1Texture.Height));
        ball_2Position.Y = ball2_Y;
    }
 
    line1Position.X += 10;
    line2Position.X += 10;
    if (line1Position.X > -2)
    {
        line1Position.X = -800;
        line2Position.X = -800;
    }
        
    //-- Ekrana dokunulduysa hangi pozisyona dokunulduğu bilgisi alınır.
    //   ve aracı o yönde ve mesafeye göre hızı ayarlanarak aracın X,Y değerleri arttırılır.
    TouchCollection touchCollection = TouchPanel.GetState();
    if (touchCollection.Count > 0) {
        TouchLocation t1 = touchCollection[0];
        double x = t1.Position.X - (carPosition.X + (carTexture.Width / 2));
        double y = t1.Position.Y - (carPosition.Y + (carTexture.Height / 2));
        double speed = Math.Sqrt(x * x + y * y) / 10;
        double angle = (float)Math.Atan2(y, x);
        carPosition.X += (float)(speed * Math.Cos(angle));
        carPosition.Y += (float)(speed * Math.Sin(angle));
    }
 
 
    //-- Per-Pixel Collision Detaction kod satırları
    Rectangle carRectangle = new Rectangle((int)carPosition.X, (int)carPosition.Y, carTexture.Width, carTexture.Height);
    Rectangle ball1Rectangle = new Rectangle((int)ball_1Position.X, (int)ball_1Position.Y, ball_1Texture.Width, ball_1Texture.Height);
    Rectangle ball2Rectangle = new Rectangle((int)ball_2Position.X, (int)ball_2Position.Y, ball_2Texture.Width, ball_2Texture.Height);
    if (IntersectPixels(carRectangle, carTextureData, ball1Rectangle, ball1TextureData) || IntersectPixels(carRectangle, carTextureData,ball2Rectangle, ball2TextureData))
    {
        collisionDetected = true;
    }
    else {
        if (collisionDetected) {
            //Oyun hakkımızı 1 azaltıyoruz
            game--;
        }
        collisionDetected = false;
    }
    //--
 
    base.Update(gameTime);
}
 
static bool IntersectPixels(Rectangle rectangleCar, Color[] dataCar,
                           Rectangle rectangleBall, Color[] dataBall)
{
    int top = Math.Max(rectangleCar.Top, rectangleBall.Top);
    int bottom = Math.Min(rectangleCar.Bottom, rectangleBall.Bottom);
    int left = Math.Max(rectangleCar.Left, rectangleBall.Left);
    int right = Math.Min(rectangleCar.Right, rectangleBall.Right);
 
    for (int y = top; y < bottom; y++)
    {
        for (int x = left; x < right; x++)
        {
            Color colorA = dataCar[(x - rectangleCar.Left) +
                                 (y - rectangleCar.Top) * rectangleCar.Width];
            Color colorB = dataBall[(x - rectangleBall.Left) +
                                 (y - rectangleBall.Top) * rectangleBall.Width];
 
            // Eğer her 2 piksel rengide transparent dan farklı ise kesişme var
            if (colorA.A != 0 && colorB.A != 0)
            {
                return true;
            }
        }
    }
    // Kesişme bulunamadı ise false
    return false;
}
Oyunumuzda aracımızı hareket ettirirken TouchCollection nesnesinden  faydalandık. Eğer istersek Windows Phone 7 cihazlarında bulunan Akselerometreden  faydalanarak da aracımızı hareket ettirebiliriz.  Akselerometre ile ilgili  detaylı bilgiye  buradan erişilebilir.

Son olarak Draw override methodumuzda nesnelerimizi ekrana çizdirecek olan C# kodlarımızı yazarak makalemizi sonlandıralım. Eğer kodları ilgili methodlarımızın içerisine yazıp F5 ile Windows Phone 7 emulator üzerinde çalıştıracak olursak aşağıdaki ekran görüntüsünü elde edeceğiz.


protected override void Draw(GameTime gameTime)
{
    if(collisionDetected)
        GraphicsDevice.Clear(Color.Red);
    else
       GraphicsDevice.Clear(Color.White);
 
    spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
    spriteBatch.Draw(carTexture, carPosition, collisionDetected ? Color.Red : Color.White);
    spriteBatch.End();
 
    spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
    spriteBatch.Draw(ball_1Texture, ball_1Position, Color.White);
    spriteBatch.End();
 
    spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
    spriteBatch.Draw(ball_2Texture, ball_2Position, Color.White);
    spriteBatch.End();
 
    spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
    spriteBatch.DrawString(textFont, TEXT, textPosition, Color.Blue);
    spriteBatch.End();
 
    spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
    spriteBatch.Draw(line1Texture, line1Position, Color.White);
    spriteBatch.End();
 
    spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
    spriteBatch.Draw(line2Texture, line2Position, Color.White);
    spriteBatch.End();
 
    base.Draw(gameTime);
}























Windows Phone 7 de keyifli oyunlar... Kolay gelsin.

gokhanmanduz.blogspot.com
gokhanmanduz@hotmail.com
gmanduz@gmail.com

2 Aralık 2010

Windows Phone 7 'de XNA

Merhabalar, bu makalemizde Windows Phone 7 ' de XNA ile oyun geliştirme adımlarını temel düzeyde inceleyeceğiz. XNA Game Studio 4 ile birlikte artık Windows Phone 7 platformu için de oyun geliştirebilmek mümkün olacak. XNA Framework, 2004 yılından bu yana farklı versiyonlar ile Microsoft tarafından sunulmaktadır. XNA Game Studio ile  oyun geliştirmenin C# bilen yazılım geliştiriciler için son derece kullanışlı ve keyifli olduğu bir gerçek. Özellikle de Windows Phone 7 platformu ile kullanılacak olması mobil teknolojiler ile ilgilenen ya da ilgilenecek olan yazılım geliştiricileri oldukça heyecanlandırdığını düşünüyorum. XNA' nın bu son versiyonu XBOX360, Windows 7 ve Windows Phone 7'de koşturacak.

XNA Nedir? XNA kütüphanesinde hangi sınıflar yer almaktadır? Bunlara ne zaman ihtiyaç duyarız? Nerede kullanırız? v.s gibi konu başlıklarının yanıtlarına şu an internet üzerinden arama ile rahatça erişebilir durumdayız.(İlgili linkleri makalenin sonunda vereceğim.) Fakat kısaca şöyle söyleyelim: XNA, Microsoft yazılım geliştiricileri tarafından üretilen ve yalnızca C# programlama dili ile yönetilebilen bir oyun platformudur, ya da oyun alt yapısı, kütüphanesi sağlayan bir Framework'dür.

Bu yazımızda fazla detaya inmeden windows phone 7 platformu tabanlı örnek bir oyun üzerinde duracağız. Bu oyunumuzdaki amaç, Visual Studio 2010' da Windows Phone Game Template ile bir projeye başlarken, zaten bize hazır bir şekilde gelecek olan bir takım methodların kullanımlarını anlamak ve bu sırada XNA kütüphanesini daha iyi hissedebilmek olacaktır.

Tabiki bu makalemizin konusu içerisinde yazacağımız kodları kendi bilgisayarımızda uygulayabilmek için VS2010'a ek olarak Windows Phone Developer Tools'un da kurulu olması gerekmektedir. Kodlarımızı tamamladıktan sonra WP7 Emulator üzerinde çalıştıracağız.
Projemizi oluşturmaya Visual Studio 2010 / File / New Project / XNA Game Studio 4.0 / Windows Phone Game seçeneği ile başlayalım.





Windows Phone Game Projemize "PhoneGame1" ismini verelim. "Game1" isminde bir ana sınıf da otomatik olarak oluşturulacaktır. Bu projenin eklenmesiyle, Solution Explorer penceresi inceleyecek olursak 2 adet projenin eklenmiş olduğunu göreceğiz. Bunlar "PhoneGame1" ve "PhoneGame1Content" isimli projelerdir. Content projemiz, adından anlaşılacağı üzere oyunumuz içerisinde yer alacak, yüklenecek olan içeriklerin (image,text,ses,v.s...) ekleneceği bölüm, C# kodlarımızı da asıl derlenecek olan projemize ekleyeceğiz, bu proje de verdiğimiz isimle yer aldığını göreceğiz. Oyunumuzda kullanmak üzere 2 adet imaj dosyasını ve 1 adet spritefont dosyasını Content projemize ekleyebiliriz. Bunlar "car.png", "Ball-red-48.png" imaj dosyaları ve CarGameFont.spritefont dosyasıdır. Imaj dosyalarını (bu makale üzerinden) üzerine sağ tıklayıp bilgisayarınıza kaydederek kullanabilirsiniz. Spritefont dosyası oluşturmak için ise Content projesine sağ tıklayıp Add / New Item / Sprite Font seçeneğini kullanabiliriz. SpriteFont dosyasını açıp incelersek, font özelliklerinin xml formatında yer aldığını görürüz. İçinde FontName, Size, Style gibi özellikleri barındırmaktadır.

Content'e eklediğimiz imaj dosyalarını dilerseniz buradan kopyalayabilirsiniz. (Araba için car.png ve toplar için ball-red-48.png)











Şimdi de otomatik olarak oluşturulan Game1 isimli ana sınıfımızı inceleyelim. Game1 isimli sınıfımızda çeşitli override methodlarımızı ve bir de constractor methodun yer aldığını göreceğiz. Sırasıyla bu methodlar;

public Game1()
protected override void Initialize()
protected override void LoadContent()
protected override void Update(GameTime gameTime)
protected override void Draw(GameTime gameTime)
protected override void UnloadContent()
olarak hali hazırda yer alacaklar. Sırasıyla hangi methodun ne zaman kullanıldığını  anlamaya çalışalım. "Game1" isimli sınıfımızda tabiki Game1 isminde bir  constractor yer alacak ve uygulamamız ilk oluşturulduğunda öncelikle bu constraktor  method çalışacak. Ctor. içerisinde uygulamamıza özgü olan ve uygulama  süresince değişmeyecek olan özellikleri set  edebiliriz. Constractorden sonra çalışacak olan Initialize()  override methodu ile de grafiksel olmayan uygulama içeriğini henüz uygulama  başlamadan hazır duruma getirmek amacı ile kullanabiliriz.  

Diğer methodlarımızı incelemeden önce sırasıyla hangi methodun çalışacağını aşağıdaki akış şeması üzerinden inceleyelim.



Initialize Method
Constractor'den farklı olarak bir de initialize methodu ayrıca oluşturulmuştur. Bu method uygulamanın ayağa kaldırılışı sırasında çalışır. Constractor ile uygulama oluşturulduktan sonra ve sonraki her reset işleminde bu method ile uygulama başlayacaktır.

LoadContent
Adından da anlaşılacağı üzere, uygulamamıza ait olan içeriğin(dosyaların),objelerin yüklenmesi/oluşturulması, ilk ayarlarının yapılmasını (ilk lokasyonun belirlenmesi v.s) burada yaparız. Uygulamanın ayağa kalkışı ile bir defa çalışır. Bu method içerisinde imaj, ses, yazı v.s gibi içerikler yüklenerek oyun için hazır duruma getirilir.

Update
Uygulama içerisindeki değişimler burada yakalanır(Touch Event'lar, nesne yerlerinin/koordinatlarının zamanla değişmesi,v.s).  Constractor içerisinde set edilen TargetElapsetTime zaman aralığının, yani bir görüntü karesi ile sonraki görüntü karesi arasında geçen sürenin dolması ile bu method tekrar tekrar, çok hızlı bir şekilde(fps hızında), uygulama sonlandırılana kadar çalışacaktır. Uygulama süresince sürekli olarak ve çok kısa zaman aralıkları ile bu method çalışacağı için, istenilen değişiklikleri, matematiksel hesaplamaları, yani oyunun iş mantığını buraya yazıyoruz.

Draw
Update methodu ile senkronize bir şekilde çalışır ve update methodundan hemen sonra devreye girer. Update içerisinde yapılan değişikliklerin ekrana yansıtılması için kullanılan methoddur.

UnloadContent
Uygulamamızın sonlandırılması durumunda çalışacaktır. LoadContent içerisinde yüklenen içeriğin hafızadan silinmesi amacıyla kullanılır.
Şimdi vakit kaybetmeden sırasıyla content projeye eklediğimiz dosyalarımızı kullanmaya başlayalım. "car.png" isimli araba nesnemizi temsilen Texture2D sınıfından faydalanacağız. Arabamızı koordinat sisteminde 2 boyutlu (2D, X ve Y'de) olarak düşünüyoruz. Bu sebeple Texture2D nesnesi araba objemizi temsilen kullanılacak. Arabamızı ekranda hareket ettirebilmek için de Vector2 (tabiki vektörel olarak) sınıfından faydalanacağız. Arabamıza vereceğimiz hareketler koordinat ekseninde X ve Y yönlerinde olacak. X'i yatay hareketlerde, Y'yi ise dikey eksen olacak.


Constractor methodumuzun üst kısmına öncelikli olarak oyunumuzda kullanacağımız objelerimizi tanımlayarak programımızı geliştirmeye başlayalım. "Game1" isimli sınıfımıza aşağıdaki tanımlamaları private değişken olarak ekleyelim.


// Araba objesi için kullanılacak Texture ve Vektör
Texture2D carTexture;
Vector2 carPosition;
 
//Top 1 objesi için kullanacağımız Texture ve Vektör
Texture2D ball_1Texture;
Vector2 ball_1Position;

//Top 2 objesi için kullanacağımız Texture ve Vektör
Texture2D ball_2Texture;
Vector2 ball_2Position;
 
//Ekrana ekleyeceğimiz text bilgisi için SpriteFont ve Vektörü
SpriteFont textFont;
Vector2 textPosition;
const string TEXT_TEMPLATE = "Gokhan Manduz Car Game - Zaman(Sn.)={0} - Car Coord.={1}";
string TEXT = "";
Oyunuzdaki objelere ekranımızda (koordinat ekseninde) vektörel hareketler  vereceğimizden dolayı değişken isimlendirmelerimizi "Position" kelimesi ile  sonlandıralım. Windows Phone 7 ekranımızda "carTexture", "ball_1Texture",  "ball_2Texture" ve textFont isimli nesnelerimiz ve bu nesnelerimize yer  değiştirme kabiliyeti kazandıracak "carPosition", "ball_1Position",  ball_2Position" ve "textPosition" isimli değişkenlerimizi tanımladık. Bu  oyunumuzda ekranımıza her dokunulduğunda arabamızı o yönde hareket ettirirken  aynı zamanda toplarımızı da sabit ama farklı hızlarda ekranımız üzerinde hareket  ettireceğiz. Aynı zamanda bir text bilgi ile arabamızın koordinat ekseninde  aldığı X ve Y değerlerini izleyeceğiz. Burada önemli olan oyunumuzun mantığından  çok objelerimizi nasıl hareketlendirdiğimiz ve ekrana nasıl çizildiğimiz  olacaktır.

Şimdi de yukarıda tanımladığımız nesnelerimizi LoadContent methodu içerisinde oyunumuz için hazır duruma getirelim. Texture'lareımızı ve Vektörlerimizi aşağıdaki gibi oluşturuyoruz.


 protected override void LoadContent()
 {
    spriteBatch = new SpriteBatch(GraphicsDevice);
 
    carTexture = Content.Load<Texture2D>("car");
    Viewport viewPort = graphics.GraphicsDevice.Viewport;
    carPosition = new Vector2( (viewPort.Width - carTexture.Width) / 2,  (viewPort.Height - carTexture.Height) / 2 );
 
    ball_1Texture = Content.Load<Texture2D>("Ball-red-48");
    ball_1Position = new Vector2(-60, 30);
 
    ball_2Texture = Content.Load<Texture2D>("Ball-red-48");
    ball_2Position = new Vector2(-60, 260);
 
    textFont = this.Content.Load<SpriteFont>("CarGameFont");
    textPosition = new Vector2(2, 2);
 
 }
Arabamızın oyunun başında ekranın ortasında olmasını istediğimiz için  carPosition vektör nesnesi constraktörüne ilgili parametreleri merkezde olacak  şekilde gönderiyoruz.  Burada dikkat edecek olursak Content.Load jenerik methodunu  kullanarak istediğimiz objeleri yükledik. Oyunumuz başlarken 2 adet  kırmızı top objelerini, ekranın dışından oyuına dahil edilmesini istediğimiz  için koordinat ekseninde X değerlerini -60 olarak verdik.
ball_1Position = new Vector2(-60, 30);  ball_2Position = new Vector2(-60, 260);
Ekranın üst kısmına da oyun ile ilgili bilgilendirme text metnimizi başlangıç noktası koordinat ekseninde (x,y) (2,2) olacak şekilde belirttik.
textPosition = new Vector2(2, 2);
Başlangıç değerlerini belirttikten sonra Update methodumuzun içinde gerçekleştireceğimiz koordinat ekseninde yer değiştirmeye yarayacak kodlarımızı da ekleyelim. Update methodu default olarak her 30fps'de (30 frames per second) bir tekrar tekrar çalışacaktır. Buradaki 30fps değeri default olarak constractorde verilmiştir. (TargetElapsedTime)


 // Frame rate is 30 fps by default for Windows Phone.
 TargetElapsedTime = TimeSpan.FromTicks(333333);
 protected override void Update(GameTime gameTime)
 {
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
        this.Exit();
 
    ball_1Position.X += 10;
    ball_2Position.X += 5;
 
    if (ball_1Position.X == 900) {
       ball_1Position.X = -60;
    }
    if (ball_2Position.X == 900)
    {
       ball_2Position.X = -60;
    }
 
    TEXT = string.Format(TEXT_TEMPLATE, gameTime.TotalGameTime.Seconds, string.Concat((int)carPosition.X,",",(int)carPosition.Y));
            
    TouchCollection touchCollection = TouchPanel.GetState();
    if (touchCollection.Count > 0) {
       TouchLocation t1 = touchCollection[0];
 
       double x = t1.Position.X - (carPosition.X + (carTexture.Width / 2) );
       double y = t1.Position.Y - (carPosition.Y + (carTexture.Height / 2));
       double speed = Math.Sqrt(x * x + y * y) / 10;
       double angle = (float)Math.Atan2(y, x);
       carPosition.X += (float)(speed * Math.Cos(angle));
       carPosition.Y += (float)(speed * Math.Sin(angle));
     }
     base.Update(gameTime);
 }
Toplarımızın Y koordinat ekseninde (dikeyde) yerlerini 30 ve 260 olarak  belirlemiştik. Topların Y değerleri sabit kalacak, istediğimiz topların yalnızca  yatayda (X ekseninde) hareket etmesi. Update methodumuz içerisinde  ball_1Position için +10 ve ball_2Position vektörünün X koordinatı değerine de +5 ekleyerek 1. topun,  2. topa göre daha hızlı (2 kat) ilerlemesini sağlayacağız. Belirli bir süre  sonra X koordinat ekseninde toplar kaybolacaktır çünkü X koordinat eksenimiz 800  ile sınırlıdır. Biz de update methodu her çalıştığında topların X değerlerini  kontrol ederek 800'den fazla ise (topların tamamen ekrandan kaybolması için 900  olarak belirledik.) tekrar başlangıç konumlarına geri çekmiş olduk.


 if (ball_1Position.X == 900) {
    ball_1Position.X = -60;
 }
Update methoduna parametre olarak gelen gameTime değişkeni ile de oyunun zamanını  da yakalamak mümkün olacaktır. Oyunun başından itibaren kaç sn veya dakika geçtiğini bu değişken ile elde ederek  string TEXT isimli değişkenimize set ediyoruz. Update methodu içerisinde ayrıca TouchPanel.GetState() methodu ile o ana denk gelen dokunmaları  da TouchCollection nesnesi yardımı ile elde edebiliyoruz ve ekrana dokunulan  noktanın koordinat eksenindeki karşılığı  ile arabamızın o an bulunduğu  nokta arasındaki mesafeyi ve bu mesafe ile temel matematiksel hesaplamalarla hızı  ya da vektörel büyüklüğü ayrıca araç ile dokunulan nokta arasındaki açıyı v.s  elde etmek kolay olacaktır. Elde edilen vektörel değerlerle arabamızın yeni  pozisyonunu carPosition.X ve carPosition.Y özelliklerine ekleyerek değiştiriyoruz. 
Update methodu ile senkronize olarak ve bu methodun hemen ardından çalışacak olan Draw methodu ile ekrana çizmek istediğimiz nesnelerimizi belirtiyoruz. Aşağıdaki Draw methoduna dikkatle bakacak olursak imaj Texture için spriteBatch.Draw ve SpriteFont için ise spriteBatch.DrawString methodlarını kullandık.

 protected override void Draw(GameTime gameTime)
 {
     GraphicsDevice.Clear(Color.White);
 
     spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
     spriteBatch.Draw(carTexture, carPosition, Color.White);
     spriteBatch.End();
 
     spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
     spriteBatch.Draw(ball_1Texture, ball_1Position, Color.White);
     spriteBatch.End();
 
     spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
     spriteBatch.Draw(ball_2Texture, ball_2Position, Color.White);
     spriteBatch.End();
 
     spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
     spriteBatch.DrawString(textFont, TEXT, textPosition, Color.Blue);
     spriteBatch.End();
 
     base.Draw(gameTime);
 }
Son olarak F5 ile projemizi çalıştıralım ve WP7 Emulatorümüz üzerinde mouse ile  ekranın çeşitli yerlerine tıklayarak Update methodu içerisindeki TouchCollection  nesnemizin beslenmesini sağlayalım. Update ve Draw methodları biz oyunu  sonlandırana kadar sürekli olarak çalışacaktır. Projemizi debug modda  çalıştıracağımız için uygulamanın çalıştığı herhangi bir anda Update  methodumuzdaki bir satıra bir Breakpoint ekleyerek, çalışma satırının direk  olarak bu breakpoint üzerinde konumlanacağını görebiliriz ve bu sırada  nesnelerin aldığı değerleri de rahatlıkla gözlemleyebiliriz.






2 adet kırmızı topun sabit hızlarda soldan sağa doğru hareketini izlerken, aynı zamanda aracımızı da ekranda dokunduğumuz noktaya doğru hareketini sağlamış olduk ve bu sırada ekranın üst kısmında yer alan text'imizin de değiştiğini göreceğiz. Emulator ekranı üzerinde arabamızdan ne kadar uzak bir noktaya dokunursak aracın o noktaya doğru ve daha hızlı bir şekilde ilerlediği hissedilecektir.























Bir sonraki makelemizde görüşmek üzere.. Kolay gelsin.
http://msdn.microsoft.com/en-us/library/bb417503.aspx
http://en.wikipedia.org/wiki/XNA_(Microsoft)

Gökhan Manduz  -  gokhanmanduz@hotmail.com