Sayfalar

8 Haziran 2011 Çarşamba

XNA İle Yapılmış Basit Bir Oyun

Microsoft Visual C# 2008 Express Edition programını kullanarak yaptığım için bu kısım belki diğer programlarda farklılık gösterebilir. Öncelikle projeye kullanacağımız resimleri , yazı tipini ve ses dosyalarını eklememiz gerekiyor. Bunun için “Solution Explorer”  penceresinde, projenizin altında Content başlığına sağ tıklayarak Add>Existing Item diyoruz ve buradan ekliyoruz. Bunun yerine üst çubukta Project butonundan da aynı menüye ulaşabilirsiniz.


Bir arkaplan resmi, bir tane hareket ettireceğimiz nesnenin resmi(ben arı kullandım) ve bir tane de nesnenin üstünden geçtiğinde yediği küçük nokta ekledik. Add>Item diyerek bir de SpriteFont ekledik.  Ardından class içinde tanımlamalara başlıyoruz:                                                                                                                             

double a = 3;//Bu nesnemizin hızını belirtmek için kullandığım değişken
Texture2D ArkaPlan;//Arkaplan resmimizi tanımlayacağımız değişken
Texture2D Ari;//Hareket ettireceğimiz nesnenin resmini tanımlayacağız
Texture2D[] Nokta = new Texture2D[5];//Nesnemizin üstünden geçerek yiyeceği noktalar
Rectangle OyunPencere;
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Vector2[] Location1 = new Vector2[5];//Noktaların yerlerini tutacak olan dizi
Vector2 Location = Vector2.Zero;//Hareket ettireceğimiz nesnenin yerini tutacak olan değişken
SpriteFont Arial;//Yazı tipimiz
SoundEffectInstance backgroundmusic;// Arkaplanda çalacak olan müzik
SoundEffectInstance score;//Her nokta yendiğinde çıkacak olan ses
int skor=0;//Kullanıcının skorunu tutan değişken.                                                           

                Ardından bir constructor geliyor. Buraya pek bir şey yazmıyoruz. Constructor’ın içini şu şekilde doldurduk:

this.Window.Title = " Oyun denemesi ";//Oyunun penceresine vereceğiniz isim
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";


                Initialize metodunda, isminden de anlaşıldığı gibi, oyun başlamadan önce neleri initialize edeceğimizi belirtiyoruz. Bilmiyorum sonrasında ne olur ancak bu oyun için bir şey initialize etmemize gerek yok. O yüzden dokunmuyoruz içeriği aynı kalıyor.

base.Initialize();


                Geldik LoadContent metoduna. Bu metotta oyuna başlama durumunu hazırlıyoruz. Mesela hareket ettireceğimiz nesne nerde olacak, noktaların yeri nerde olacak, arkada çalan müziğin sesi nasıl olacak tekrar edilecek mi… gibi. Bu şekilde, oyuna başladığımızda hazır olmasını istediğimiz durumları bu metotta belirleyeceğiz.

Random rast = new Random();//Noktaları rastgele dizmek için random değişkeni yaratıyorum
spriteBatch = new SpriteBatch(GraphicsDevice);
OyunPencere = new Rectangle(0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height);//Oyun penceresini tanımlıyorum
ArkaPlan = Content.Load<Texture2D>("fil");//Arka plana belirlediğim resmi ekliyorum
Ari = Content.Load<Texture2D>("ari");//Hareket ettireceğimiz resmi ekliyorum
Arial = Content.Load<SpriteFont>("SpriteFont1");//Yazı tipimiz.
backgroundmusic = Content.Load<SoundEffect>("Pong").CreateInstance();//Arkaplanda çalacak müziği ekledim.
score = Content.Load<SoundEffect>("tong").CreateInstance();//Nokta yendiğinde çalacak müziği ekledim
backgroundmusic.Volume = 0.2f;// Burada arkaplan sesini %20 oranında azalttım
backgroundmusic.IsLooped = true;//Sürekli tekrarlanmasını sağladım
backgroundmusic.Play();// Ve müziği oynattım
for (int i = 0; i < Nokta.Length; i++)//Her bir noktaya rastgele yer vermek için kurulan for döngüsü
{
   Nokta[i] = Content.Load<Texture2D>("Adsız");//Buradaki Adsız, nokta için belirlediğim resim dosyası
   Location1[i].X = rast.Next(0, graphics.GraphicsDevice.Viewport.Width);
   Location1[i].Y = rast.Next(0, graphics.GraphicsDevice.Viewport.Height);
}


Burada öncelikle şunu belirtmek isterim ki, “ Ari = Content.Load<Texture2D>("ari")” ifadesindeki parantez içerisinde “ari” ifadesi, bizim projeye eklediğimiz resim doyasının ismidir.
                Dikkat ettiyseniz en başta SpriteFont oluşturmuştuk ancak üzerinde hiçbir işlem yapmamıştık. Şimdi o SpriteFont’un bize Arial yazı türünü vermemiz için içini nasıl değiştirmemiz gerektiğini anlatacağım. Projemizin altında yarattığımız SpriteFont’a çift tıklayarak pencereye ekleyelim ve içini düzeltelim:

