Skip to main content

Bu yazıda ilk oyunumuz olarak sayılabilecek, basit, birkaç model içeren, kullanıcı kontrollü bir araba gezintisi oyunu yapacağız. Bu oyunu yaparken bundan önce yazmış olduğum yazılardan birçoğuna değineceğiz. Bu yüzden şimdiye kadar eğer bir konuda eksiğiniz varsa tamamlamanızı öneririm. Bu oyunu hazırladıktan sonra daha detaylı görsellik elde etmek için grafikleri ekran kartına çizdirmek üzere HLSL programlama diline giriş yapacağız.

Oyunu programlamaya başlamadan önce zemin oluşturması için Microsoft XNA programlama örneklerinden aldığım zemin dokusunu paylaşmak istiyorum. Aşağıdaki bağlantıdan gereken dosyaları indirip projenize ekleyebilirsiniz. İki dosyayı da projeye eklerseniz bir uyarı alacaksınız. Bu uyarının nedenini daha önceki oyuna bir model yüklenmesi sayfasında bulabilirsiniz.

XNA Checker Ground

Artık oyunumuzu programlamaya hazırız. İlk önce global olarak oyunda kullanacağımız değişkenleri tanımlayalım.

GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;

List<CModel> models = new List<CModel>();
CModel player;
Camera camera;

Dikkat ederseniz oyuncunun kullanacağı modeli models listesi dışında player olarak ayrı tanımladım. Bu tamamen keyfi bir seçimdir, isterseniz oyuncunun modelini de models listesi içinde tutabilirsiniz. Oyun ayarları ile ilgili farklı değişiklikler yapmak isterseniz, varsayılan kodun altına, Game1() yapıcı methodu içinde tanımlayabiliriz.

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

    this.Window.AllowUserResizing = false; // Pencerenin boyutlarını sabitlemek için

    // Oyunu tam ekran çözünürlüğüne göre ayarla
    graphics.PreferredBackBufferWidth = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;
    graphics.PreferredBackBufferHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;

    graphics.PreferMultiSampling = true; // Çoklu örnekleme (daha iyi grafikler için)
    graphics.SynchronizeWithVerticalRetrace = true; // Vertical Sync Bekleme ayarı
    //graphics.ToggleFullScreen(); // Oyunu tam ekran oynamak için
}

Daha sonra LoadContent() methodu içinde gerekli modelleri yükleyelim.

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

    camera = new ChaseCamera(new Vector3(0, 300, 800), new Vector3(0, 200, 0), new Vector3(0, 0, 0), GraphicsDevice);

    player = new CModel(Content.Load<Model>("Skyline"), Vector3.Zero, Vector3.Zero, new Vector3(1f), GraphicsDevice);
    models.Add(new CModel(Content.Load<Model>("Ground"), Vector3.Zero, Vector3.Zero, new Vector3(1f), GraphicsDevice));
}

Burada bir adet takip kamerası (ChaseCamera), oyuncu için bir adet araba modeli ve zemin yüklenmektedir. Oyunda bulunan kameranın ve oyuncunun modelinin güncellemesi işlemlerini Update() methodu içinde gerçekleştireceğiz.

protected override void Update(GameTime gameTime)
{
    // ESC'ye veya Joystick'den Geri tuşuna basarak oyundan çıkmak için
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Escape))
        this.Exit();

    updateModel(gameTime); // Oyuncunun güncellenmesi
    updateCamera(gameTime); // Kameranın güncellenmesi

    base.Update(gameTime);
}

Daha sonra güncellenen modellerin çizilmesi, yani Draw() methodu işlemileri gelmektedir.

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

    foreach (CModel model in models)
        if (camera.BoundingVolumeIsInView(model.BoundingSphere))
            model.Draw(camera.View, camera.Projection);

    if (camera.BoundingVolumeIsInView(player.BoundingSphere))
        player.Draw(camera.View, camera.Projection);

    base.Draw(gameTime);
}

Burada dikkat edilmesi gereken bir durum vardır. Player modelini ayrı olarak tanımladığımız için foreach döngüsü dışında kalmaktadır. Models dizisi içinde kullanan programcılar için bu kısım gerekli değildir.

Kameranın güncellenmesi için gereken değerleri hesaplayan updateCamera() methodu ise şu şekildedir.

void updateCamera(GameTime gameTime)
{
    // Kamerayı modelin yeni konumu ve açısına göre yeniden konumlandır
    ((ChaseCamera)camera).Move(player.Position, player.Rotation);
    // Kamerayı Güncelle
    camera.Update();
}

 Son olarak ise oyuncunun kontrollerine göre araba modelini güncellememizi sağlayan updateModel() methodu şu şekildedir. Bu kısım tamamen keyfi olarak programlanabilir. Böylelikle oyununuzun gerçekçiliğini yada hayal gücünüzün limitlerini deneyebilirsiniz.

void updateModel(GameTime gameTime)
{
    KeyboardState keyState = Keyboard.GetState();
    Vector3 rotationChange = new Vector3(0, 0, 0);
    Vector3 positionChange = new Vector3(0, 0, 0);
    Vector3 reverseConstant = new Vector3(0, 1, 0);

    Matrix rotation = Matrix.CreateFromYawPitchRoll(player.Rotation.Y, player.Rotation.X, player.Rotation.Z);

    // Basılan tuşlara göre aracın gideceği yönleri hesapla
    if (keyState.IsKeyDown(Keys.W) || keyState.IsKeyDown(Keys.Up))
        positionChange += Vector3.Transform(Vector3.Forward, rotation) * (float)gameTime.ElapsedGameTime.TotalMilliseconds * 2;
    if (keyState.IsKeyDown(Keys.S) || keyState.IsKeyDown(Keys.Down))
    {
        positionChange -= Vector3.Transform(Vector3.Forward, rotation) * (float)gameTime.ElapsedGameTime.TotalMilliseconds / 2;
        reverseConstant = new Vector3(0, -1, 0); // Araba geri giderken direksiyonu ters yöne döndür
    }
    if ((keyState.IsKeyDown(Keys.A) || keyState.IsKeyDown(Keys.Left)) && positionChange.Length() > 0)
        rotationChange += new Vector3(0, 1, 0) * reverseConstant;
    if ((keyState.IsKeyDown(Keys.D) || keyState.IsKeyDown(Keys.Right)) && positionChange.Length() > 0)
        rotationChange += new Vector3(0, -1, 0) * reverseConstant;

    // NOS :P
    if (keyState.IsKeyDown(Keys.Space))
        positionChange *= 2;

    // Oyuncunun konumunu ve dönme miktarını güncelle
    player.Position += positionChange;
    player.Rotation += rotationChange * .025f;

}

Burada dönme kontrollerini gerçekleştiren “if” kodu içerisindeki positionChange.Length() değeri ile aracın ilerleyip ilerlemediği kontrol edilip, araç eğer ilerlemiyorsa dönmemesi sağlanmaktadır. Ancak burada aracın gezdirilmesi tamamen fizik kurallarından bağımsız, keyfi olarak ötelemelerden ibarettir. Gerçek fiziksel yapıları içeren bir oyun programlamak için JigLibX veya Henge3D gibi fizik motorlarına ihtiyaç vardır.

Son olarak oyunumuzun daha iyi grafik özelliklerini desteklemesi adına proje ayarları içerisinde küçük bir değişikliğe ihtiyaç vardır. XNA projeleri ilk açıldıklarında varsayılan olarak Windows Phone’da çalışabilir düzeyde oyunlar için ayarlı gelmektedir. Ancak mobil cihazlar tahmin edeceğiniz gibi her grafik özelliğini desteklememektedir. Bu yüzden oyunumuzu PC veya XBox için derlediğimizi proje ayarlarında belirtmeliyiz. Bu ayarı yapmak için projeye sağ tıklayarak “Properties” bölümüne girip, “XNA Game Studio” sekmesi altındaki “Use HiDef to access the complete API” seçeneğini aktif hale getirmeliyiz.

xna_game_profiles