11.05.2010

XNA Kayan Arka Plan

Merhaba arkadaşlar,

Bu yazımızda platform oyunlarının en temel tekniklerinden biri olan arka planı kaydırma olayını xna ile nasıl yapabileceğimizi inceleyeceğiz. Yapacağımız örnekte bu olay zamanla doğru orantılı bir şekilde çalışacaktır. Bu teknik aynı zamanda Shoot-Em Up türündeki oyunlarda da çok sık kullanılır. Örnek vermek gerekirse Commodore64 dönemindeki River Raid oyununu hatırlayanlar vardır belki. Bu oyunda sürekli yukarıdan aşağıya doğru kayan bir oyun dünyası vardır. Platform oyunlarında ise ekranın kaydığı yön genelde basılan tuşa göre değişkenlik gösterir. Örneğin Mario oyununda oyuncu sağa gitmek istediği zaman oyun sahnesi sola doğru kaymaya başlar. Oyuncu eğer herhangi bir yön tuşuna basmazsa oyun sahnesi sabit kalır. Diğer bir örnekte Prince of Persia oyunudur. Bu oyunda da sahnenin yukarı-aşağı ve sağ-sol olmak üzere kaydığı 4 farklı yön vardır. Şimdi biz de en basit haliyle arka planı nasıl kaydırabiliriz bunu inceleyeceğiz.

Uygulamaya Başlangıç

Öncelikle yeni bir Windows Game projesi oluşturalım.

Örneğimizin asıl amacı buradaki temel tekniği anlamak olduğu için, sahnelerin çok uzun olmasına gerek yok. Bu yüzden 3 farklı arka plan bizim için yeterlidir. Görüntüler farklı olabilir ama yanyana geldiklerinde mutlaka bir uyum içinde olması gerekiyor tabiki. Şimdi biraz teknikten bahsetmek gerekirse aslında çok basit olduğunu söylemek gerekiyor. Burada önemli olan resimlerimizin boyutlarıdır. Şöyle ki; ilk resmin ekranda xy(0,0) noktasında oluştuğunu düşünelim. Ozaman ikinci resim, ilk resmin devamı niteliğinde olacağı için bunun oluştugu nokta, xy(1.resmin_oluştuğu_X_noktası + 1.resmin_genişliği, 0) olacaktır. Dolayısıyla üçüncü resim de, xy(2.resmin_oluştuğu_X_noktası + 2.resmin_genişliği, 0) olacaktır. Böylece bir bütünlük sağlanmış olacaktır.

Kod yazmaya geçmeden önce bahsettiğim gibi örneğimiz için 3 tane resim hazırlamıştım. Bunları aşağıdan kopyalayıp, Content içine atabilirsiniz (isimlerini bg1, bg2, bg3 olarak kaydetmeyi unutmayın)


Şimdi ekrandaki nesneleri daha rahat kontrol edebilmek için projemize GameObject adında bir sınıf ekleyelim. Sınıfımızın yapısı son derece basit olacaktır. Ekranda gösterilecek imajı tutacak olan bir alan ve bunun boyutu ile poziyonunun tutacak birer alan yazmak örneğimiz için yeterlidir. Bunun dışında bu değerleri kolay bir şekilde set edebilmek için de constructor 'ı overload ediyoruz. GameObject sınıfı aşagıdaki şekildedir.

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;


namespace XNAScrollingBackground
{
public class GameObject
{
public Texture2D texture;
public Vector2 size;
public Vector2 position;


public GameObject(Texture2D texture, Vector2 size, Vector2 position)
{
this.texture = texture;
this.size = size;
this.position = position;
}
}
}


GameObject sınıfımızı yazdıktan sonra Game1.cs dosyamıza dönelim ve aşağıdaki gibi her bir arkaplan için global olarak 3 tane GameObject nesnesi tanımlayalım

GameObject bg1;
GameObject bg2;
GameObject bg3;


Daha sonra LoadContent() methodu içinde bunlardan birer tane nesne oluşturalım.

bg1 = new GameObject(Content.Load<Texture2D>("bg1"), new Vector2(500, 500), new Vector2(0, 0));
bg2 = new GameObject(Content.Load<Texture2D>("bg2"), new Vector2(500, 500), new Vector2((bg1.position.X + bg1.size.X), 0));
bg3 = new GameObject(Content.Load<Texture2D>("bg3"), new Vector2(500, 500), new Vector2((bg2.position.X + bg2.size.X), 0));


Nesneleri oluştururken kullandığım son paremetreye dikkat ederseniz eğer, az önce yukarda açıkladığım yöntemi burada aynen uyguladığımı görebilirsiniz.

Şimdi Update() methodu içinde gerekli hesaplamaları yapalım ve bu nesnelerin posizyon değerlerini zamana göre değiştirelim. Hatta buna birde hız özelliği katalım.

if (bg1.position.X < -bg1.size.X)
{
bg1.position.X = bg3.position.X + bg3.size.X;
}


if (bg2.position.X < -bg2.size.X)
{
bg2.position.X = bg1.position.X + bg1.size.X;
}


if (bg3.position.X < -bg3.size.X)
{
bg3.position.X = bg2.position.X + bg2.size.X;
}


Vector2 direction = new Vector2(-1, 0);
Vector2 speed = new Vector2(160, 0);


bg1.position += direction * speed * (float)gameTime.ElapsedGameTime.TotalSeconds;
bg2.position += direction * speed * (float)gameTime.ElapsedGameTime.TotalSeconds;
bg3.position += direction * speed * (float)gameTime.ElapsedGameTime.TotalSeconds;


Yukarıdaki kod bloğunu kısaca açıklamak gerekirse eğer; ilk olarak if blokları ile hangi resimden sonra hangisinin geleceğinin kontrolü yapılıyor. Ardından Vector2 tipindeki direction nesnesi ile ekrandaki resimlerin kayma yönü belirleniyor. Burada Vector2 'nin aldığı parametrelere dikkat ederseniz eğer bir X değeri ile bir Y değeri aldığını görebilirsiniz. Siz eğer X paremetresine -1 değerini verirseniz bu resimlerin sağdan-sola doğru kayması anlamına gelmektedir. Eğer bunu 1 yaparsanız bu sefer resimler soldan-sağa doğru kayacaktır. Aynı işlemi Y parametresi için yaptığınızda ise ekrandaki görüntünün yukardan-aşağı veya aşağıdan-yukarı dogru bir harekete sahip olmasını sağlayabilirsiniz. Yani diğer bir deyişle nesneleri Y ekseni üzerinde hareket ettirmiş olursunuz. Biz örneğimiz de sadece sağdan sola doğru bir kayma hareketi kullanacağımız için X paremetresine -1 ve Y parametresine 0 değerini vermeliyiz. Hemen ardından hareketin hızını kontrol edebileceğimiz ve yine Vector2 tipinde tanımlanmış speed adında bir nesne oluşturuyoruz. Hareket X ekseni üzerinde olduğu için de X paremetresine pozitif bir değer vermemiz hareketin hızını belirlememiz için yeterlidir.

Buraya kadar hem yönümüzü hemde hızımızı tanımladık. Fakat bu değerler henüz GameObject 'lerimiz üzerinde herhangi bir etki yaratmıyor. Bunu gerçekleştirmek için de son 3 satıra bakıyoruz. Bu satırlarda öncelikle yön ve hız değerleri çarpılıyor. Oluşan bu değer ile aynı zamanda oyunda geçen toplam saniye 'de çarpıldığı zaman artık elimizde zamanla, hıza ve yöne göre hareket eden bir arka plan oluşmuş oluyor.

Geriye sadece görüntüyü oluşturacak kodları Draw() methodu içine yazmak kalıyor. Son olarak aşagıdaki kodları da aynen Draw() methodu içine yazıyoruz.

spriteBatch.Begin();
spriteBatch.Draw(bg1.texture, bg1.position, Color.White);
spriteBatch.Draw(bg2.texture, bg2.position, Color.White);
spriteBatch.Draw(bg3.texture, bg3.position, Color.White);
spriteBatch.End();


Artık projeyi çalıştırıp sonucu görebilirsiniz.

Son olarak tavsiyem bu tarz örneklerden sonra kaynak kod üzerinde çeşitli değişiklikler yapmanızdır. Böylece yaptığınız değişikliklerin oyuna nasıl etki ettiğini somut olarak görebilirsiniz. Bu da konuyu daha net anlamanıza yardımcı olacaktır.

Kaynak : http://www.xnadevelopment.com/tutorials/scrollinga2dbackground/ScrollingA2DBackground.shtml

Örnek Uygulama

Mehmet Aydın Ünlü

XNA Oyunu Pause Durumuna Almak

Merhaba arkadaşlar,

Bu yazımızda xna ile geliştireceğimiz oyunlara pause özelliğini nasıl ekleyebileceğimizi göreceğiz. Biz örneğimizde ekrana, oyun normal halinde devam ederken "Oyun Devam Ediyor..." pause konumuna getirildiğinde de "Oyun Beklemede." yazacağız. Siz buradaki mantığı kendi oyunlarınızda istediğiniz gibi ele alabilirsiniz tabiki. Örnek vermek gerekirse, pause durumunda ekrana oyunla ilgili istatiksel bilgileri getirebilirsiniz ya da oyuncunun, oyunun ayarlarına ulaşabileceği çeşitli işlevsel menüleri getirebilirsiniz. Bunların dışında isterseniz sadece ekranı dondurmakla da yetinebilirsiniz. Bunlar tamamen oyununuzun şekline ve sizin nasıl bir pause mekanizması kullanmak istediğinizle alakalı detaylardır. Şimdi gelin bu özelliği nasıl kullanacağımızı görelim;

Öncelikle yeni bir Windows Game projesi oluşturalım. Ardından ekranda oyunun durmumunu gösterebilmek için Content projesine bir SpriteFont ekleyelim (Ekrana nasıl yazı yazabileceğimizi bir önceki makalemden öğrenebilirsiniz). Hemen ardından Game1.cs sınıfında oyunun o anki durumunu tutabilmek için bir enum tanımlayalım. Enum 'ın adı GameState ve sahip olabileceği değerlerin adı da Continue ve Pause olsun.

Bunun için aşagıdaki kodu namespace seviyesinde yazalım;

enum GameState {
Continue,
Pause
}


Ardından da sınıf düzeyinde aşağıdaki tanımlamaları yapalım.

GameState state;
SpriteFont font;


