Bir önceki yazımda XNA dünyasına ilk adımımızı atıp bu dünyayı biraz da olsa tanımaya çalıştık. Şimdi bu dünya içinde bir oyunun yaşam döngüsü nasıl ilerliyor bunu inceleyeceğiz. Dolayısıyla burada anlatacaklarıma yabancılık çekmemek için önce, XNA Dünyasına Yolculuk isimli yazıyı okumanızı tavsiye ederim.
Bir oyun döngüsünü genel hatlarıyla aşağıdaki şekilde özetleyebiliriz;
- Öncelikle oyunun başlangıç durumları ile ilgili değerlerin ayarlanacağı bir hazırlık aşaması çalışır.
- Oyun içinde kullanılacak kaynakların yüklenmesi.
- Hazırlık ve yükleme aşamalarından hemen sonra oyun döngüsü başlayabilir. Döngü içinde aşağıdaki işlemler yapılabilir.
- Kullanıcı girişlerinin takip edilmesi
- Gereken hesaplamaların yapılması (çarpışma, oyunu kazanma, oyunu kaybetme, vs mantıksal kontrolleri gibi)
- Oyun döngüsünü sonlandıracak veya geçici olarak durduracak etkenlerin kontrolü. (ESC tuşuna basılması, vs)
- Nesnelerin ekrana çizilmesi. Seslerin durumlara göre çıkartılması.
- Kullanıcı girişlerinin takip edilmesi
- Tüm bu giriş ve çıkış işlemlerinin sonlandırılması
- Kaynakların serbest bırakılması.
Şimdi programı derleyip çalıştırdıktan sonra işleve konacak olan ilk metodumuza bir bakalım (Entry Point). Uygulamanın başlangıç noktası, önceki yazımda da belirttiğim gibi Program.cs sınıfıdır.
static class Program
{
static void Main(string[] args)
{
using (Game1 game = new Game1())
{
game.Run();
}
}
}Kısaca özetlemek gerekirse, başlangıç noktası olan Main methodu içinde game adında oyunumuzu temsil eden bir Game1 nesnesi yaratılıyor. Run methodu ise anlaşılacağı gibi oyunumuzun başlamasını sağlıyor.
Oyun Döngüsündeki Temel Aşamalar
Buraya kadar anlattığımız tüm adımları gruplamak istersek eğer ortaya aşağıdaki gibi 3 temel aşama çıkmış olur.
- Game Initialization (Hazırlık)
- Game Loop (Döngü)
- Finalization (Bitiş)
1 - Game Initialization
Hatırlarsanız eğer Game1 sınıfı içinde 2 tane nesne tanımlaması yapılmıştı. Bunlardan biri GraphicsDeviceManager tipinden bir nesne, diğeri de SpriteBatch tipinden bir nesneydi. İşte bu GraphicsDeviceManager tipindeki graphics nesnesi, oyun dünyasında yer alacak olan tüm nesnelerin, bu dünya içine eklenmelerinden, ekran kartı ile ilgili ayarlamalardan, pencere boyutunun belirlenmesinden ve bunlar gibi bir çok ayarın yönetilmesinden sorumludur. Diğer yandan spriteBatch nesnesi ise ekrana yazı yazmak veya 2 boyutlu resimleri ekran üzerinde göstermek ve yönetmekten sorumludur. Bunlar dışında Constructor içinde kaynakların yer aldığı root klasörü belirten bir tanımlamada mevcuttur.
Content.RootDirectory = "Content";Content PipeLine Manager
PipeLine, iş hattı olarak Türkçe ' ye çevrilen bir kelimedir. Content Pipe Line Manager 'ı bu şekilde Türkçe' ye çevirince "içerik işhattı yönetimi" gibi birşey oluyor ve ilk olarak anlamsız gelebiliyor. Bunun yerine daha anlaşılır olması amacıyla buna, oyunumuzda kullanacağımız içeriklerin yönetiminden sorumlu olduğu için, içerik yönetim modülü diyebiliriz.
Peki oyunlarda bir içerik yönetim modülü olması neden önemlidir? Kısaca bu sorunun cevabını aramak gerekirse; geliştirdiğimiz uygulama bir oyun projesi olduğu için görsel ve işitsel olarak bir çok farklı medya türü proje dahilinde kullanılacak demektir. Bir masaüstü uygulaması geliştirirken çok az resim dosyasına ihtiyacınız olur. Bunun yanında genelde ses veya video formatında bir dosyaya da ihtiyacınız pek olmaz. Fakat oyunlarda bu durum tam tersidir. Bir oyun projesinde binlerce resim, 3D obje, ses vs gibi farklı formatlarda bir çok dosyaya ihtiyacınız olur. Bu dosyaları yönetilmek bir yana bunların işlenebilmeside başlı başına bir iştir. Dolayısıyla xna' in bize sunduğu bu modül, bu farklı formattaki dosyaların ele alınış ve işleniş biçiminden sorumludur. Dolayısıyla ekrana bir şey çizileceği zaman veya bir ses çıkartılacağı zaman bu tamamen ContentPipeLine mimarisinin sunduğu imkanlar dahilinde ve onun mimarisine göre gerçekleşen bir şeydir.
Content Pipe Line mimarisini incelemeden önce aşağıdaki grafiğe bakabilirsiniz.
Grafik XNA'in sahip olduğu Content Pipe Line mimarisinin basit bir modelidir. Öncelikle en baştaki mavi kutucuklar XNA' in desteklediği bazı dosya tiplerini temsil ediyor. Bu dosya tipindeki veriler öncelikle uygun Importer 'lar tarafından okunuyorlar. Ardından bu verilerin herbiri ContentDOM dediğimiz bir içerik bulutunda toplanıyor. Processor 'lar kendilerine uygun olan verileri bu buluttan alıyorlar ve veriyi XNA 'in anlayacağı şekilde işliyorlar. ContentCompiler bu verileri derliyor ve .XNB formatına çeviriyor. Ardından bu .xnb 'ler oyun içinde kullanılıyor.
Şimdi Importer 'ların okuyabileceği farklı dosya formatlarına kısaca bir bakalım.
3D File Format : X dediğimiz DirectX ile oluşturulmuş dosyalardır. Bunun yanında FBX ise çeşitli 3D programları ile yaratılan dosyalardır (3DS Max, Maya vs.. modelleri)
Material File Formats : FX, çeşitli 3D efektleri içeren dosya formatıdır.
2D File Formats : En sık kullanılan 2D dosya formatlarıdır. (BMP, DDS, DIB, HDR, JPG, PFM, PNG, PPM, TGA, vs)
Font : Yazı tipleridir.
Audio File Format : .XAP, daha öncede bahsettiğimiz XACT adındaki ses yönetim aracı sayesinde oluşturulan dosya formatıdır.
Importer 'ların okuduğu bu dosyalar, ilerde oyun içinde birer nesne olarak ele alınabilmek için processor 'lar tarafından runtime 'da birer nesne olarak oluşturulur.
2 - Game Loop
Oyun genelindeki bir çok işlem oyun döngüsü içinde gerçekleşir. Bu yüzden oyun döngüsünü yönetebilmek son derece önemlidir. Oyun döngüsü aksi belirtilmedikçe oyun boyunca sürekli çalışır. Bu yüzden bu döngü içinde yapılan işlemlere; kullanıcı girişlerinin kontrolü, yapay zeka işlemlerinin hesaplanması, oyun içindeki nesnelerin hareketleri ve bu bağlamda bu hareketler arasındaki etkileşimlerin hesaplanması, oyunu sonlandırıcı durumların kontrolü, oyun içindeki ses efektlerinin ve müziklerin gerçekleşmesi gibi şeyleri örnek olarak verebiliriz. Aynı zamanda oyun döngüsü içinde oyunda yer alacak nesnelerin ekrana çizilmeside gerçekleşir.
Bu bağlamda XNA bize Microsoft.Xna.Framework.Game sınıfı içinde, oyun döngüsünü gerçekleştirebileceğmiz 2 tane override edilebilen method sunuyor.Bu metodlar pek yabancı gelmeyecektir çünkü bunlar daha önce bahsettiğmiz Update ve Draw methodlarından başkası değildir. Kısa ve basit bir şekilde özetlemek gerekirse, Update methodu içinde yapay zeka, çarpışma kontrolü, oyunu sonlandırıcı etkenler gibi oyun içinde genel olarak hesaplanması gereken mantıksal işlemler yapılabilir. Draw metodu ise sadece ekrana bir şeyler çizmek için kullanılabilir. Böylece oyun döngüsünü sürdürebilmek için gereken işlemleri birbirinden ayrıştırıp daha kolay bir şekilde yönetilebiliriz.
Dikkat edilmesi gereken bir diğer nokta da, bu 2 metodun aldıkları parametredir. Dikkat ettiyseniz her 2 metod da GameTime tipinden birer parametre alıyor.
protected override void Update(GameTime gameTime)
protected override void Draw(GameTime gameTime)GameTime oyun içinde gerçekleşecek olan olayların ortak bir zaman dahilinde oluşmasını sağlar.
Update metodu içinde yapılabileceklere somut bir örnek vermek gerekirse eğer; kullanıcının input cihazları ile yaptığı girişleri kontrol etmek verilebilir. Mesela aşağıdaki kod bloğu ile kullanıcının esc tuşuna basıp basmadığı kontrol ediliyor. Eğer esc tuşuna basıldıysa oyun sonlandırılıyor. Bu tarz örnekleri ilerde uygulama yapmaya başladığımız zaman sık sık kullanacağız zaten. (Kodu Update metodu içine yazmanız yeterli)
KeyboardState ks = Keyboard.GetState();
if (ks.IsKeyDown(Keys.Escape))
{
this.Exit();
}Draw metodu içinde bulunan aşağıdaki kod ise ekran temizlendiği zaman arka plan renginin ne olacağını belirtiyor.
GraphicsDevice.Clear(Color.CornflowerBlue);
3 - Game Finalization
XNA 'de olayların ve nesnelerin bellekten kaldırılması arka planda gerçekleşen bir işlemdir. Bu işlem tabiki .net platformunun sahip olduğu özelliklerden biri olan GarbageCollector sayesinde gerçekleşiyor. Oyun içinde yaratılan nesnelere bir daha ihtiyacımız olmadığı zaman bellekte tutulmasının bir anlamı yoktur. Bu amaçla bu nesnelerin sonlandırılması yani bellekten çıkartılması gerekir.
Bu yazıda bir oyun döngüsünde gerçekleşen işlemlere çok temel düzeyde yaklaşarak kavramaya çalıştık. Birazda xna 'in content pipe line mimarisine değinip fikir sahibi olmaya çalıştık.
Kaynaklar :
Beginning XNA 2.0 Game Programming
http://blogs.msdn.com/xna/archive/2006/08/29/730168.aspx
Mehmet Aydın Ünlü

0 yorum:
Yorum Gönder