<?xml version="1.0" encoding="utf-8"?>
<!--
This file contains an xml description of a font, and will be read by the XNA
Framework Content Pipeline. Follow the comments to customize the appearance
of the font in your game, and to change the characters which are available to draw
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
  <Asset Type="Graphics:FontDescription">

    <FontName>Arial</FontName>
   
    <Size>16</Size>
   
    <Spacing>0</Spacing>
   
    <UseKerning>true</UseKerning>
   
    <Style>Regular</Style>
   
    <CharacterRegions>
     
      <CharacterRegion>
       
        <Start>&#32;</Start>
       
        <End>&#255;</End>
       
      </CharacterRegion>
     
    </CharacterRegions>

  </Asset>
</XnaContent>

XML den pek anlamadığım için buraya pek bir açıklama yapamıyorum.


                UnloadContent metodu da tahmin ettiğiniz gibi LoadContent metodunun tam tersi.  Bu metodun içi boş kalıyor, en azından bu proje için.
                Gelelim en can alıcı metod olan Update metoduna. Bu metod dikkat ettiğiniz üzere parametre olarak bir GameTime değişkeni alır. Bu metod, oyunun yenileme hızı (fps) ile orantılı olarak sürekli işlem yapar. Oyun her yenilendiğinde bu metod çağırılır. Bu yüzden hareket eylemini bu metod içinde tanımlayacağız. Şimdi bu metodun içine bir göz atalım:


KeyboardState ks = Keyboard.GetState();//Klavyeden veri almak için ks değişkenini oluşturduk
Random rand = new Random();
if (ks.IsKeyDown(Keys.Escape))// Esc tuşuna basıldığında oyunu kapatan kontrol
this.Exit();

for (int i = 0; i < Location1.Length; i++)// Noktanın yenip yenilmediğini kontrol eden, yenildiyse yerini random bir yer ile değiştiren kod parçası
{
if (Location.X >= Location1[i].X - 32 && Location.X <= Location1[i].X + 32 && Location.Y >= Location1[i].Y - 32 && Location.Y <= Location1[i].Y + 32)
{
Location1[i].X = rand.Next(0, graphics.GraphicsDevice.Viewport.Width);
Location1[i].Y = rand.Next(0, graphics.GraphicsDevice.Viewport.Height);
 skor += 1;
 score.Volume = 0.3f;
 score.Play();
}
}
if (ks.IsKeyDown(Keys.R))// R ye basıldığında Arı yı pencerenin tam ortasına getiren kod parçası
{
 Location.Y = graphics.GraphicsDevice.Viewport.Height / 2;
 Location.X = graphics.GraphicsDevice.Viewport.Width / 2;
}
if (ks.IsKeyDown(Keys.Up))
Location.Y -= (int)a;
if (ks.IsKeyDown(Keys.Down))
Location.Y += (int)a;
if (ks.IsKeyDown(Keys.Left))
Location.X -= (int)a;
if (ks.IsKeyDown(Keys.Right))
Location.X += (int)a;
if (ks.IsKeyDown(Keys.L))// L ye basıldığında da tüm noktaların yerlerini değiştiren kod parçası
{
for (int i = 0; i < Location1.Length; i++)
{
Location1[i].X = rand.Next(0, graphics.GraphicsDevice.Viewport.Width);
Location1[i].Y = rand.Next(0, graphics.GraphicsDevice.Viewport.Height);
}
}
           
base.Update(gameTime);// Bu satır da her seferinde oyun zamanının yenilenmesini sağlıyor


Dikkat ettiğiniz üzere “ks.IsKeyDown(Keys.B)” ifadesinde B tuşuna basılıyorsa true döndürüyor. “ks.IsKeyUp(Keys.B)” ifadesi ise B tuşuna basılmıyorsa true döndürüyor.

                Ve son metodumuz olan Draw metoduna geldik. Burada ekranda göstermek istediğimiz çizimleri yapıyoruz.

GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
spriteBatch.Draw(ArkaPlan, OyunPencere, Color.White);
for (int i = 0; i < Nokta.Length; i++)
{
spriteBatch.Draw(Nokta[i], Location1[i], Color.White);
}
spriteBatch.DrawString(Arial, "Puan : " + skor, new Vector2(), Color.Yellow);
spriteBatch.DrawString(Arial, "Süre : " +  gameTime.TotalRealTime , new Vector2((float)(graphics.GraphicsDevice.Viewport.Width * 0.80), 30), Color.Yellow);
spriteBatch.Draw(Ari, Location, Color.White);
base.Draw(gameTime);
spriteBatch.End();


                spriteBatch.Draw metoduna dikkat ettiyseniz 3 parametre alıyor. Bunların ilki ekrana çizilecek görüntü, ikincisi bu görüntünün çizileceği yer, üçüncüsü ise rengi.
                Ekrana bir string yazdırmak istersek de kullanacağımız metod: spriteBatch.DrawString. Bu metod da 4 parametre alıyor. İlki yazı tipi , ikinci yazdırmak istediğimiz string, üçüncüsü pek bilgim olmasa da anladığım kadarıyla nereye yazdırılacağını belirten bir vector, sonuncu yani dördüncüsü de rengi.
                Draw metodu da parametre olarak GameTime aldığı için bu çizimi de sürekli yinelemek mümkün. Bunu da base.Draw(gameTime) koduyla gerçekleştiriyoruz. Böylece sürenin eş zamanlı olarak gösterilmesini sağlamış olacağız.
                Bu da kodun tam hali:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace WindowsGame1
{

    public class Game1 : Microsoft.Xna.Framework.Game
    {
        double a = 3;
        Texture2D ArkaPlan;
        Texture2D Ari;
        Texture2D[] Nokta = new Texture2D[5];
        Rectangle OyunPencere;
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Vector2[] Location1 = new Vector2[5];
        Vector2 Location = Vector2.Zero;
        SpriteFont Arial;
        SoundEffectInstance backgroundmusic;
        SoundEffectInstance score;
        int skor=0;
        public Game1()
        {
            this.Window.Title = " Oyun denemesi ";
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

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

        protected override void LoadContent()
        {
            Random rast = new Random();
            spriteBatch = new SpriteBatch(GraphicsDevice);
            OyunPencere = new Rectangle(0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height);
            ArkaPlan = Content.Load<Texture2D>("fil");
            Ari = Content.Load<Texture2D>("ari");
            Arial = Content.Load<SpriteFont>("SpriteFont1");
            backgroundmusic = Content.Load<SoundEffect>("Pong").CreateInstance();
            score = Content.Load<SoundEffect>("tong").CreateInstance();
            backgroundmusic.Volume = 0.2f;
            backgroundmusic.IsLooped = true;
            backgroundmusic.Play();
            for (int i = 0; i < Nokta.Length; i++)
            {
                Nokta[i] = Content.Load<Texture2D>("Adsız");
                Location1[i].X = rast.Next(0, graphics.GraphicsDevice.Viewport.Width);
                Location1[i].Y = rast.Next(0, graphics.GraphicsDevice.Viewport.Height);
            }

        }

        protected override void UnloadContent()
        {

        }

        protected override void Update(GameTime gameTime)
        {

            KeyboardState ks = Keyboard.GetState();
            Random rand = new Random();
           
            if ((gameTime.TotalRealTime.TotalSeconds-1) % 5 == 0)
            {
                a *= 2;
            }
            if (ks.IsKeyDown(Keys.Escape))
                this.Exit();

            for (int i = 0; i < Location1.Length; i++)
            {
                if (Location.X >= Location1[i].X - 32 && Location.X <= Location1[i].X + 32 && Location.Y >= Location1[i].Y - 32 && Location.Y <= Location1[i].Y + 32)
                {
                    Location1[i].X = rand.Next(0, graphics.GraphicsDevice.Viewport.Width);
                    Location1[i].Y = rand.Next(0, graphics.GraphicsDevice.Viewport.Height);
                    skor += 1;
                    score.Volume = 0.3f;
                    score.Play();

                }
            }
            if (ks.IsKeyDown(Keys.R))
            {
                Location.Y = graphics.GraphicsDevice.Viewport.Height / 2;
                Location.X = graphics.GraphicsDevice.Viewport.Width / 2;
            }
            if (ks.IsKeyDown(Keys.Up))
                Location.Y -= (int)a;
            if (ks.IsKeyDown(Keys.Down))
                Location.Y += (int)a;
            if (ks.IsKeyDown(Keys.Left))
                Location.X -= (int)a;
            if (ks.IsKeyDown(Keys.Right))
                Location.X += (int)a;
            if (ks.IsKeyDown(Keys.L))
            {
                for (int i = 0; i < Location1.Length; i++)
                {
                    Location1[i].X = rand.Next(0, graphics.GraphicsDevice.Viewport.Width);
                    Location1[i].Y = rand.Next(0, graphics.GraphicsDevice.Viewport.Height);
                }
            }
           
            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
            spriteBatch.Draw(ArkaPlan, OyunPencere, Color.White);
            for (int i = 0; i < Nokta.Length; i++)
            {
               spriteBatch.Draw(Nokta[i], Location1[i], Color.White);
            }
            spriteBatch.DrawString(Arial, "Puan : " + skor, new Vector2(), Color.Yellow);
            spriteBatch.DrawString(Arial, "Süre : " +  gameTime.TotalRealTime , new Vector2((float)(graphics.GraphicsDevice.Viewport.Width * 0.80), 30), Color.Yellow);

            spriteBatch.Draw(Ari, Location, Color.White);
            base.Draw(gameTime);
            spriteBatch.End();

           
        }
    }
}


                Biraz karışık anlatmış olabilirim ama sorularınız ya da eklemek istediğiniz şeyler olursa lütfen belirtin.

                İyi çalışmalar,
                Mert.

Hiç yorum yok:

Yorum Gönder