float keyPressCheckDelay = 0.25f;
float totalElapsedTime = 0;


Şimdi pause mekanizmasının çalışmasını sağlayacak aşağıdaki kodu Update methodu içine yazabiliriz.

float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
totalElapsedTime += elapsed;


KeyboardState ks = Keyboard.GetState();

if (state == GameState.Continue)
{
if (totalElapsedTime >= keyPressCheckDelay)
{
if (ks.IsKeyDown(Keys.P) || ks.IsKeyDown(Keys.Pause))
{
state = GameState.Pause;
totalElapsedTime = 0;
}
}
}
else
{
if (totalElapsedTime >= keyPressCheckDelay)
{
if (ks.IsKeyDown(Keys.P) || ks.IsKeyDown(Keys.Pause))
{
state = GameState.Continue;
totalElapsedTime = 0;
}
}
}

Kodu kısaca özetlemek gerekirse eğer, totalElapsedTime ile oyunda geçen toplam zamanı tutuyoruz. Sonraki satırlarda da klavyeden basılan tuşun P ve Pause olup olmadığına bakıyoruz. Bu durumları if blokları ile kontrol edip oyunun durumunu Pause veya Continue ile değiştiriyoruz. Şu anda durumları ekrana yazdırmadığımız için net bir sonuç göremiyoruz. Son olarak durumları ekranda gösterebilmek için LoadContent() ve Draw() methodlarına aşağıdaki kodları yazıyoruz.

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


font = Content.Load<SpriteFont>("SpriteFont1");
}


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


spriteBatch.Begin();
if (state == GameState.Continue)
{
spriteBatch.DrawString(font, "Oyun Devam Ediyor...", new Vector2(100, 100), Color.Green);
}
else if (state == GameState.Pause)
{
spriteBatch.DrawString(font, "Oyun Beklemede.", new Vector2(100, 100), Color.Red);
}
spriteBatch.End();


base.Draw(gameTime);
}


Kaynak : http://www.krissteele.net/blogdetails.aspx?id=128

Örnek Uygulama

Mehmet Aydın Ünlü

XNA Yazı Yazmak

Merhaba arkadaşlar,

Bu yazımızda bir xna uygulamasında ekrana herhangi bir yazıyı nasıl yazarız bunu inceleyeceğiz. XNA ile birlikte gelen Console.WriteLine() gibi oyun sahnesine yazı yazmamızı sağlayan hazır bir method bulunmadığı için bu işlemi yapmak biraz daha karışıktır diyebiliriz.


Hello World

Konuya daha yakından bakmak için yeni bir WindowsGame uygulaması açıyoruz. Uygulamamızın özünde yapacağı tek bir işlem var o da ekrana Hello World yazmak. Bu durum yapılması gereken adımlar bakımından herhangi bir konsol veya masaüstü uygulamasında olduğu kadar kolay değildir. Bu durumu açıklamak için, XNA 'de ekrana çizeceğimiz herşeyin aslında ContentPipeLine mimarisi tarafından işlenecek olmasıdır diyebiliriz. Dolayısıyla ekranda çizmek istediğimiz her şey bu yapıyı destekler nitelikte olmalıdır ki XNA bunu çizebilsin. Sonuç itibariyle ilk etapta yapmamız gereken şey yazımızı bir şekilde XNA 'e tanıtmaktır. Burada yazıdan kastımız aslında yazı tipi olan Font ve fontun özellikleridir. Şimdi yukarda söylediklerimi biraz daha somutlaştırmak için Solution Explorer 'dan Content projesine sağ tıklayıp, Add > New Item diyoruz. Bu işlemi yaptıktan sonra karşımıza aşagıdaki pencere gelecektir.


Açılan pencereden Sprite Font adındaki elemanı seçiyoruz ve ardından bir isim verip bunu projemize ekliyoruz. Fontumuzu projemize ekledikten sonra karşımıza bir xml dökümanı gelecektir. Eğer karşınıza böyle bir döküman gelmediyse Solution Explorer 'dan az önce eklediğimiz SpriteFont 'a çift tıklamanız yeterlidir. Aşağıdaki resimde görebileceğiniz gibi bu XML dökümanı font ile ilgili tüm özellikleri tutmaktadır.


Bunun dışında, Solution Explorer 'dan bu SpriteFont 'u seçip Property panelinden özelliklerine bakarsanız eğer, ContentImporter ve ContentProcessor özelliklerinde, Sprite Font Description adında fontlara özel bir değerin atandığını görebilirsiniz. Bu özellikler tabiki eklediğimiz yazı tipinin ContentPipeLine tarafından nasıl ele alınıp işleneceğini belirtiyor.


XML kodlarına kısaca bir bakarsanız eğer, Asset etiketi içinde bulunan Type niteliğinde Graphics:FontDescription şeklinde bir değer görürsünüz. İşte bu nitelik sayesinde bu xml dosyası içindeki bilgilerin bir Font ile ilgili bilgiler olduğunu belirtilmiş oluyor. Bunun dışında ayrıca FontName etiketi içinde ekrana yazılacak yazının tipini, Size etiketi içinde de boyutunu belirttiğini görebilirsiniz. Kısaca ekrana yazılacak yazının nasıl olması gerektiği ile ilgili tüm özellikleri buradan yönetebiliyoruz.

Artık elimizde XNA ' in anlayabileceği bir content var. Şimdi bunu kullanarak ekrana istediğimiz yazıyı yazabiliriz. Nasıl ki Texture2D adında 2 boyutlu imajlara yönelik özelleştirilmiş bir sınıfımız var ise burada da yazılar için özelleştirilmiş SpriteFont adında bir sınıf vardır. Ekrana yazımızı yazabilmek için aşağıdaki işlemleri yapmamız yeterlidir.

Öncelikle global düzeyde SpriteFont tipinde bir nesne tanımlayalım.

SpriteFont sp;

Daha sonra LoadContent methodu içinde bu nesneye projeye eklediğimiz fontu yükleyelim.

sp = Content.Load<SpriteFont>("SpriteFont1");

Son olarak ekrana istediğimiz yazıyı yazdırmak amacıyla Draw methodu içine aşagıdaki kodları yazalım.

spriteBatch.Begin();
spriteBatch.DrawString(sp, "Hello World", new Vector2(50, 50), Color.Black);
spriteBatch.End();


Bu işlemleri yaptıktan sonra uygulamayı derleyip çalıştırıp sonucu görebilirsiniz.

Draw methodu içinde dikkatinizi çekmek istediğim nokta, SpriteBatch.DrawString() isimli methoddur. Nasıl ki Draw ile ekrana bir nesne çiziliyorsa DrawString() ile de ekrana bir yazı yazılıyor.

Sonuç olarak xna ile ilgili ekrana yazı yazmak konusunda ilk başta Console.WriteLine() kadar kolay olmadığını söylesekte aslında durumun okadar da vahim olmadığını da görmüş olduk sanırım. Aslında yapılan işlemler son derece kolay şeylerdir. Sadece 1 tek methodda yaptığımız işi biraz daha fazla adıma bölüyoruz. Burada ufak bir öneri vermek gerekirse, bu tarz işlemler için mutlaka kendi Helper sınıflarınızı yazın. Mesela buradaki örnekte olduğu gibi ekrana yazmak için gereken adımları toparlayıp daha basit bir hale getirmek sizin elinizde.

Örnek Uygulama

Mehmet Aydın Ünlü

XNA Dünyasında Çarpışma

Merhaba arkadaşlar,

Bundan önceki yazılarımızda oyun programcılığı ve xna üzerine bir çok kavramsal konudan bahsettik. Bu yazılar içinde zaman zaman çeşitli kod örnekleri görsekte aktif olarak hiç kod yazmadık. Dolayısıyla artık kod yazmaya başlamanın zamanı gelmiştir diyebiliriz. Bu yazımızın konusu ise xna dünyasında bulunan iki farklı nesenin birbirleri ile çarpışıp çarpışmadığınının kontrolüdür. Bu duruma yani iki veya daha çok nesnenin birbirleriyle çarpışmasına, oyun programcılığında collision denir. Bu durumu yönetebilmek adına her ne kadar bir çok farklı teknik geliştirilmiş olsada biz bugün bunlardan en basitini inceleyeceğiz. Bunu yaparken aynı zamanda xna dünyasında bir nesne ekranda nasıl gösterilir ve klavye kontrolü ile nasıl hareket ettirilir gibi farklı teknikleri de görmüş olacağız. Kod yazmaya başlamadan önce ilerde sık sık karşılacağımız ve sahneye konulacak nesneler ile ilgili bazı temel kavramları görmekte fayda var.

Sprite : 2 boyutlu olan imajlara genel olarak sprite denir.

Texture : 3 boyutlu bir modeli giydirmek için kullanılan imajlara denir.

Tiles : Küçük küçük imajların birleştirilip büyük bir imaj haline gelmesiyle oluşan yapıdır. Mesela bir çöl zemini düşünün. Bunun için çok büyük bir çöl imajı hazırlamak yerine çok daha küçük bir imaj hazırlayıp bunu yan yana ve altalta dizerek bir bütün olarak gösterebiliriz. Bu da bize sistem kaynakları gibi unsurlardan tasarruf sağlar. Genelde zemin, duvar veya gökyüzü gibi kendini tekrar eden yapılar için kullanılır.


Kodların Ekrana Yansıması...

Yazdığımız kodların ekranda nerede ve nasıl görüntüler oluşturacağını anlayabilmek için önce monitörümüzü tanımak gerekiyor. Kısaca özetlemek gerekirse; iki boyutlu bir düzlem olan monitör üzerinde görüntü elde edeceğimiz için öncelikle bize bu iki boyutu temsil edecek iki doğru gerekiyor. Bu iki doğrunun oluşturduğu düzlem hepimizin lisede gördüğü koordinat sisteminin ta kendisidir. Dolayısıyla bizim ekran üzerinde oluşturacağımız her nesnenin pozisyonu bu x ve y doğruları ile belirlenir. Fakat bizim kullanacağımız koordinat sistemi biraz daha farklıdır. Şöyle ki; standart koordinat sisteminde orjin (x ve y değerlerinin sıfır olduğu nokta), düzlemin tam ortasında x ve y doğrularının kesiştiği noktadır. Fakat monitörümüzün kullandığı koordinat sisteminde orjin, monitörümüzün sol üst köşesidir. Dolayısıyla görünürde eksi değer yoktur. Bu da nesnelerin hareketlerini daha kolay yönetmemizi sağlıyor diyebiliriz. Resim 1 'de iki farklı koordinat sistemi gösterilmiştir.


Bu düzlemler teoride sonuza kadar gider. Fakat biz sonlu bir ekranda çalışıyoruz. Yani kullandığımız ekranların fiziksel olarak sabit bir genişlik ve yükseklik değerleri vardır. Örneğin benim bilgisayarımın ekran boyutu 15.4" 'tir. Aynı zamanda bu ekranın desteklediği farklı çözünürlük değerleri de vardır. Örneğin 1280x800 gibi. Şimdi ekran üzerindeki en küçük noktaya piksel dediğimizi belirttikten sonra, biz bu çözünürlük değeriyle 1280 piksel genişliğe ve 800 piksel yüksekliğe sahip bir kullanım alanına sahip oluruz. İşte bizim ekran üzerindeki koordinat sistemimizin sınırları da bu çözünürlük değerlerine bağlıdır. Bu şu demektir, 1280 x 800 çözünürlüğe sahip bir ekranda dikey doğruda 801. piksele koyacağımız bir nokta ekranda görünmeyecektir.

Bu bilgiler ışığında, nesneler nasıl hareket ediyor sorusunun cevabı artık çok daha anlaşılır olacaktır sanırım. Şöyle ki; eğer nesneyi sağa doğru hareket ettirmek istiyorsak yapmamız gereken tek şey, nesnenin sahip olduğu x değerinini arttırmaktır. Aynı şekilde sola doğru gitmesini istiyorsak yapmamız gereken şey, nesnenin sahip olduğu x değerini küçültmektir. Bu x ve y değerlerini nesnemizi oluşturan sınıfın özellikleri olarak düşünebilirsiniz. Nitekim birazdan böyle bir örnek yapacağız.


Uygulamaya Başlangıç


Artık kod yazmaya başlayıp ilk uygulamamızı geliştirebiliriz. Bu uygulamada ilk olarak ekrana bir nesne yerleştirip ardından bunu klavye yardımı ile hareket ettireceğiz. Son olarak ta ikinci bir nesne ekleyip bunları hareket ettirip çarpışıp çarpışmadığını kontrol edeceğiz.

Şimdi Visual Studio 'yu açalım ve File>NewProject menüsünden Windows Game (3.0) şablonunu seçip yeni bir uygulama yaratalım. Karşımıza ilk olarak önceki makalemizde incelediğimiz Game1.cs sınıfı gelecektir. Dilerseniz standart olarak gelen yorum satırlarını silebilirsiniz.

Uygulamada kullanacağımız imajları kolay bir şekilde yönetebilmek için Content projesine Sprites adından bir klasör ekleyelim (Content sağ tık>Add>New Folder). Ardından resimleri sürükle bırak yöntemiyle Sprites klasörü içine atabilirsiniz.


İlk olarak en basit haliyle bir nesneyi ekranda gösterip sonra bunu daha modüler bir şekilde nasıl yaparız, buna bakacağız. Ayrıca burada nesne yönelimli programlamanın en basit örneklerinden birini de görmüş olacağız.

XNA 'de 2 boyutlu nesneleri yönetebilmek adına özelleştirilmiş Texture2D adında bir sınıf geliştirilmiştir. Dolayısıyla öncelikle yapmamız gereken bu tipte bir nesne tanımlamaktır.

Texture2D sprite1;

Artık elimizde 2D Texture 'leri tutacak bir nesnemiz var. Peki biz bu nesne sayesinde herhangi bir imajı nasıl yükleceğiz. Bunun için LoadContent() methodu içine aşağıdaki kodu yazıyoruz.

sprite1 = Content.Load<Texture2D>("Sprites/sprite1");

Burada parametre olarak verdiğmiz resim adresinde neden resmin uzantısını belirtmedik diye düşünebilirsiniz. Bunun nedeni ise parametre olarak verdiğimiz değerin aslında resmin adından oluşmuyor olmasıdır. Solution Explorer 'dan resmi seçip, Properties panelinden özelliklerine bakarsanız eğer aşağıda ki görüntü ile karşılaşırsınız.

Burada önemli olan değer AssetName özelliğidir. Bunu klasik Name özelliğine benzetebilirsiniz. İşte bizim Load methoduna parametre olarak vereceğimiz değer de bu isimdir.

Bir diğer önemli özellik ise ContentImporter ve ContentProcessor özellikleridir. Bu özelliklerde XNA 'in desteklediği çeşitli formatlar vardır. Seçtiğiniz dosya formatına uygun importer ve processor seçmek gerekmektedir. Aşağıdaki resimde Sprite1 için uygun Importer tipini görebilirsiniz.


Kodumuza geri dönersek eğer, anlaşılabilirliği kolaylaştırmak adına sprite1 adındaki değişkenimize imajımız atanmış diyebiliriz. Eğer şu anda uygulamayı F5 ile derleyip çalıştırırsanız ekranda hiçbir şey göremezsiniz. Aslında şu anda imajımız yüklenmiştir fakat henüz bunu ekrana çizdirmediğimiz için göremiyoruz. Hatırlarsanız daha önce SpriteBatch nesnesini tanıtırken çeşitli nesnelerin ekrana çizilmesinden sorumludur demiştik.

Dolayısıyla biz bu sorumluluğu önce;
  • başlatmalıyız sonra,
  • imajı ekrana çizdirmeliyiz ve en sonunda da,
  • bu sorumluluğu sonlandımalıyız
Bu adımları yapabilmek adına aşağıdaki kodları Draw methodu içine yazmalıyız.

spriteBatch.Begin();
spriteBatch.Draw(sprite1, new Vector2(10, 10), Color.White);
spriteBatch.End();


Şimdi bu üç satır koda kısaca bir bakalım. İlk olarak bir çizim yapılacağı zaman bunu spriteBatch 'e Begin methodu ile bildirmek gerekiyor. Ardından çizme işleminin gerçekleşmesi için spriteBatch nesnesinin Draw methodunu çağırmak gerekiyor. Draw methodunun çeşitli overload edilebilir şekilleri bulunmaktadır. Biz burada 3 parametre alacak şekilde kullandık. 1.parametre, çizilecek olan nesneyi gösteriyor. 2. parametre, nesnenin ekranda ki pozisyonunu gösteriyor. 3. parametre olarakta renk değeri veriliyor(şu anda rengin bir geçerliliği yok) Son olarakta spriteBatch'e End methodu ile çizim işlemini sonlandırması gerektiğini söylüyoruz. Sonuçta programı derleyip çalıştırırsak nesnemizi oyun sahnesinde görebiliriz.

Şimdi yaptığımız bu işlemi bir adım daha ileri götürelim ve basitte olsa nesne yönelimli programlamanın faydalarını kullanmaya başlayalım.


Kendi Sınıfımızı Geliştirelim


İsterseniz buraya kadar yazdığımız kodları silebiliriz veya yeni bir proje üzerinden de gidebiliriz (Yeni proje için resimleri Sprites klasörü altına taşımayı unutmayalım).

İlk olarak sahne üzerindeki nesnelerimizi temsil edecek çok basit bir sınıf yazacağız. Bu sınıfın bazı temel özellikleri olacak. Bunlar ekranda hangi imajın gösterileceğini belirten, imajın boyutunu ve ekrandaki pozisyonunu belirten özellikler olacaktır. Ozaman projemize yeni bir Class ekleyelim ve adını da MyGameObject olarak verelim.

Sınıfımızı oluşturduktan sonra namespacelerimizi eklememiz gerekiyor. Aşağıdan da kopyalabilirsiniz.

using System;
using System.Collections.Generic;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;


Hemen ardından az önce belirttiğim özellikleri tutacak değişkenlerimizi tanımlayalım ve nesnemizi oluştururken rahat bir şekilde değer atayabilmek için default constructor 'ımızı 3 parametre alacak şekilde overload edelim.

public Texture2D image;
public Vector2 size;
public Vector2 position;


public MyGameObject(Texture2D image, Vector2 size, Vector2 position)
{
this.image = image;
this.size = size;
this.position = position;
}


Artık uygulamamızda kullanacağımız sınıf hazır. Şimdi Game1.cs dosyamıza geri dönelim ve global olacak şekilde aşağıdaki gibi bir nesne tanımlayalım.

MyGameObject gameObject1;

Sonra bu nesnemizi LoadContent methodu içinde oluşturalım.

gameObject1 = new MyGameObject(Content.Load<Texture2D>("Sprites/sprite1"), new Vector2(48, 48), new Vector2(10, 10));

1. parametre ile hangi imajın yükleneceğini belirtiyoruz. 2. parametre ile nesnemizin boyutlarını ve 3.parametre ile de nesnenin ekrandaki pozisyonunu belirtiyoruz.

Son olarak bu nesneyi Draw methodu içinde ekrana çizdiriyoruz.

spriteBatch.Begin();
spriteBatch.Draw(gameObject1.image, gameObject1.position, Color.White);
spriteBatch.End();


Şimdi uygulamayı derleyip çalıştırırsanız eğer sonucu görebilirsiniz. Kısaca özetlemek gerekirse artık bizim bir çok imajı uygulama anında nesne olarak ele alabileceğimiz, onun temel 3 özelliğine erişebileceğimiz bir sınıfımız var. Bir başka deyişle, artık MyGameObject sınıfı sayesinde daha modüler bir şekilde uygulama geliştirebiliriz.


Ekrandaki Nesneyi Hareket Ettirmek

Şimdi ekrana çizdiğimiz bu nesneye hareket kazandırmamız gerekiyor. Dilerseniz önce işin arka plandaki mantığına kısaca bir bakalım.

Bir nesnenin ekranda hareket etmesi için gereken en basit şey bir tuşa basılmasıdır. Peki biz uygulama içinde herhangi bir zamanda herhangi bir tuşa basıldıgını nasıl anlayacağız ? Bu sorunun en basit cevabı tabiki bu durumu sürekli kontrol etmektir Peki bir işlemin oyun içinde sürekli yapılması gerekiyorsa bu işlemi yapacak kodlar nereye yazılabilir ? Update methodu içine tabiki. Bunun dışında mesela kullanıcı W tuşuna basınca ekrandaki nesnenin yukarı hareket etmesini istiyorsak, bu durumda yapmamız gereken şey nesnenin Y pozisyonunu azaltmaktır. Benzer şekilde sağa doğru gitmesini istiyorsak X değerini yükseltmemiz gerekiyor. Şimdi bu mantığı uyguladığımız somut örneği görmek için aşağıdaki kodları Update methodu içine yazıyoruz. Ardından da kısaca kodlarımızı inceleyeceğiz.

