22 Kasım 2008 Cumartesi

XNA’ de Oyuncu İsmini Input Olarak Alma

XNA klavyeden girdiğin her tuşu tutar. Bu tuşlara göre yerleştirdiğin nesneleri hareket ettirirsin ya da bir sonraki aşamaya geçersin,.. vs. Ancak ne zamanki ismini oyuna yazmak istediğinde bastığın tuşlardaki karakterler ekranda görünmez. XNA kütüphanesinin sağladığı bir textbox nesnesi yok. Bu nedenle oyunu oynayan kişi adını yazabilmesi için bizim bir takım kodları yazmamız gerekmektedir.

Bu makalede bu işlemlerin nasıl yapıldığı ve kullanıcının adını girmesi için uygulamaya eklenmesi gereken kodlar açıklanmaktadır.

1. Karakterleri Tutan Diziyi Tanımlama

Klavyeden girilen karakterler “Keys” adı verilen bir dizide tutulur. Bu diziden karakterlere “GetPressedKeys” mesajı ile ulaşabiliriz. Bu dizi içinde karakterler tutulurken özel bir tanımlama ile tutuluyor. Örneğin NumPad’ den girilen numaralardan “1” “NumPad1” olarak, klavyedeki numaralar başlarına “D” karakteri gelerek (“1” “D1” olarak tutulmaktadır. ) ve harfler aynı klavyedeki haliyle tutulmaktadır.

Bunun için iki boyutlu bir dizi tanımlanır. Dizinin adı “keyToCharacter” olsun. Bu dizi girilen karakterlerin kullanıcının anlayacağı türe çevrilmesi için kullanılır. Örneğin kullanıcı bir tuşa bastığında; bu karakteri ekrana basmak için girilen karakterin “Keys” tipinde tanımlı olan dizideki karşılığı bulunur. “NumPad1” ise bu karakter ekrana 1 olarak ekrana yazılacak olan tipi karakter katarı olarak tanımlanmış değişkene (“string”) eklenir.

Tanımlanması gereken dizi:

private string[,]keyToCharacter = {{"A", "a"},{"B", "b"}, {"C", "c"}, {"D", "d"}, {"E", "e"}, {"Space", " "},
{"F", "f"}, {"G", "g"}, {"H", "h"}, {"I", "i"}, {"J", "j"},
{"K", "k"}, {"L", "l"}, {"M", "m"}, {"N", "n"}, {"O", "o"},
{"P", "p"}, {"Q", "q"}, {"R", "r"}, {"S", "s"}, {"T", "t"},
{"U", "u"}, {"V", "v"}, {"W", "w"}, {"X", "x"}, {"Y", "y"},
{"Z", "z"},
{"NumPad1", "1"}, {"NumPad2", "2"},{"NumPad3", "3"},{"NumPad4", "4"},
{"NumPad5", "5"}, {"NumPad6", "6"},{"NumPad7", "7"},{"NumPad8", "8"},
{"NumPad9", "9"}, {"NumPad0", "0"},
{"D1", "1"}, {"D2", "2"}, {"D3", "3"}, {"D4", "4"}, {"D5", "5"},
{"D6", "6"}, {"D7", "7"}, {"D8", "8"}, {"D9", "9"}, {"D0", "0"}
};



2. “EkranaYazma” Sınıfı

