XNA ile Karakter Hareketi

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

Her oyunda bir ana karakter vardır ve biz oyuncular olarak, bu ana karakteri mouse/klavye/joystik aracılığıyla oyun evreninde kontrol ederiz.

Bu yazımda önce bir oyun evreni oluşturacak, sonra da ana oyun karakterini bu evrende hareket ettireceğiz.

Önce oyunda kullanacağımız görselleri bilgisayarımıza indirelim;

XNA ile Oyun Programlama - Karakter Hareket Çim ArkaPlan XNA ile Oyun Programlama - Karakter Hareket Sprite

Öncelikle arkaplan ve ana karakterimiz için sınıf seviyesinde değişkenlerimizi oluşturalım;

Texture2D KarakterSprite; Texture2D ArkaplanCim;</pre>

Klavye bilgisini alabilmek için KeyboardState sınıfından bir değişken ekleyelim;

KeyboardState ks;

Vector2 sınıfından bir değişken ile, ana karakterimizin oyun penceresinde konumunu tutalım;

Vector2 KarakterKonum;

Oyun sınıfının constructor‘ında (Game1 ismini GameLoop olarak değiştirelim) KarakterKonum değişkenine başlangıç değerini verelim;

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

    KarakterKonum = new Vector2(50, 50);
}

LoadContent() method’unda ArkaplanCim ve KarakterSprite değişkenlerine değer atayalım;

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

    KarakterSprite = Content.Load<Texture2D>("KarakterSprite");
    ArkaplanCim = Content.Load<Texture2D>("Cim");
}

KarakterSprite görselinde, karakterimizin dört yöne yapacağı hareketlerin tek tek görüntüleri yer alıyor.

Karakterimize yürüme efekti vermek için, aslında birden fazla görselden oluşan tek bir görsel kullanıyoruz. (Böylece hafızaya tek bir görsel yüklendiği için hafıza kullanımını az tutmuş oluyoruz)

Sırayla görselin herbir parçasını ekranda karakterimiz olarak çizdiğimizde, karaktere yürüme efektini vermiş oluyoruz.

Bir Sprite‘ın bir parçasını ekrana çizdirmek için, SpriteBatch sınıfının Draw() method’undan faydalanırız;

SpriteBatch.Draw(Texture2D, Vector2, Rectangle, Color);

Bu method’un parametreleri;

  • Texture2D, ekrana çizdireceğimiz görselin bulunduğu görseli yüklediğimiz değişken
  • Vector2, görselin ekranda çizileceği konum
  • Rectangle, görselin ekrana çizilecek parçası (Left-Top-Width-Height isminde dört özelliği vardır)
  • Color, görsele uygulanacak baskın renk değişkeni

Sınıf seviyesine aşağıdaki değişkenleri ekleyerek devam edelim;

Rectangle Arkaplan;
Rectangle Karakter;

int Kare = 0;

int Yon = 0;

GameLoop sınıfının constructor‘ına;

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

ekleyelim. Böylece, arkaplan görselinin çizileceği alanı tanımlamış olduk.

Oyun kodlarımızın en önemli iki methodundan biri, Update() method’udur;

ks = Keyboard.GetState();

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

if (ks.IsKeyDown(Keys.Down))
{
    Yon = 0;
    Kare++;
    KarakterKonum.Y += 3;
}
else if (ks.IsKeyDown(Keys.Up))
{
    Yon = 1;
    Kare++;
    KarakterKonum.Y -= 3;
}
else if (ks.IsKeyDown(Keys.Left))
{
    Yon = 2;
    Kare++;
    KarakterKonum.X -= 3;
}
else if (ks.IsKeyDown(Keys.Right))
{
    Yon = 3;
    Kare++;
    KarakterKonum.X += 3;
}

if (Kare > 5)
{
    Kare = 0;
}

Her bir yön tuşuna basıldığında Yon değişkenini farklı bir değere atadık. Ayrıca Kare değişkeninin değerini de bir artırdık.

KarakterSprite görselinde karakter’in yürüme efekti için yana doğru 6 görsel kullanıldığını görüyoruz. Kare değişkeni 5 değerinden büyük bir değere ulaştığında 0 değerine eşitleyip değişkeni sıfırlamış oluyoruz.