KeyboardState ks = Keyboard.GetState();
if (ks.IsKeyDown(Keys.W))
{
gameObject1.position.Y -= 5;
}
if (ks.IsKeyDown(Keys.S))
{
gameObject1.position.Y += 5;
}
if (ks.IsKeyDown(Keys.A))
{
gameObject1.position.X -= 5;
}
if (ks.IsKeyDown(Keys.D))
{
gameObject1.position.X += 5;
}


Öncelikle KeyboardState türünden bir değişken tanımlıyoruz ve buna Keyboard sınıfının GetState() methodu ile bir değer atıyoruz. KeyboardState o anda klavye ile ilgili bir durumu tutar. Burada yapılan işlem de şudur; GetState() ile o anki durumu ks 'ye atıyoruz. Ardından if kontrolleri ile bu durumu kontrol ediyoruz. ks.IsKeyDown() 'a Keys tipinden bir enumerator yardımıyla parametre veriyoruz ve diyoruz ki, tuşlardan W 'ya basıldı mı, eğer basıldıysa, gameObject1'in yukarı dogru hareket etmesi için, position.Y değerini, sahip oldugu değerden 5 azalt. Bu nesnenin 5 pixel yukarı hareket etmesini sağlar. Diğer if satırlarıda aynı mantıkla çalışıyor tabiki.

Şimdi ikinci bir nesne ekleyip bunların çarpışıp çarpışmadığını kontrol etmemiz gerekiyor.


Çarpışma ( Collision) Kontrolü

Yine aynı mantıkla sprite2 isimli imajımızı da ekrana çizdirelim. Fakat bunu bu sefer ekranın sağ alt köşesine koyalım.

Sınıf düzeyinde;

MyGameObject gameObject2;

LoadContent içinde;

gameObject2 = new MyGameObject(Content.Load<Texture2D>("Sprites/sprite2"), new Vector2(70f, 80f), new Vector2((graphics.PreferredBackBufferWidth - 70f), (graphics.PreferredBackBufferHeight - 80f)));

Burada farklı iki kod göze çarpıyor.

graphics.PrefferedBackBufferHeight
graphics.PrefferedBackBufferWidth


Bu özellikler oyun sahnesinin genişlik ve yükseklik değerlerini tutarlar. Bunları neden kullanıyoruz diye düşünebilirsiniz. Bunun nedeni, ikinci nesnemizin ekranın sağ alt köşesinde göstermektir. Ekranın bu genişlik ve yükseklik değerlerinden, nesenin genişlik(48) ve yükseklik(48) değerlerini çıkartıp, bunu nesnemizin position özelliğine parametre olarak verirseniz istediğimiz şeyi gerçekleştirmiş oluruz. Şimdi ikinci nesnemizi ekrana çizdirmek için Draw methodu içine gerekenleri yazalım.

Draw içinde;

spriteBatch.Begin();
spriteBatch.Draw(gameObject1.image
, gameObject1.position, Color.White);
spriteBatch.Draw(gameObject2.image, gameObject2.position, Color.White);
spriteBatch.End();

Artık uygulamayı derleyip çalıştırırsanız aşağıdaki gibi bir sonuç alırsınız.


Ardından ikinci eklediğimiz nesneye de hareket özelliği kazandıralım. Ozaman bunun için aşağıdaki kodları yukarda yazdığımız update methodu içindeki kodların altına yazmamız yeterlidir. Bu seferki hareket tuşlarımız ok tuşları olacak.

if (ks.IsKeyDown(Keys.Up))
{
gameObject2.position.Y -= 5;
}
if (ks.IsKeyDown(Keys.Down))
{
gameObject2.position.Y += 5;
}
if (ks.IsKeyDown(Keys.Left))
{
gameObject2.position.X -= 5;
}
if (ks.IsKeyDown(Keys.Right))
{
gameObject2.position.X += 5;
}


Buraya kadar yaptıklarımıza bakarsak artık elimizde birbirinden bağımsız şekilde hareket edilebilen 2 tane nesne var. Şimdi bunların çarpışıp çarpışmadığını nasıl programlayabileceğimize bakalım.

İlk olarak çarpışma kontrolünün teorik olarak 2boyutlu bir ekranda nasıl gerçekleştiğini anlayabilmek için aşağıdaki resmi inceleyelim.


Şekilde görüldüğü gibi böyle bir çarpışmanın algoritması şu şekilde özetlenebilir;

beyaz cismin X pozisyonu + genişliğinin toplamı, gri cismin X pozisyonundan büyükse ve
beyaz cismin X pozisyonu, gri cismin X pozisyonu + genişliği, toplamından küçükse ve
beyaz cismin Y pozisyonu + yüksekliği, gri cismin Y pozisyonundan büyükse ve
beyaz cismin Y pozisyonu, gri cismin Y pozisyonu + yüksekliğinden küçükse eğer
bunlar çarpışmıştır.
değilse
çarpışmamıştır.

Şimdi bu durumu somut olarak görebilmek için koda dökmek gerekiyor.

Öncelike MyGameObject sınıfımıza geri dönüyoruz ve CollisionControl adında MyGameObject tipinden bir paremetre alan ve geriye bool değer döndüren bir fonksiyon tanımlıyoruz.

public bool CollisionControl(MyGameObject gameObject)
{
if (this.position.X + this.size.X > gameObject.position.X &&
this.position.X < gameObject.position.X + gameObject.size.X &&
this.position.Y + this.size.Y > gameObject.position.Y &&
this.position.Y < gameObject.position.Y + gameObject.size.Y)
return true;
else
return false;
}


Artık sınıfımız içinde çarpışma kontolünü yapan fonksiyonumuz hazır. Peki bunu oyun içinde nasıl kontrol edeceğiz. Çarpışma kontrölü de nesnelerin hareketleri gibi sürekli kontrol edilmesi gereken bir işlemdir. Dolayısıyla bunu Update methodu içine yazmamız gerekiyor.
Şimdi Game1.cs sınıfımıza geri dönüyoruz ve global düzeyde bool tipinde IsCollide adında bir değişken tanımlıyoruz. Daha sonra Update methodu içinde çarpışma durumunu kontrol ediyoruz ve eğer çarpışma varsa IsCollide değişkenine true değerini atıyoruz.

Sınıf içinde;
bool IsCollide = false;

Update methodu içinde;
if (gameObject1.CollisionControl(gameObject2))
{
IsCollide = true;
}
else
{
IsCollide = false;
}


Bu kodları da uygulamamıza ekledikten sonra artık çarpışma kontrolümüz de yapılmaktadır. Fakat şu anda biz göremiyoruz. Dolayısıyla bu durumu görebilmek için çarpışma gerçekleştiği zaman ekranın ortasında bir tane kırmızı çarpı işareti gösterelim. Buna da sprite3 diyelim ve Sprites klasörümüz altına koyalım.


Son olarak Draw methodu içinde çarpışma gerçekleştiyse kırmızı çarpıyı gösterecek kodu yazıyoruz.

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


spriteBatch.Begin();
if (IsCollide == true)
{
spriteBatch.Draw(Content.Load<Texture2D>("Sprites/sprite3"),new Vector2(((graphics.PreferredBackBufferWidth / 2) - 50),((graphics.PreferredBackBufferHeight / 2) - 50)), Color.White);
}
spriteBatch.Draw(gameObject1.image, gameObject1.position, Color.White);
spriteBatch.Draw(gameObject2.image, gameObject2.position, Color.White);
spriteBatch.End();


base.Draw(gameTime);
}


Sonuç olarak uygulamayı çalıştırıp nesneleri çarpıştırmayı denerseniz eğer çarpışma anında ekranın ortasında çarpı işaretini görebilirsiniz. Böylece çarpışma olup olmadıgını net bir şekilde görmüş oluyoruz.

Örnek Uygulama

Mehmet Aydın Ünlü

XNA Bir Oyunun Yaşam Döngüsü

Merhaba arkadaşlar,

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ı.
  • Tüm bu giriş ve çıkış işlemlerinin sonlandırılması
  • Kaynakların serbest bırakılması.
Dikkat ettiyseniz eğer bir önceki yazımızda Game1 sınıfı ile gelen yapıyı incelerken, tüm bu oyun döngüsündeki aşamalara karşılık gelen kod blokları olduğunu görmüş olmalısınız. Mesela hazırlık aşaması için bir Initialize() methodunun olması gibi. Diğer bir örnek ise oyun döngüsünü içeren Update() metodudur. Dolayısıyla şunu diyebiliriz ki; XNA bize kodlama yapacağımız yerleri ana hatlarıyla belirtiyor. Ayrıca nerede ne yazacağımız konusunda da bize güzel bir ipucu veriyor. Bu yapının dışına çıkıp kendi mimarinizi geliştirmekse, çok ta zor olmamakla birlikte, sizin nesne yönelimli programlama tecrübenize kalmış bir durumdur tabiki.

Ş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.
  1. Game Initialization (Hazırlık)
  2. Game Loop (Döngü)
  3. Finalization (Bitiş)
Şimdi bu adımlara biraz daha yakından bakalım


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ü

XNA Dünyasına Yolculuk

Merhaba arkadaşlar,

Bir önceki yazımda XNA ile oyun geliştirmeye başlamadan önce bilgisayarımıza kurmamız gereken araçlara değinmiştik. Bunların kurulumunu yaptıysak eğer artık XNA dünyasına adım atma vaktimiz gelmiş demektir...


İlk Adım

Öncelikle Microsoft Visual C# 2008 Express Edition 'ı açıyoruz. File menüsünden New Project 'e tıklıyoruz. Açılan pencerede aşağıdaki resimde gördüğünüz gibi Windows Game (3.0) proje şablonunu seçiyoruz. Ardından da projemize bir isim verip OK tuşuna basarak ilk uygulamamızı oluşturuyoruz.



Uygulamamızı oluşturduktan sonra proje şablonunun bize sunduğu yapıyı tanıyabilmek için Solution Explorer penceresinden proje ile gelen standart yapılara bir bakalım.


Uygulama ile gelen standart yapı içindeki en farklı öğe Content alt projesidir. Uygulamanın yaratılmasıyla birlikte Content adında ufak bir proje de uygulamaya dahil edilmektedir. Content projesinin amacı için, oyunumuzun içinde yer alacak olan bir çok farklı öğeyi merkezi bir yerden yönetbilmektir diyebiliriz. (grafik, ses, vs.).

Content projesinden sonra References düğümlerine bakmakta fayda var. Burada görebileceğiniz gibi Microsoft.Xna.Framework ön ekiyle başlayan bir çok farklı Assembly uygulamanın standart yapısı içinde gelmektedir. İşte bu assembly 'ler XNA Game Studio ile sisteme kurulan dosyalardır.

Bunların dışında uygulamayla birlikte Game1.cs ve Program.cs olmak üzere 2 tane sınıf gelmektedir. Program sınıfının işlevi diğer Windows veya Console uygulamalarındaki Program sınıfından farklı değildir. Dolayısıyla program sınıfı için uygulamanın başlangıç noktasıdır (Entry Point) diyebiliriz. Game1 sınıfını ise birazdan çok daha detaylı bir şekilde inceleyeceğiz. Fakat önce XNA ile gelen ve temel olarak bilmeniz gereken bazı standart namespace 'lere değinmek istiyorum.


Derinlere...

using Microsoft.Xna.Framework; MSDN Link
Bir oyunda gerekebilecek en temel ve genel yapıları sunar (Oyun döngüsü, zamanlamalar, pozisyonlar, boyutlar, vs.)

using Microsoft.Xna.Framework.Audio; MSDN Link
Auido kelimesi ile herşey anlaşılıyor gibi ama daha somut anlatmak gerekirse; oyunlarda çeşitli müzikler veya ses efektleri kullanmamız gerekir. XNA 'de geliştireceğimiz oyunlara, ses dosyalarını, harici bir program olan Microsoft Cross-Platform Audio Creation Tool (XACT) ile ekliyoruz (Bu programa Başlat>Programlar\Microsoft XNA Game Studio 3.0\Tools altından erişebilirsiniz). Biz de XACT 'nin oluşturuğu veriler üzerinden Audio namespace 'ini kullanarak ses dosyalarını yönetebiliyoruz.

using Microsoft.Xna.Framework.Content; MSDN Link
Content Pipeline 'da bulunan özellikleri yönetmeyi sağlar. İçerik yönetimi ve kaynak yönetimi gibi konularla ilgili sınıflar burada bulunur. (Content Pipeline nedir sorusunun cevabını bu yazının ilerleyen bölümlerinde göreceğiz)

using Microsoft.Xna.Framework.GamerServices; MSDN Link
Adından da anlaşılabileceği üzere bu namespace içinde oyuncular ile ilgili bir çok çeşitli servis sınıfı yer alır. Bu servisler direk olarak kullanıcı ile iletişim içinde bulunurlar.

using Microsoft.Xna.Framework.Graphics; MSDN Link
Grafiksel işlemleri gerçekleştirip yönetebileceğimiz sınıfları bünyesinde bulundurur. Ekrana bir resim veya 3D bir obje koymaktan tutunda, ekran kartının özelliklerine erişmeye kadar bir çok yeteneği bizlere sunar.

using Microsoft.Xna.Framework.Input; MSDN Link
Klavye, mouse veya XBOX için gamepad gibi giriş birimlerini yönetebileceğimiz sınıfların toplandıgı yerdir. Klavyede herhangi bir anda hangi tuşa basılmış veya farenin ekrandaki pozisyonu gibi bir çok durum üzerinde kontrole sahip oluyoruz.

using Microsoft.Xna.Framework.Media; MSDN Link
Çeşitli MediaList'ler yani; playlist, resim albümü gibi şeyler oluşturabileceğimiz koleksiyonlara sahiptir.

using Microsoft.Xna.Framework.Net; MSDN Link
Oyunlarımıza network altyapısını sağlayacak olan sınıfları içerir.

using Microsoft.Xna.Framework.Storage; MSDN Link
Dosyaları okumak veya dosyalara yazma işlemini yapabilmek için gerekli olan sınıflara sahiptir.

Bu bahsettiğimiz isim alanları xna ile gelen temel modüllerdir. Bunlardan kısaca bahsettiğimize göre şimdi Game1.cs sınıfının yapısını detaylı bir şekilde inceleyebiliriz.


Game1.cs

public class Game1 : Microsoft.Xna.Framework.Game


Game1.cs sınıfımız görüldüğü gibi XNA Framework içinde bulunan Game adındaki sınıftan türemektedir.

GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;


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


Her sınıfta olduğu gibi Game1 sınıfımızın da bir yapıcı metodu (Default Constructor) bulunmaktadır. Yapıcı metodların genel kullanım amacını hatırlamak gerekirse eğer; program genelinde kullandığımız değişkenlere, başlangıçta sahip olmasını istediğimiz değerlerin atandığı yerdir diyebiliriz. Nitekim burada da ekran kartına erişebileceğimiz sınıf olan GraphicsDeviceManager 'dan bir nesne yaratılmıştır. Ardından da oyun içinde kullanacağımız içeriklerin bulunduğu kaynak gösterilmiştir. Şimdilik GraphicsDeviceManager ve SpriteBatch sınıflarının ne işe yaradığını çok fazla düşünmeyelim.


protected override void Initialize()
{
base.Initialize();
}


Initialize() metodu ise oyun içinde, oyun ile ilgili başlangıç değerlerinin belirlendiği bölüm olarak tanımlanabilir. Constructor 'ı oyunu programlamak için gereken teknik hazırlık aşaması olarak düşünürsek eğer Initialize aşaması da oyuna başlangıc için gereken hazırlık aşaması olarak tanımlanabilir.


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


LoadContent() methodunu, masa üstü uygulamalarındaki Form_Load methoduna benzetebilirsiniz. Açıklamak gerekirse, oyun ilk çalıştığı anda çalışan metottur. Oyun içinde kullanılacak nesnelerin yüklenmesi gibi amaçlar için kullanılabilir. Nitekim burada da aynen bu şekilde SpriteBatch tipinden bir nesne yaratılmıştır.


protected override void UnloadContent()
{


}

UnloadContent(), uygulama kapanırken çalışan metodumuzdur. Örnek vermek gerekirse; oyuncu oyunu kaydetmeden çıkmaya çalışırsa eğer ona oyunu kaydetmek isteyip istemediğini sorabileceğimiz bir çıkış işlemi süreci yazabiliriz.


protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();


base.Update(gameTime);
}



Update(), methodu oyunun çalışmaya başladığı andan itibaren çalışan bir metottur. Bu yüzden bu metod içinde oyun genelindeki bir çok kontrol ve yönetim işlemini kontrol edebiliriz. Örnek vermek gerekirse; hareket eden iki cismin çarpışıp çarpışmadığını bu method içinde rahatlıkla kontrol edebiliriz. Burada ise bir IF kontrolü ile gamepad 'de geri tuşuna basılıp basılmadığı kontrol ediliyor ve eğer bu tuşa basıldıysa oyun kapanıyor.


protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
base.Draw(gameTime);
}


Bir oyun nesnesini ekranda gösterebilmek için teorik olarak bunun ekrana çizilmesi gerekir. Draw() metodu da bu çizim işlemlerini gerçekleştirmekten sorumludur. Ayrıca Update() metodu gibi sürekli çalışan bir metottur.


Buraya kadar Game1.cs sınıfıyla birlikte gelen standart yapıyı kısaca görmüş olduk. Umarım artık kendinizi xna dünyasına biraz daha yakın hissetmeye başlamışsınızdır.

Mehmet Aydın Ünlü

XNA İçin Gerekenler

XNA ile oyun geliştirmeye başlamadan önce uygulama geliştirme ortamını hazırlamak gerekiyor. Bu amaçla yapmamız gereken 3 temel adım vardır. Bunlar;
  1. Uygulama yazıp derleyebilmek için bize kolaylık sağlayacak IDE' miz olan Visual C# 2008 Express Edition 'ın kurulumu.

  2. XNA Framework 'ünü kullanabilmek için XNA Game Studio 'nun kurulumu.

  3. DirectX desteğinden yararlanabilmek için DirectX Runtime dosyalarını kurulumu.

1- Geliştirme Ortamı

Geliştirme ortamı olarak Microsoft' un ücretsiz olarak kullanıma sunduğu Visual C# Express Edition 'ı kullanabilirsiniz. Diğer yandan hali hazırda kullandığınız herhangi bir Visual Studio 2008 versiyonu varsa eğer onu da kullanabilirsiniz.

Download Link : http://www.microsoft.com/express/Downloads/#2008-Visual-CS

2- XNA Game Studio

XNA Game Studio için şu an ki kararlı son versiyonu olan 3.1 'i kurmanızı öneririm.

Download Link (v 3.1) : http://www.microsoft.com/downloads/details.aspx?FamilyID=80782277-d584-42d2-8024-893fcd9d3e82&displaylang=en

Bunun yanında Microsoft XNA 'i geliştirmeye devam ettiği için şu anda CTP halinde olan 4.0 sürümünü de kurmak ve incelemek isteyebilirsiniz. Bunu için aşağıdaki linki kullanabilirsiniz.

Download Link (v 4.0 CTP) : http://www.microsoft.com/downloads/details.aspx?FamilyId=2338b5d1-79d8-46af-b828-380b0f854203&displaylang=en

3. DirectX Runtime

Son olarak DirectX Runtime dosyalarının kurulumunu yapabiliriz. Böylece xna ile oyun geliştirmeye başlamadan önce yapmamız gereken hazırlıkları tamamlamış oluruz.

Download Link : http://www.microsoft.com/downloads/details.aspx?familyid=2da43d38-db71-4c1b-bc6a-9b6652cd92a3&displaylang=en

Bunların yanında ilerde çıkabilecek olan yeniliklerle bağlantılı olarak kurmanız gerekebilecek uygulamları XNA Creators Club sitesinden takip edebilirsiniz.

Mehmet Aydın Ünlü

XNA Nedir ?

Merhaba arkadaşlar,

Bu yazımda sizlere XNA 'in ne olduğundan kısaca bahsedip ardından xna dünyasına adım atmadan önce bu dünya içinde yapabileceklerinizden bahsetmek istiyorum.

XNA Nedir ?

XNA; Microsoft' un oyun programlama dünyasına .net platformu ile destek vererek geliştirdiği ücretsiz bir oyun geliştirme platformudur.