Kullanıcını ekrana ismini girmesi için yapılan işlemleri gerçekleştiren kodları bir sınıfta toplarsak daha kullanışlı ve anlaşılır bir program yazmış oluruz. Bunun için bu programda tanımlanan sınıfın adı “EkranaIsimYazma” dır. Bu sınıfta 2 adet metot geçekleştirimi yapılmıştır ve gerekli alt alanlar tanımlanmıştır.

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 EkranaOyuncuAdiniYazma
{
class EkranaIsimYazma
{
//tanımlanan alt alanlar
private string[,]keyToCharacter = {{"A", "a"},{"B", "b"},{"C", "c"}, {"D", "d"}, {"E", "e"}, {"Space", " "},
{"F", "f"}, {"G", "g"}, {"H", "h"}, {"I", "i"}, {"J", "j"},
{"K", "k"}, {"L", "l"}, {"M", "m"}, {"N", "n"}, {"O", "o"},
{"P", "p"}, {"Q", "q"}, {"R", "r"}, {"S", "s"}, {"T", "t"},
{"U", "u"}, {"V", "v"}, {"W", "w"}, {"X", "x"}, {"Y", "y"},
{"Z", "z"},
{"NumPad1", "1"}, {"NumPad2", "2"},{"NumPad3", "3"},{"NumPad4", "4"},
{"NumPad5", "5"}, {"NumPad6", "6"},{"NumPad7", "7"},{"NumPad8", "8"},
{"NumPad9", "9"}, {"NumPad0", "0"},
{"D1", "1"}, {"D2", "2"}, {"D3", "3"}, {"D4", "4"}, {"D5", "5"},
{"D6", "6"}, {"D7", "7"}, {"D8", "8"}, {"D9", "9"}, {"D0", "0"}
};

private Keys[] keyMap;
private KeyboardState keyboardState, lastKeyboardState;
private const int maxNameLength = 15;
private const int characterNum = 47;
private string userName = "player 1";



“maxNameLength” kullanıcının gireceği adın maksimum kaç karakterde olacağını, “userName” kullanıcı adını, "keyMap" kalvyeden basılan karakterlerin tümünü, “characterNum” dizide tanımlanan karakter sayısını tutmaktadır.

“CharacterDelete” metodu:

Bu metot kullanıcının isim girerken yanlış ya da istemediği bir karakter girdiğinde bu karakter veya karakterlerin silme işlemini gerçekleştirmek için yazılmıştır. Bu metot her “back space” tuşuna basıldığında çağrılır.

Metot gerçekleştirimie baktığımızda önce şu anki tuş durumunu anlamamız için “keyboardState” adlı değişkene basılan tuşu aktaran metottan dönene değer atılır. Ardından “keyboardState” nesnesine “IsKeyDown” mesajını “Keys.Back” argümanını vererek göndeririz. Böylece “backspace” tuşunu elde tutmuş oluruz eğer basıldıysa. Bu ifadenin bulunduğu kontrole bir de kullanıcı adının 0’dan büyük olması koşulunu ekleriz.

Koşullar sağlandığında girilen kullanıcı adının sonundaki karakter silinir. Bu işlem için kullanılan metot string işlemlerde kullanılan “SubString” metodudur.

public string CharacterDelete()
{
keyboardState = Keyboard.GetState();

if (keyboardState.IsKeyDown(Keys.Back) && lastKeyboardState.IsKeyUp(Keys.Back) && userName.Length > 0)
{
userName = userName.Substring(0, userName.Length - 1);
}

return userName;
}//end of void CharacterDelete


“CharacterDisplay” metodu:

Kullanıcının klavyeden girdiği karakterleri kullanıcı adını içeren değişkene eklenmesini sağlayan metottur. Bunun için basılan tüm karakterler “keyMap” adlı diziye atılır. Ardından foreach döngüdü sayesinde bu karakterler tek tek kontrol edilir, bu kontrol işleminin gerçekleştirimi nasıl yapılıyor?

Programda en başta belirtilen karakterleri içeren “keyToCharacter” dizisindeki karakterlerle girilen karakterler karşılaştırılır ve bu dizi içinde yer alan karakterler kullanıcı adını tutan “userName” karakter katarına (“string”) eklenir.

Public string CharcterDisplay()
{
keyMap = (Keys[])keyboardState.GetPressedKeys();
foreach (Keys key in keyMap)
{
for (int i = characterNum-1; i >=0; i--)
{
if (key.ToString() == keyToCharacter[i, 0] && lastKeyboardState.IsKeyUp(key))
{
userName += keyToCharacter[i, 1];
break;
}//end of inner if condition
}//end of for loop
}//end of foreach loop
lastKeyboardState = keyboardState;
return userName;
}//end of void CharcterDisplay
“keyboardState” değişkenini “lastKeyboardState” içine atmamız daha önceden bir karaktere basılıp basılmadığını kontrol etmemizi sağlar. XNA’ de FPS (saniyede kaç kere ekrana yazdırdırdığın) kavramı çok önemlidir.. Eğer bu satırı silersek “backspace” tuşuna bir kere bastığımızda birden fazla karakter silinir. Klavyeden bir karakter girdiğimizde ise aynı karakter birden fazla yazılır. FPS kavramı bu nedenle önemlidir. Bu nedenle son basılna karakterle ilk karakter aynı ise bu işlem bir kere yapılır, son karakterle ilkinin aynı olma olasılığını kontrol etmezsek bir kere bastığımızda bire karakter saniyedeki karakter yazma miktarı ne akdarsa ekrana o kadar yazılır (4 FPS ise saniyede 4 kere ekrana yazılır).

3. “Game1.cs” Sınıfı İçinde Yapılan Değişiklikler

Texture2D backgroundTexture;
Rectangle viewportRect;
EkranaIsimYazma ekranaYazmaObj;
string userName;

Sade bir ekrana yazı yazmaktansda bir arka plana yazı yazmak daha gösterişli olabilir. Zaten bu uygulamayı oyunlarımızda kullandığımızda bir resim üzerine yazacağız. İki boyutlu bir arka plan resmi eklemek için bu resim bilgilerini tutan “backgroundTexture” isimli değişkeni ve bu resmin başlangıç koordinatlarını tutacak olan “viewportRect” nesnesini tanımlarız.

Ardından bu tanımlamalara ekrana isim yazmamış için gerekli olan değişkenleri ekleriz. Bunlardan biri “EkranaIsim Yazma” sınıfındaki mesajları göndereceğimiz “ekranaYazmaObj” nesnesidir. Diğer değişken ise geri mesaj sonunda geri döndürülen kullanıcı adını tutması için tanımlanmış olan “userName” değişkenidir.

Ardından “LoadContent” metodu içine:
backgroundTexture =Content.Load("Sprites\\background");
Arial = Content.Load("Fonts/Arial");
ekranaYazmaObj = new EkranaIsimYazma();
//drawable area of the game screen.
viewportRect = new Rectangle(0, 0,
graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height);
Yukarıdaki kod satırlarının yazılması gerekir ki oyun sırasında bir kere çağrılacak olan bu metotla birlikte gerekli yüklemeler ilgili nesnelere yapılsın.

Arial = Content.Load("Fonts/Arial");

Bu kod satırı sayesinde ekranda belirlenecek olan kullanıcı adının hangi yazı tipinde olacağı belirtilir. Bunun için yapmamız gereken bir işlem ise “Solution” daki “Content” e sağ tıklayıp Fonts adında bir klasör eklemek , ardından bu klasöre yine sağ tıklatıp “Add new Item” seçeneğini seçtikten sonra “Sprite Font” a tıklayıp “Arial.spritefont” html’ ini projeye eklemektir.

“Update” metodu içine yazılması gerekenler programda birden çok kez yapılan olan işlemlerdir. Kullanıcını karakter girmesi ya da bir karakteri silmesi birden fazla kez yapılancak olan işlemlerdir. Bu nedenle bu mesajları ilgili nesneye verdiğimiz uygun yer bu metodun içidir. Yazılacak satırlar:

userName = ekranaYazmaObj.CharacterDelete();
userName = ekranaYazmaObj.CharcterDisplay();

Sıra geldi ismin ekrana çizilmesine. Çizilmek eyleminim kullandım, çünkü bir resim üzerine işlem yapıyoruz.

Ekrana resmi bastırmayı sağlayan metot “Draw” metodudur. Bu metot içinde önce resmi ekleriz ardında bu resmin üzerine kullanıcın girmiş olduğu ismi ekleriz.

spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
//Draw the backgroundTexture sized to the width
//and height of the screen.
spriteBatch.Draw(backgroundTexture, viewportRect, Color.White);
//ikinci sekli de dogru arka plani ekrana bastirmada
//aşagidaki satirda kullanilabilir
//spriteBatch.Draw(backgroundTexture, new Vector2(0, 0), Color.White);
spriteBatch.DrawString(Arial, "Your Name: " + userName + "<", new Vector2(100, 100), Color.White); spriteBatch.End();


Hiç yorum yok: