Bu yazımı okumadan önce XNA konusundaki diğer makalelerimi okumanızı öneririm.
Bu sefer yapacağımız oyun, 30 Ağustos‘un ruhuna uygun olacak - Çanakkale Geçilmez.
Önce görsellerimizi verelim;
İki tane de ses dosyamız var;
Başlayalım oyunumuzu yazmaya; Çanakkale Geçilmez projemizi oluşturduktan ve Game1.cs‘in ismini GameLoop.cs olarak değiştirdikten sonra, class seviyesindeki değişkenlerimizi tanımlayalım;
public const int PENCERE_GENISLIK = 800; public const int PENCERE_YUKSEKLIK = 600; public const bool TAM_EKRAN = false;
Texture2D Arkaplan;</pre>
Oyun penceremizin sınırlarını tutacağımız Rectangle tipinde bir değişkeni class seviyesindeki değişkenlerimize ekleyelim;
Rectangle Pencere;
Gelelim bu değişkenleri kullanmaya, GameLoop class‘ımızın constructor methodunda aşağıdaki kodları yazalım;
graphics.PreferredBackBufferWidth = PENCERE_GENISLIK; graphics.PreferredBackBufferHeight = PENCERE_YUKSEKLIK; graphics.IsFullScreen = TAM_EKRAN; Pencere = new Rectangle(0, 0, PENCERE_GENISLIK, PENCERE_YUKSEKLIK);
Ses dosyalarımız için class seviyesinde değişkenlerimiz tanımlayalım;
SoundEffectInstance ArkaplanSes; SoundEffectInstance GemiVurulduSes;
LoadContent() method‘unda değişkenlerimize yükleme işlemlerini gerçekleştirelim;
Arkaplan = Content.Load<Texture2D>("Arkaplan"); ArkaplanSes = Content.Load<SoundEffect>("pong").CreateInstance(); GemiVurulduSes = Content.Load<SoundEffect>("ir_begin").CreateInstance(); ArkaplanSes.IsLooped = true; ArkaplanSes.Volume = 0.3f; ArkaplanSes.Play();
Ses dosyaları ile yaptığımız bu işlemleri XNA ile Pong oyunu yazalım – 2 yazımdan hatırlayacaksınız.
Bu oyunumuzda aktörleri Nesne Yönelimli Programlama (Object Orriented Programming) kurallarına uyarak oluşturalım; oyun projemize yeni bir class ekleyelim ve ismini GameObject.cs verelim.
Çanakkale Geçilmez oyunumuzda oluşturacağımız tüm nesneleri GameObject class’ından oluşturacağız.
public class GameObject { public bool IsAlive; public Texture2D Texture; public Vector2 Position; public Vector2 Center; public Vector2 Velocity; public float Rotation; private Rectangle _TextureRectangle; public Rectangle TextureRectangle { get { _TextureRectangle.X = (int)Position.X; _TextureRectangle.Y = (int)Position.Y; return _TextureRectangle; } } public GameObject(Texture2D Texture) { this.IsAlive = false; this.Texture = Texture; this.Center = new Vector2(Texture.Width / 2, Texture.Height / 2); this.Position = Vector2.Zero; this.Velocity = Vector2.Zero; this.Rotation = 0; this._TextureRectangle = new Rectangle(0, 0, Texture.Width, Texture.Height); } }
Yukarıdaki kodu incelediğimizde;
GameObject sınıfının constructor‘ı sadece bir Texture2D nesnesi alıyor ve bu parametreyi kendi iç değişkenlerinin değerlerini hesaplamada kullanıyor.
Artık GameLoop sınıfımızın class seviyesinde, Top nesnesi için, GameObject sınıfından değişken oluşturabiliriz.
public GameObject Top;
LoadContent() methodunda bu değişkenin atamasını yapalım;
Top = new GameObject(Content.Load<Texture2D>("Top"));
Update() methodunda Top nesnemizin yerini hesaplayalım;
KeyboardState ks = Keyboard.GetState(); if (ks.IsKeyDown(Keys.Left)) Top.Position.X -= 5; if (ks.IsKeyDown(Keys.Right)) Top.Position.X += 5;
Aynı method içerisinde Top nesnemizin dönüş miktarını da hesaplayabiliriz; (Yukarı ve Aşağı tuşlarına basıldıkça 10 derece dönmesini sağlayacağız)
if (ks.IsKeyDown(Keys.Up)) Top.Rotation += MathHelper.ToRadians(10); if (ks.IsKeyDown(Keys.Down)) Top.Rotation -= MathHelper.ToRadians(10);
MathHelper sınıfının static ToRadians fonksiyonu sayesinde, Top’umuzun dönme açısını radian cinsinden kolaylıkla hesaplayabiliyoruz.
Top‘umuzun dönme açısının -90 ile +90 dereceler arasında olduğundan ve ekrandan dışarı çıkmayıp, görünür olduğundan emin olalım;
if (Top.Position.X < 0) Top.Position.X = 0; if (Top.Position.X > PENCERE_GENISLIK) Top.Position.X = PENCERE_GENISLIK; if (Top.Rotation > MathHelper.ToRadians(90)) Top.Rotation = MathHelper.ToRadians(90); if (Top.Rotation < MathHelper.ToRadians(-90)) Top.Rotation = MathHelper.ToRadians(-90);
Oyunun, Windows’ta başka bir pencereye geçilmesi esnasında (focus kaybetme) bekleme moduna geçmesini, tekrar oyuna dönüldüğünde ise (focus alma), kaldığı yerden devam etmesini sağlayalım;
Öncelikle sınıf seviyesindeki değişkenlerimize,
</pre><pre class="brush:csharp">bool OYUN_DEVAM_EDIYOR = true;</pre>
ekliyoruz. Microsoft.Xna.Framework.Game sınıfından türetildiği için GameLoop sınıfının OnActivated ve OnDeactivated method’larını override edebiliriz.
OnDeactivated method’unda, oyun penceresinin focus kaybettiğini, OnActivated method’unda ise, oyun penceresinin focus aldığını anlayabiliriz.
protected override void OnActivated(object sender, EventArgs args) { OYUN_DEVAM_EDIYOR = true; ArkaplanSes.Resume(); base.OnActivated(sender, args); } protected override void OnDeactivated(object sender, EventArgs args) { OYUN_DEVAM_EDIYOR = false; ArkaplanSes.Pause(); base.OnDeactivated(sender, args); } Şu ana kadar oyunumuza hiç düşman eklemedik. Bir sonraki yazımda düşmanları ekleyeceğiz. *Top'umuzla da düşmanları vurup, puan kazanıyor olacağız.*
Senior Software Engineer, @Microsoft
Ada ve Ege'nin babası ;)
Makale Adedi: 484