XNA ile Yapabilecekleriniz

XNA ile yapabileceklerinize gelirsek eğer ilk söylenmesi gereken şey DirectX desteğinin olduğudur.
Video oyun yapımı ve geliştirilmesinde kullanılan DirectX, Microsoft'un video oyunları başta olmak üzere çoklu ortam yazılımlarını rahat, hızlı ve uyumlu şekilde hazırlayabilmek için yarattığı bir API Yazılım Programlama Arayüzü - Application Programming Interfacedir. İçerdiği bileşenlerden bazıları şu şekilde özetlenebilir:

* Direct3D, hem iki hem üç boyutlu grafikleri ekrana dökmeye yarar. Piyasadaki çoğu ekran kartının en modern donanım hızlandırma özelliklerini destekler. En büyük rakibi OpenGL'dir

* DirectSound hem iki hem üç boyutlu ses için kullanılır. Windows altında çalışabilen her ses kartı en azından yazılım ile DirectSound ve DirectSound 3D desteğine sahiptir.

* DirectInput, klavye, fare ve oyun çubuğu gibi bileşenlerin giriş ve çıkışlarını basit bir şekilde yönetebilmek için olan arabirimdir.

* DirectPlay, TCP/IP, modem ve Bluetooth gibi birçok protokol üzerinden bağlantı ve mesajlaşma bileşenlerini içerir.

Kaynak : http://tr.wikipedia.org/wiki/Directx

XNA ile doğrudan gelen DirectX desteği sayesinde 2D ve 3D oyunları çok rahat bir şekilde geliştirebilirsiniz. Input cihazlarını (klavye, mouse, gamepad vb..) çok kolay bir şekilde yönetebilirsiniz. Bunların dışında güzel olan bir şey daha var ki XNA ile sadece PC değil XBOX ve ZUNE platformları içinde oyunlar veya çeşitli yazılımlar geliştirebilirsiniz.

XNA 'in sahip olduğu yazılım geliştirme kolaylıklarının yanında ayrıca xna platformu için geliştirilmiş fizik motoru gibi bir çok ücretsiz/ücretli yazılımda hali hazırda mevcuttur.


XNA Racing Game



XNA için Kaynak Linkler

Resmi geliştirici platformu : http://creators.xna.com/en-US/

XNA/DirectX MVP Blogları : https://mvp.support.microsoft.com/communities/mvp.aspx?product=1&competency=XNA%2fDirectX

XNA MSDN Sayfası : http://msdn.microsoft.com/en-us/aa937791.aspx

XNA Takımı Bloğu : http://blogs.msdn.com/xna/

Mehmet Aydın Ünlü

Bir Oyunda Olması Gereken Temel Yapılar

Merhaba arkadaşlar,

Bir önceki giriş yazımda oyun programlamaya başlamadan önce yapılması gereken analiz adımlarından bahsetmiştim. Ayrıca bir oyun geliştirme ekibinde bulunabilecek temel karakterlerden de bahsetmiştim. Bu yazımda ise bir oyunda olması gereken temel yapıları inceleyerek devam edeceğiz. Aslında bu öğeler bir çoğumuzun bildiği sıradan ve basit şeyler. Fakat gel gelelim oyun kodlamanın büyüsüne kapılıp bu tarz şeylerin varlığını bile unutabiliyoruz. Bu yapıların iyi bilinmesi oyun geliştirme sürecinin daha en başında neyin, nerede ve nasıl yapılması gerektiğini belirlememizi sağladığı için çok önemlidir. Şimdi bu kavramlara kısaca bir bakalım...


Amaç


Öncelikle her oyunun mutlaka bir amacı olmalıdır. Mesela Super Mario oyununu örnek vermek gerekirse, onlarca bölümü geçmek için uğraşıyoruz. Peki amacımız ne ? Prensesi kurtarmak. Dolayısıyla oyuncuyu oyuna bağlayan bir amaç olmalıdır.

Sonlandırıcı Etkenler ve Kaydetme

Oyunun amacının yanında bu amaca ulaşmak o kadar da kolay olmamalı. Mutlaka oyuncuyu zorlayan durumlar olmalıdır. Bu aynı zamanda ulaşılması gereken amacı daha da değerli bir hale getirir. Hatta gerekirse karakterinizin belli bir hakkı olmalı ve bu hak tükendikten sonra oyun orada sonlanmalıdır. Daha sonra oyun belli bir yerden tekrar başlamalıdır. İşte bu noktalara SavePoint (Kayıt Noktası) diyoruz. Bu noktalarda oyun kaydedilir ve bir sonraki kayıt noktasına kadar geçen sürede eğer oyun sonlanırsa, oyun ulaşılan en son kayıt noktasından tekrar başlar. Bu mantık özellikle platform tabanlı oyunlarda sıkça görülür. Mesela aynı mantık Mario 'da vardır. Haritada sürekli ilerliyorsunuz ama öldüğünüz zaman, öldüğünüz yere göre, oyuna tekrar belli bir noktadan başlıyorsunuz. Ya en baştan ya da haritanın ortasındaki bir yerden...

Bir de bir çok oyunda gördüğümüz, istediğimiz anda oyunu kaydetme özelliği vardır. Oyuncu oyunun herhangi bir anında oyunu kaydedip, daha sonra oyuna oradan devam edebilir. Bu iki farklı teknikten hangisini seçeceğimizi belirleyen unsur ise genelde oyunun türüdür. Eğer SavePoint mantığı kullanılacaksa iki savepoint arası çok uzak olmamalıdır. Aksi halde karakter ölürse veya görev başarısız sonuçlanırsa, oyuncu aynı şeyleri çok fazla tekrar etmekten sıkılacaktır. Bu da kısa bir süre sonra oyuncunun bir daha oyununuzu oynamaması anlamına gelir.

Gerçekçi Bir Hikaye

Oyunun hedefine giden yolda, oyunun oyuncuyu taşıyabilmesi için gereken en önemli öğelerden biri de gerçekçi bir hikayedir. Aslında oyunun tarzı ve sizin verdiğiniz farklı bir karar ile siz oyunu çok gerçek dışı yapabilirsiniz. Fakat oyun gerçek dışı dünyasında, kendi içinde çelişmeyecek bir realiteye sahip olmalıdır. Oyundaki bölümler de bu hikayenin gidişatına göre şekillenmelidir. Karşınıza çıkacak her şey hikayenin gidişatına göre doğru zamanda çıkmalıdır. Aksi taktirde oyuncu her an şaşırabilir. Bu durum da insanların oyununuzdan soğuması için yeterli bir sebeptir.

Oynanabilirlik

Oynanabilirlik bir çok oyun dergisi tarafından oyuna verilecek atı puanlara etki edecek kadar önemli bir kriterdir. Oynanabilirlik dediğimiz kavram, oyunu daha basit nasıl oynatabiliriz sorusunun cevabıdır. Bir başka deyişle geliştirdiğiniz oyun mümkün olduğu kadar basit bir oynanışa sahip olmalıdır. Buna klavye kısayollarından tutunda, ekrandaki nesnelerin kullanılabilirliğine kadar bir çok etken etki edebilir. Oynanabilirlik neden bu kadar önemli peki. Bunu basit bir örnek ile kısaca özetleyelim. Bir oyun geliştirdinizi düşünelim. Oyun çıktığı zamanın en iyi 3D grafiklerine sahip olsun. Ses efektleri çok iyi sanatçılar tarafından yapılmış olsun. Hatta bu oyunu orta seviye donanıma sahip bir bilgisayar bile rahatlıkla çalıştırabilir olsun. Dolayısıyla daha oyun çıkar çıkmaz bir sürü potansiyel müşteriniz var demektir. Fakat oyunda ufak bir sorun var. 3D' nin ilk çıktığı dönemdeki oyunları hatırlayın mesela. Siz tam bir hamle yapacakken kamera öyle bir şekilde döner ki istediğiniz hamleyi bir türlü yapamazsınız. Veya oyuna standart bir klavye kontrol düzeneği atamışsınızdır fakat bunun ayarlar panelinden kişiselleştirilebilir olmasını sağlamamışsınızdır... gibi bu örnekler çoğaltılabilir. Bu tarz hatalar veya eksikler olacaktır belki ama oyunun geneline yayılmış bir durum söz konusu ise emin olun oyuncunun ilk yapacağı iş oyunu bilgisayardan kaldırmak olacaktır. Bu şu demektir; insanların oynaması için bir oyun geliştiriyorsunuz fakat bunu onlara oynatamıyorsunuz. Bu nedenle oynanabilirliği elinizden geldiği kadar basit ve kullanışlı tutmaya çalışmalısınız.

Tekrar Oynanabilirlik

Bunu açıklamak için size şöyle bir soru sormak istiyorum. Öncelikle bir oyun geliştirdiğinizi ve bu oyunu da bir arkadaşınızın oynadığını düşünün. Arkadaşınız bu oyunu oyanamaya başlıyor ve 1 hafta gibi bir sürede bitiriyor diyelim. Şimdi arkadaşınıza öyle bir neden söyleyin ki bu oyunu oturup 1 hafta daha oynayıp bir kez daha bitirmek istesin. İşte bu sorunun cevabı ne kadar geniş olursa oyununuz da o kadar tekrar oynanabilecek bir potansiyele sahip demektir. Burada oyuna yön verecek karakter sayısını fazla tutup, her birine farklı özellikler vermek ilk akla gelen yöntemlerden biridir. Veya Red Alert gibi bir strtaji oyununu ele alalım. Kırmızı güçler ile mavi güçlerinin sahip oldukları üniteler tamamen birbirlerinden farklıdır. Bu şu demek oluyor; oyunu oynayacak kişi bu oyunu en az 2 farklı şekilde bitirebilir. Burada tabi hikayede ön plana çıkan bir başka detaydır. Bu sefer her farklı güce, karaktere ve bu gibi öğelere özel hikaye akışı ve senaryolar olmalıdır. Bu geniş ve detaylı bir şekilde kurgulanması gereken bir konudur ama emin olun oyununuzun daha başarılı olmasını garanti eder.

Denge

Oyunun mutlaka sahip olması gereken bir dengesi olmalıdır. Şöyle özetlemek gerekirse, oyundaki karakterimiz geliştikçe, karşımıza çıkan düşmanların da güçlenmesi gerekir. Aksi halde oyunun seviyesinde gözle görülür bir şekilde düşüş görülür. Bu da her şeyin kolaylaşması demektir. Ya da oyunun daha başında çok zor bölümlere sahip olması oyun dengelerini altüst edebilir. Dolayısıyla da bu dengenin mantıklı bir şekilde sağlanıp korunması gerekir.