Her yön tuşuna basıldığında Yon değişkenine verdiğimiz değer, KarakterSprite görselinde ilgili tuşa ait yönün yukarıdan aşağıya sıra numarası aynı zamanda.

Son adımda, Draw() method’unu yazıyoruz;

GraphicsDevice.Clear(Color.CornflowerBlue);

Karakter = new Rectangle(Kare * 24, Yon * 32, 24, 32);

spriteBatch.Begin();

spriteBatch.Draw(ArkaplanCim, Arkaplan, Color.White);
spriteBatch.Draw(KarakterSprite, KarakterKonum, Karakter, Color.White);

spriteBatch.End();


Öncelikle Rectangle tipinde *Karakter* değişkenine, *KarakterSprite* değişkeninin hangi **parçasını** ekrana çizmek istediğimizi belirteceğimiz değeri atıyoruz.

Sonra *arkaplan* ve *karakterimizi* oyun penceresine **çizdiriyoruz**.

![XNA ile Oyun Programlama - Karakter Hareket Oyun Ekranı](/assets/uploads/2011/07/XNAKarakterHareket.png "XNA ile Oyun Programlama - Karakter Hareket Oyun Ekranı")

Oyunun kodlarını indirmek için tıklayınız.

XNA ile Video Oynatmak

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;</pre>

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 Hareketli Arkaplan

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

Birçok oyunda arkaplan görselinin yavaşça kaydığını görmüşüzdür. Bu tarz bir etkiyi kendi oyunlarımızda nasıl sağlayacağımızı bu yazımda inceliyor olacağım.

Her zamanki gibi öncelikle görselleri paylaşarak başlıyorum;

XNA ile Oyun Programlama - Uzay Arkaplan Resmi XNA ile Oyun Programlama - Uçak Resmi

Öncelikle sınıf seviyesinde birkaç değişken/sabit (readonly, const) ile oyun penceremizin özelliklerini ayarlayalım;

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

private readonly Color PENCERE_ARKAPLAN = Color.Black;</pre>

Oyun sınıfının constructor‘ında ilgili sabitleri kullanalım;

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

Oyun projemize, Uzay ve Ucak isimli iki tane sınıf (class) ekleyelim. Böylece arkaplan’da kayacak uzay görseli ile ilgili işleri Uzay sınıfında, klavye ile yöneteceğimiz uçak ile ilgili işleri de Ucak sınıfında gerçekleştirebileceğiz.

Ucak.cs dosyasında yeralan Ucak sınıfının yapacağı işler çok basit;

public class Ucak
{
    public Vector2 Position;
    public readonly Vector2 Size;

    public Texture2D Texture { get; private set; }

    public Ucak(Texture2D Texture)
    {
        this.Texture = Texture;
        this.Size = new Vector2(Texture.Width, Texture.Height);
    }
}

Uzay.cs dosyasında yeralan Uzay sınıfı ise, kendi Update() ve Draw() method’larına sahip olacak.** Draw()** method’unda sürekli arkaplan görselini kaydırarak oyun penceresine çizdirecek.

Bunu yapabilmek için, SpriteBatch sınıfından bir instance’a ihtiyaç duyacağız.

Uzay sınıfının constructor‘ında ihtiyacımız olacak SpriteBatch tipinden bir parametre alacak ve sınıf seviyesinde bir değişkende saklayacağız;

public class Uzay
{
    private readonly Texture2D _Texture;
    private readonly Texture2D _TextureSecond;

    private float _Position = 0f;

    private readonly int _Width;

    private readonly SpriteBatch _SpriteBatch;

    public Uzay(Texture2D Texture, SpriteBatch SpriteBatch)
    {
        this._SpriteBatch = SpriteBatch;

        this._Texture = Texture;
        this._TextureSecond = Texture;

        this._Width = _Texture.Width;

        this._Position = 0;
    }

    public void Update()
    {
        _Position -= 0.5f;

        if (_Position < -_Width)
        {
            _Position += _Width;
        }
    }

    public void Draw()
    {
        _SpriteBatch.Draw(_Texture, new Vector2(_Position, 0), Color.White);
        _SpriteBatch.Draw(_TextureSecond, new Vector2(_Position + _Width, 0), Color.White);
    }
}

Uzay sınıfının Update() method’unda, arkaplan görselini sürekli 0.5 birim sola kaydırıyoruz.

Not : Arkaplan görseli kaydıkça ekrandan dışarı çıkıyor olacak, arkaplansız kalmamak için aslında ekrana yanyana iki tane arkaplan görseli çizdiriyoruz.

Gelelim bu sınıflardan değişkenlerimizi oluşturmaya ve oyun sınıfımıza eklemeye;

</pre><pre class="brush:csharp">private Uzay Arkaplan; private Ucak SavasUcagi;

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

Arkaplan = new Uzay(Content.Load&lt;Texture2D&gt;("Uzay"), spriteBatch);
SavasUcagi = new Ucak(Content.Load&lt;Texture2D&gt;("Ucak"));
SavasUcagi.Position = new Vector2(50, PENCERE_YUKSEKLIK / 2); }</pre>

Oyunumuzun Update() method’unda, klavye tuş vuruş durumlarına göre uçağımızı kontrol ediyor olacağız. Ayrıca Arkaplan değişkeninde bulunan Uzay sınıfının instance‘ından Update() method’unu çağırıyor olacağız. Böylece arkaplan görseli 0.5 birim sola kaymış olacak ve oyun penceresine yeni yerinde çizilecek.

protected override void Update(GameTime gameTime)
{
    KeyboardState ks = Keyboard.GetState();

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

    if (ks.IsKeyDown(Keys.Left))
        SavasUcagi.Position.X -= (ks.IsKeyDown(Keys.LeftShift) || ks.IsKeyDown(Keys.RightShift)) ? 6 : 3;

    if (ks.IsKeyDown(Keys.Right))
        SavasUcagi.Position.X += (ks.IsKeyDown(Keys.LeftShift) || ks.IsKeyDown(Keys.RightShift)) ? 6 : 3;

    if (ks.IsKeyDown(Keys.Up))
        SavasUcagi.Position.Y -= 3;

    if (ks.IsKeyDown(Keys.Down))
        SavasUcagi.Position.Y += 3;

    if (SavasUcagi.Position.X < 0)
        SavasUcagi.Position.X = 0;

    if (SavasUcagi.Position.X > PENCERE_GENISLIK - SavasUcagi.Size.X)
        SavasUcagi.Position.X = PENCERE_GENISLIK - SavasUcagi.Size.X;

    if (SavasUcagi.Position.Y < 0)
        SavasUcagi.Position.Y = 0;

    if (SavasUcagi.Position.Y > PENCERE_YUKSEKLIK - SavasUcagi.Size.Y)
        SavasUcagi.Position.Y = PENCERE_YUKSEKLIK - SavasUcagi.Size.Y;

    Arkaplan.Update();

    base.Update(gameTime);
}

Uçağı sağa/sola yönetmek için kullandığımız ok tuşlarına (Left - Right) basılırken, Shift tuşlarından birine (LeftShift - RightShift) basılıyorsa, uçağı normalin iki katı hızlı ilerletiyoruz (3 birim yerine 6 birim)

Son olarak, Draw() method’unda uçağı ekrana çizdirecek ve Uzay sınıfının instance‘ının (Arkaplan değişkeni) Draw() method’unu çağıracağız;

protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(PENCERE_ARKAPLAN);

    spriteBatch.Begin();

    Arkaplan.Draw();
    spriteBatch.Draw(SavasUcagi.Texture, SavasUcagi.Position, Color.White);

    spriteBatch.End();

    base.Draw(gameTime);
}


Sonuç olarak, yukarıdaki kodları yazdıktan sonra oyun projemizi başlatırsak;

![XNA ile Oyun Programlama - Hareketli Arka Plan Ekran Görüntüsü](/assets/uploads/2011/06/HareketliArkaPlan.jpg "XNA ile Oyun Programlama - Hareketli Arka Plan Ekran Görüntüsü")

Hareketli ArkaPlan oyun projemizin kodlarını buradan indirebilirsiniz.

XNA - Kısa sorular, Kısa cevaplar

Mouse ikonumu bulamıyorum?

Evet, varsayılan olarak XNA, oyun penceresi içerisinde mouse ikonunu gizler. Eğer mouse’u görmek istiyorsanız;

this.IsMouseVisible = true;</pre>

kodunu eklemeniz gerekir.

Oyunu farklı çözünürlükte çalıştırmak istiyorum

XNA ile oyun geliştirmeye çalışan her programcının çok kısa süre sonra merak ettiği bir sorudur bu.

Çözüm;

public Game1()
{
    graphics = new GraphicsDeviceManager(this);

    Content.RootDirectory = "Content";

    /// Oyun penceresinin çözünürlüğünü 1920x1080 ayarlar
    this.graphics.PreferredBackBufferWidth = 1920;
    this.graphics.PreferredBackBufferHeight = 1080;
}

Not : Bu konu ile ilgili XNA - Oyun ekranının boyutlarını belirlemek yazımı okumanızı tavsiye ederim.

Oyunumu tam ekran oynatmak istiyorum

Çözünürlüğü değiştirdikten hemen sonra, tam ekran oyun nasıl oynatılır? sorusu gelir;

protected override void Initialize()
{
    /// Eğer tam ekran değilse, tam ekran moduna geç!
    if (!graphics.IsFullScreen)
    {
        graphics.ToggleFullScreen();
    }

    base.Initialize();
}

Not : Bu konu ile ilgili XNA - Oyun ekranının boyutlarını belirlemek yazımı okumanızı tavsiye ederim.

Oyun penceremin aktif olup/olmadığını nasıl anlarım?

Windows oyunları o anda çalışan tek uygulama olmayabilirler. Oyuncular, oyun oynarken, email adreslerini kontrol etmek, internette bir kelime araştırmak veya diğer oyuncular ile farklı ortamlarda sohbet etmek isteyebilirler.

Oyun penceresinden başka bir uygulamaya geçtiklerinde (yani oyun penceresi focus kaybettiğinde) oynadıkları oyunun durmasını (pause moduna geçmesini) isterler.

Oyun penceresinin Active veya InActive olduğunu kontrol etmemiz, Active değilse, Pause moduna geçmemiz gerekmektedir;

Not : Bu konu ile ilgili XNA Oyunu / Çanakkale Geçilmez - 1 yazımı okumanızı tavsiye ederim.

protected override void Update(GameTime gameTime)
{
    if (this.IsActive)
    {
        /// Sadece oyun penceresi aktif iken yapılması gereken işleri
        /// buraya yazıyoruz

        /// Joystik, klavye, mouse hareketlerini algılamak
        /// Yapay zeka görevlerini yürütmek gibi
    }

    base.Update(gameTime);
}

Oyun penceresinin başlığını nasıl değiştiririm?

protected override void Initialize()
{
    this.Window.Title = "Oyun oynamak içindir!";

    base.Initialize();
}


XNA Oyunu / Çanakkale Geçilmez – 2

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

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

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

int SKOR_ATIS = 0; int SKOR_PUAN = 0;

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

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

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

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

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

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

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

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

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

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

</pre><pre class="brush:csharp">if (pks.IsKeyDown(Keys.Space) && ks.IsKeyUp(Keys.Space)) GulleAtesle();</pre>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

</pre><pre class="brush:csharp">foreach (GameObject Gulle in Gulleler) { if (Gulle.IsAlive) { Gulle.Position += Gulle.Velocity; if (!Pencere.Contains(Gulle.TextureRectangle)) Gulle.IsAlive = false;

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

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

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

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

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

GraphicsDevice.Clear(Color.CornflowerBlue);

spriteBatch.Begin(SpriteBlendMode.AlphaBlend);

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

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

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

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

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

Texture2D Karakterler;
Texture2D Sayilar;

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

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

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

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

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

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

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

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

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

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

XNA ile Oyun Programlama - Çanakkale Geçilmez Oyunu

Oyunu tüm kodlarını buradan indirebilirsiniz.

Engin Polat hakkında

Senior Software Engineer, @Microsoft

Ada ve Ege'nin babası ;)

Kategoriler

İstatistik

Makale Adedi: 484

Creative Commons Lisansı