Ödül

En önemli öğelerden biri de ödüldür. Ödül oyunun türüne göre değişkenlik gösterebilir. Ödülleri fazladan can, enerji, para veya diğer kaynaklar gibi düşünebilirsiniz. Mesela bir bölüm sonu canavarını öldürdükten sonra mutlaka bir ödül verilmesi gerekir. Bunun dışında ödül illa ki bir başarının sonucunda gelmeyebilir. Mesela oyun dünyasında gizli yerlere çeşitli ödüller koyabilirsiniz. Oyuncunun böyle bir durumdan haberdar olması demek, tüm haritayı didik didik etmesi demektir. Sonuçta bu durum da oyunun oynanabilirlik süresini uzatır. Diğer bir deyişle oyununuzun ömrü uzar. Ayrıca burada verilen ödüllerde yine dengeli davranılması gerekir. Bir bölüm sonu canavarını öldürünce verilen ödül ile rastgele bir kutudan çıkan ödül aynı olmamalıdır.

Çevre

Günümüzde oyunlar sadece bir eğlence unsuru olarak ele alınmıyor. Bunun yanında artık oyun dünyası sosyal bir platform haline gelmiştir. Günümüzde oyunların fanlarının toplandığı, görüşlerini paylaştıgı hatta oyun içi eşyaların satıldığı forumlar ve internet siteleri mevcuttur. Dolayısıyla bu gibi altyapılara da destek vermeniz gerektiğini unutmamak gerekir. Bunların yanında bir de belli dönemlerde güncellemeler veya genişleme paketleri çıkarmanız yine oyunun ömrünü uzatan bir başka yöntemdir.

Sonuç olarak bir oyunda olması gereken en temel yapılar bu şekilde özetlenebilir. Bunlar oyunun türüne ve sizin hayalinizdeki oyun dünyasına göre çeşitli farklılıklar gösterebilir tabiki.

Kaynak : Beginning XNA 2.0 Game Programming

Mehmet Aydın Ünlü

Oyun Programcılığına Giriş

Merhaba arkadaşlar,

Bu yazıda sizlere, oyun programlamaya başlamadan önce bilmeniz gereken bazı temel unsurlardan bahsedeceğim. Bu unsurları 3 ana başlık altında ele alacağız.

  1. Geliştireceğiniz oyunları kime yönelik geliştirmeniz gerektiğini belirlemek için oyuncu profillerine bakacağız,
  2. Geliştireceğiniz oyunların nasıl olması gerektiğini belirlemek için oyun türlerini kısaca örnekleyeceğiz,
  3. İlerde bir oyun geliştirme ekibi içinde yer alırsanız ekip arkadaşlarınızın kimlerden oluşacağına bakacağız.
Bu 3 başlığı bir oyun geliştirme sürecine başlamadan önce yapılması gereken başlangıç analizi olarak görebilirsiniz.
Analiz bir konuyu (maddi veya düşünsel) temel parçalarına ayırarak, daha sonra parçaları ve aralarındaki ilişkileri tanımlayarak sonuca gitme yoludur.

Kaynak : http://tr.wikipedia.org/wiki/Analiz

Oyun geliştirme işi bir çok farklı adımdan oluşuyor olsada özünde bir yazılım geliştirme sürecidir. Her yazılım geliştirme çalışmasına da başlamadan önce yapılması gereken bazı işler vardır. Bunların en önemlisi de iyi bir analiz çalışmasıdır. Analiz çalışmaları uygulama geliştirme aşaması için hayati derecede önem taşır. Bu aşama 5-6 aylık geliştirme süreci olan herhangi bir proje için çok büyük bir olumsuz etki yaratmayabilir belki fakat oyun geliştirme süreci gibi uzun soluklu projelerde, eksik yapılmış bir analiz çok daha büyük negatif etkiler yaratabilir. Bu bağlamda yukarda bahsettiğimiz unsurlara daha yakından bakalım...
Farklı yazılım geliştirme süreçlerinde ( extreme programming, waterfall, scrum, vs.) farklı analiz süreçleri vardır. Biz bu yazıda analiz sürecine sadece genel bir bakış yapıyor olacağız.

Hedef Kitle Seçimi


Doğru hedef kitleyi belirlemek oyunun geleceği açısından son derece hayati bir önem taşır. Bunun nedeni; geliştireceğiniz uygulamanın bir işin olmasına, bir ticari amacın gerçekleşmesine veya bu tarz bir şeye hizmet etmeyecek olmasıdır (crm, erp, muhasebe programları gibi). Yani ortada sizin anlaştıgınız, henüz sizin projenizi bekleyen bir müşteri yok. Bir başka deyişle siz müşterinizin herhangi bir ticari ihtiyacını kapatmak için yazılım geliştirmeyeceksiniz. Evet yine bir ihtiyacı karşılayacaksınız ama bu ihtiyaç tamamen insan doğasından kaynaklanan bir ihtiyaç olacak...
Dijital oyun oynamak aynı zamanda bir takım görevleri yerine getirmek demekti. Haz, bu görevlerin yerine getirilmesi sırasında gerçekleşen olaylardan ve iletişimden kaynaklanmaktaydı. Bu hazzı incelemek bizi homo ludens kavramına götürdü. Bu arada Karl Marx' ın Kapital' de Nicholas Barbon' dan (1969) aktardığı; "Meta, her şeyden önce, bizim dışımızda bir nesnedir ve taşıdığı özellikleriyle, şu ya da bu türden insan gereksinimlerini gideren birşeydir. Bu gereksinimlerin niteliği, örneğin ister mideden, ister hayalden çıkmış olsun birşey değiştirmez (istek gereksinim demektir; o ruhun iştahıdır ve tıpkı vücüdun açlığı gibi doğaldır. ... Şeylerin çok büyük bir kısmı, ruhun gereksinimlerini karşıladığı için değerlidir...(2004: 47)"

Kaynak : Kültür Endüstrisi Ürünü Olarak Dijital Oyun

Eskiden oyunlar daha çok küçüklere hitap etsede günümüzde yaş farketmeksinizin bir çok insan bilgisayar oyunu oynuyor. Yinede ortada insanların yaş farklarından doğan farklı seçimleri vardır. Mesela Super Mario oyununu ele alalım. Bu oyunu her ne kadar bir çoğumuz hala eğlenerek oynasada oyunun asıl hedef kitlesi çocuklardır desek yanlış olmaz sanırım. Buradan her oyunun belli bir yaşa göre seçilmiş hedef kitlesi olmalıdır gibi bir çıkarım yapmakta çok doğru olmaz tabiki. Yinede hedef kitle olarak geniş bir yaş aralığı seçecekseniz ona göre bir analiz yapıp çalışmanıza da bu yönde yol vermeniz gerektiğini de unutmamanız gerekiyor. Şimdi geliştireceğiniz oyunları oynayacak oyuncu profillerine kısaca bir bakalım.

Araştırmalara göre bilgisayar oyuncuları 6 profile ayrılıyor.
  1. Heavy Gamers (Ağır oyuncular)
  2. Console Gamers (Konsol oyuncuları, PlayStation, XBOX, WII)
  3. Mass Market Gamers (Sadece çok etkileyici oyunları tercih edenler)
  4. Prefer Portable Gamers (Taşınabilir cihazlarda oyun oynamayı tercih edenler)
  5. Secondary Gamers (İkincil oyuncular, oyun almazlar sadece çevresindekilerden buldukları herhangi bir oyunu alıp türüne bakmaksızın oynarlar)
  6. Infrequent Gamers (Nadir oyuncular, ara sıra oyun oynayanlar)

Bu 6 farklı oyuncu profili ise, 2 tür altında toplanıyor.

1. Infrequent Gamers :

Bu tarz oyuncular gelişigüzel oyun oynarlar. Diğer bir deyişle canları istedikleri zaman oyun oynarlar. Bu nedenle oyunlardan mümkün olan olan maksimum eğlenceyi, mümkün olan minimum zamanda elde etmek isterler. Dolayısıyla bu tarz oyuncular için oyunun çok basit olması gerekir. Ayrıca oyunun derin bir hikayesi de olmaması gerekir. Hatta oyunun bir hikayesi olmasa bile olur. Oyun bölümlerinin de kısa olması gerekir. Yani bir bölüm saatlerce sürmemelidir. Bunun yanında oyuncuya başarma hissinin yansıtılması çok önemlidir. Çünkü dediğimiz gibi oyuncu en kısa zamanda en fazla eğlenceyi elde etmek ister. Başarma hissine etki eden en basit unsur ise; oyuncunun, oyun oynamak ile geçirdiği sürenin dışında, bu sürenin çeşitli ödüller ile desteklenmesidir. Çok basit bir örnek vermek gerekirse; Super Mario oyununda 100 altın topladıktan sonra ekstradan 1 can verilmesi gibi.

Bunların dışında oyunda üst düzey 3D efektlerin veya çok etkileyici ses efektlerinin olması da çok önemli değildir. Şunu asla unutmamak gerekir, geliştirdiğiniz şey sadece bir bilgisayar oyunu ve sadece oyuncuyu eğlendirmeyi hedefliyor. Böyle bir hedefe saf 2D görüntüler ile de ulaşabilmeniz mümkündür. Örnek vermek gerekirse; Diablo, Super Mario veya World Of Goo gibi oyunlar 2D grafikler ile çok büyük başarılar elde etmiştir.

2. Heavy Gamers

Büyük prodüksiyona sahip oyunların hedef kitlesidir diyebiliriz. Bu tarz oyunculara "hardcore gamers" derler. Oyunları çok ciddi bir şekilde ele alırlar. Hatta bunu yaşam tarzı olarak görenler bile vardır. (Warcraft çıkmadan bir gün önce mağazaların önünde sabahlayanları görmüştük haberlerde) Bu tarz oyuncular için oyunun son derece gerçekçi olması gerekir. Bunun dışında bu oyuncuların oyundan etkilenmesi ve oyunu benimsemesi için oyunun bir hikayesi olması gerekir. Hikayenin gerçekçi olması çok önemli değildir. Fakat hikaye kendi içinde mutlaka gerçekçi olmalıdır. Mesela Yüzüklerin Efendisi son derece gerçek dışıdır fakat kendi evreni içinde her karakterin kendine özgü bir davranışı ve dünyanın da kendine özgü bir yapısı vardır. Ayrıca dikkatinizi bir noktaya çekmekte fayda var, eskiden filmlerin oyunları yapılırdı ama bu durum günümüzde tersine dönmüştür ve artık oyunlarında filmleri yapılmaktadır. Bu da oyun sektörünün ne kadar geliştiğinin en güzel örneklerinden biridir. Tomb Raider, Max Payne, Resident Evil ilk aklıma gelen filmleri yapılan oyunlardır. Bu ufak nottan sonra bu tarz oyuncuların istekleri asla kutu kutu düşmanlar, düz mavi zemin üzerinde yuvarlak yuvarlak bulutlardan oluşan 2D bir dünya değildir. Tam aksine bekledikleri şey son derece derin detaylarla donatılmş ve o dünyanın içinde olduklarını onlara hissettirebilecek son derece gerçekçi 3D grafiklere sahip bir oyundur. Ayrıca bu görsellik yine çok gerçekçi ses efektleri ve o anki oyun içinde gerçekleşen duruma özel müziklere sahip olmalıdır. Oyunun başında çalan eğlenceli müziğin karakteriniz öldükten sonra da çalması oyunu kırmak için yeterli bir sebeptir. Bu tarz oyuncuların bir beklentisi de uzun oyun zamanıdır. Bir bölümü geçmek için günlerce uğraşabilirler. Bundan sıkıldıklarını sanmayın aksine zevk alırlar. Ama bu çabalarını mutlaka bir şekilde ödüllendirmeniz gerektiğinide asla unutmayın. Bu ödülleri de adil ve mantıklı dağıtmanız gerekiyor tabiki. Mesela karakteriniz sıradan bir düşmanı öldürünce 100 puan kazanıyorsa, bir bölüm sonu canavarını öldürünce çok daha büyük puan veya ödüller kazanmalıdır.


Oyun Türü Seçimi

Yukarıda "oyunun tek bir hedefi vardır ve oda eğlendirmektir" demiştik. Şimdi de "her insan farklı şekilde eğlenir" diyeceğimiz noktaya geliyoruz. Oyun geliştirmeye başlamadan önce vermeniz gereken bir karar da oyunun türüdür. Bazı oyun türlerine örnek vermek gerekirse;

  • Strategy : Red Alert, WarCraft, StarCraft
  • Shooter (kendi içinde 4 'e ayrılır)
    • Shoot'em up : DuckHunt, Virtu Cop
    • LightGun Shoter : Shot'em up' ın tabanca ile oynananı
    • Firs Person Shooter(FPS) : DOOM, Quake, Half-Life, CounterStrike
    • Third Person Shooter : MaxPayne, GTA 3 ve sonrası
  • Tactical Shooter : TomClany's RainbowSix, GhostRecon, OperationFlashpoint
  • Role-Playing Game (RPG) : Diablo, NeverWinterNights
  • Adventure : Alone In The Dark, Monkey Island
  • Action : Unreal Tournament
  • Sports : FIFA, NBA serileri
  • Racing : NeedForSpeed Serisi, GranTourismo Serisi
  • Fighting : StreetFighter

Oyun Geliştirme Ekibini Tanımak


Geliştirdiğimiz uygulama bir oyun olduğu için takım içinde oyunun türüne en uygun, kendi alanında uzmanlaşmış bir çok farklı karakter olmalıdır. Şimdi gelin bu karakterleri kısaca tanıyalım.

Project Manager (Proje Yöneticisi)

Her profosyonel yazılım geliştirme sürecinde oldugu gibi oyun geliştirme süreci içinde takımı motive edecek, koordinasyonu sağlayacak, kaynak yönetimini yapacak kısaca takımı yönetecek bir proje yöneticisi şarttır.

Script Writers (Senarist)

Eğer oyununuz bir hikayeye sahipse doğal olarak bir senaryosu da olmalıdır. Senaryo içinde karakterler arasında çeşitli diyaloglar geçer. Kimi zaman bu diyaloglara oyuncu da müdahale edebilir ve bunun sonucunda oyun farklı bir şekilde yol alabilir. İşte senaristler oyunun hikayesini belirleyen ve hikayenin ön plana çıktığı, özellikle adventure tarzı oyunlardaki en önemli karakterlerden biridir. Bir futbol oyununda senariste gerek yoktur belki ama bir RPG'de mutlaka olması gerekir.

Bunun dışında Age Of Empires gibi oyunlarda, takım içinde tarih bilgisi çok yüksek, oyunun geçtiği çağlardaki dönemleri çok iyi bilen mimarlar, sanat yönetmenleri gibi hikayeye ortak olacak bir çok karakterde takım içinde bulunabilir.

Level Designers (Bölüm Tasarımcıları)

Hikayenin akışına göre veya bölümün hedeflerine yönelik, o bölümde kullanılacak araçların tanımlanması, o bölümde yapılacak işlerin belirlenmesi gibi kararları verirler. Kısaca bölümün hedefine en uygun oyun akışını düzenlerler. Mesela, bölüm sonunda bir canavarı öldürmeniz gerekiyordur fakat elinizdeki silahla onu öldürmeniz imkansızdır, haritada biraz gezersiniz ve oyunda kenarda köşede kalmış bir karakteri öldürünce onun silahını alıp, o silahla çok rahat bir şekilde canavarı öldürebilirsiniz. İşte bu gibi kararların hepsini (tabi hikaye dışına taşmadan) Level Designer'lar verir.

Bir oyunun yapısı hızlı işliyorsa çok uzun bölümler genelde oyuncuyu sıkar. Her şey çok hızlı ilerliyordur, oyun çok eğlencelidir ve oyuncu hemen bölüm sonuna gelimek ister. Örneğin Super Mario oyununda bölümler asla çok fazla uzun değildir. Bu noktada Level Designer' ın önemi çok daha net bir şekilde görülmektedir. Çünkü verdikleri kararlar direk oynanabilirliğe etki etmektedir.

Artist

Oyun menülerinin tasarımı, 3D karakerler için dokuların hazırlanması gibi görsel sanatların işlendiği aşamalarda görev alırlar.

Modelers (Modelleyiciler)

Çeşitli 2D veya 3D tasarım programları ile oyun içindeki karakterleri, binaları, köprüleri kısaca nesneleri modelleyen kişilerdir. Bir oyun için görsel zenginlik çok önemlidir. Bu bağlamda modelleyicinin ortaya koyduğu modeller çok önemlidir. Siz bir uçuş similasyonu için çok iyi bir fizik motoru yazmış olabilirsiniz ama modelleyiciniz, bir boeing 737'yi kutu gibi modeller ise oyununuzun pek tutmayacağını rahatlıkla söyleyebilirim.

Animators (Animatörler)

Bölümlerin başında, sonunda veya hikayenin gidişatına göre herhangi bir anda ortaya çıkan izlenmek için yapılmış animasyonları hazırlayan kişilerdir. Animasyonlar hikayenin anlaşılmasını destekleyen oyuncuyu oyuna bağlayan önemli öğelerden biridir. Siz oyunun menülerine hikayenin okunabileceği bir menü koyup, düz yazı şeklinde hikayeyi oyuncuya sunabilirsiniz. Fakat bu kadar uzun yazıyı herkes okumak istemez. Dolayısıyla burada hikayeyi özetleyen kısa animasyonlara ihtiyaç duyarsınız. Bunu da animatörler yapar. Hikayenin pekiştirilmesi ve daha net anlaşılması için çok önemlidirler.

Musicians (Müzisyenler)

Müzikler için, oyuncuyu oyuna çeken, grafikten sonraki en önemli etkendir diyebiliriz. Gerçekçi ve doğru zamanda oluşan ses efektleri, duruma uygun fon müziği oyunun çok daha iyi olmasını sağlar. Bu müzikleri ve ses efektlerini de müzisyenler hazırlar. Oyunun tarzına uygun müzik seçilmeside ayrı bir özen ister. Örneğin; DOOM oyunundaki ateş edince çıkan sesi asla Super Mario 'da aramazsınız.

Programmers (Programcılar)

Ortada bu kadar fazla dinamik öğe varken, bunların koordine bir şekilde nerde ve ne zaman işleyeceğini belirleyen kişiler programcılardır. Bir karakterin can sayısından tutunda, bir strateji oyunundaki kaynak yönetimine kadar arka plandaki tüm mantıksal işlemleri programlayan kişilerdir.

Testers (Testçiler)

Her yazılım çalışması sona erdikten sonra ortaya çıkan ürünün mutlaka testi yapılır. Oyun geliştirmede de durum farklı değildir. Oyunun her anının tek tek testleri yapılmalıdır. Gözden kaçan hatalar oyun çıkar çıkmaz ardından bir patch yayınlamanıza neden olur. Bu da ekstra maliyet demektir. Ayrıca bazı durumlarda oyununuz oyuncuların gözünden de düşebilir. Bu yüzden test aşaması en az analiz aşaması kadar detaylı yapılmalıdır. Bu aşamada oyundaki hatalar tespit edilir ve düzeltilir. Tüm hatalar düzeltildikten sonra oyun piyasaya sürülür. Ne var ki her yazılım çalışmasında oldugu gibi buglar mutlaka olacaktır, bunları kapamak için yamalar yayınlanır. Bu süreçte de testlere devam edilir. Test yapan kişilerin testi iyi yapması da bu noktada önemlidir.


Takım arkadaşlarımızı da tanıdıktan sonra bu kavramlar hakkında son birşey söylemek gerekiyor. Bu işe yeni başlayan veya amatör hislerle bu işle ilgilenmek isteyen kişiler için bu bilgiler hiç bir anlam ifade etmeyebilir. Fakat şahsen bir işin en temelinden öğrenilmesi gerektiğine inanıyorum. Profosyonel bir oyun geliştirme süreci içinde bulunmadığınız sürece bu karakterle karşılaşmayacaksınız belki ama bu işin dünyada profosyonel olarak bu tür kişilerle, bu şekilde yapıldığını bilmek önemlidir. Bu karakterler ve kavramlar oyun geliştirme olgusu içindeki en temel ortak öğelerdir. Oyunun türüne göre takım içinde yeni ve farklı özelliklere sahip karakterler de olabilir tabiki.

Kaynak : Beginning XNA 2.0 Game Programming

Mehmet Aydın Ünlü