![](images/logo.gif)
Oyun Yapımı - 3 (Kullanıcı Etkileşiminin Sağlanması)
Oyun Yapımı - 3
1. Basılan Tuşlara Göre Düzgün Hareket Sağlanması:
Geçen dersimizde Entity sınıfını ve bundan türeyen Ball sınıfını
oluşturmuş, Ball nesnelerini ekrana çizdirmiştik. İsterseniz şimdi
kullanıcı etkileşimi konusuna değinelim. Oyunlarda kullanıcı etkileşimi
klavye, mouse, joystick gibi birimler ile sağlanmaktadır. SDL kütüphanesi
bize bu birimlerden girdi almada kolaylık sağlayan yordamları içerir.
Teknik olarak bu birimlerden gelen girdiler SDL sisteminde “event queue”
olarak adlandırılan yapı içerisine işlenirler. SDL_PollEvent() yordamı
ile sırada bekleyen bir “event” i elde edebiliriz. Daha sonra bu “event”
in tipine ve özelliklerine göre programımıza yön veririz.
Geçen örneklerimizde yine bu fonksiyon aracılığı ile ESC tuşuna
basılıp basılmadığını sınamayı görmüştük. Şimdi main.cpp kütüğü
üzerinde çeşitli eklemeler yaparak, programımızın çizdiği
bir adet top nesnesini ok tuşları ile hareket ettirmeyi öğreneceğiz.
// --- main.cpp --------------------
#include "types.h"
#include "Ball.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
Ball ball;
bool mov_east=false, mov_west=false,mov_north=false,mov_south=false;
void initSDL(int width,int height,int bpp) {
// Bu yoram SDL kütüphanesini
baslatan yordamdir. SDL kütüphanesinin VIDEO
// ve zamanlama kisimlarini kullanmayi düsündügümüz
için buna uygun
// parametreleri kullandik. Herhangi bir hata durumunda ise
SDL_GetError()
// yordami ile hatanin sebebini ögrenip ekrana (yada
stdout.txt kütügüne)
// yazdiriyor ve programdan çikiyoruz.
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) {
fprintf(stderr,"SDL baslatiminda hata! %s",SDL_GetError());
exit(-1);
}
// exit() yordami çagirildiginda
buna ek olarak SDL_Quit() isimli SDL yordaminin da
// çagirismasini asagidaki kod ile belirtmis oluyoruz.
SDL_Quit() yordami SDL
// kütüphanesini kapatan yordamdir. Bu sekilde artik
program sonunda SDL_Quit()
// yordamini çagirmak yerine sadece exit() yordami
ile bu isin otomatik gerçeklesmesini
// saglamis olduk.
atexit(SDL_Quit);
// Bu yordam ile nihayet genisligini,
yüksekligini ve renk çözünürlügünü
belirledigimiz
// bir pencere açiyoruz. SDL_OPENGL parametresi
bu pencereyi OpenGL altindan
// kullanacagimizi belirtiyor.
if (SDL_SetVideoMode(width,height,bpp,SDL_OPENGL) == NULL)
{
fprintf(stderr,"SDL ekrani açamadi!");
exit(-1);
}
}
void setupOpenGL(int width,int height) {
// poligonlarin cizim sirasinda oncelik
kontrolu icin Z Buffer
// teknigini kullan.
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
// poligonlarin icini doldurmada renk
gecislerini yumusak yap
glShadeModel(GL_SMOOTH);
// arka fon rengi siyah olsun
glClearColor(0,0,0,0);
// goruntuyu olusturacagimiz alani belirt.
glViewport(0,0,width,height);
// opengl de goruntu olusturulacakken
kullanilacak sanal kameranin
// lens ayarlarini gerceklestir (bakis acisi ve menzil ayarlari...)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45,(float)width/(float)height,0.1f,4000.0f);
glMatrixMode(GL_MODELVIEW);
}
void renderScene() {
// Onceki seferde cizilenleri siliyoruz.
Ayni zamanda Z Buffer
// algoritmasinin duzgun islemesi icin Z Buffer daki onceki
seferden
// kalma bilgilerde sifirlaniyor.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Kamera poziyonunu sıfırlıyoruz.
glLoadIdentity();
// Kameramızı biraz geri alalımki dünyadaki
çizimleri gözlemleyelim..
// (Yani cisimler kameranın arkasında kalmasınlar...)
glTranslatef(0.0f,0.0f,-30.0f);
// Z ekseni dogrultusunda bir hareket
durumu varsa bunu uyguluyoruz.
if (mov_north) {
static const Vec3d deltaz = {0,0,-0.1};
ball.move(&deltaz);
}
else
if (mov_south) {
static const Vec3d deltaz = {0,0,0.1};
ball.move(&deltaz);
}
// X ekseni dogrultusundaki hareket
durumunu uyguluyoruz.
if (mov_east) {
static const Vec3d deltax = {0.1,0,0};
ball.move(&deltax);
}
else
if (mov_west) {
static const Vec3d deltax = {-0.1,0,0};
ball.move(&deltax);
}
// topu ciz.
ball.render();
// Bellekte olusturulan cizim pencere
icine aktariliyor. Bu sekilde
// goruntuyu ekranda gorebiliyoruz.
SDL_GL_SwapBuffers();
}
int main(int argc,char *argv[]) {
// Ana donguden cikis icin kullandigimiz
degiskenimiz.
bool quit = false;
// SDL kütüphanesini başlatıp,
ekranda bir pencere açiyoruz.
initSDL(640,480,16);
setupOpenGL(640,480);
// Her top nesnesi için rastgele
koordinat ve renk değerleri
// belirliyoruz.
srand(time(NULL));
ball.setPosition(0.1f * (rand()%100) - 5.0f,
0.1f * (rand()%100) - 5.0f,
0.1f * (rand()%100) - 5.0f);
ball.setColor(0.01f * (rand()%100),0.01f * (rand()%100),0.01f
* (rand()%100));
while (!quit) {
renderScene();
// SDL de giris/cikis
islemleri event ler vasitasi ile yurutulur.
// Burada bir event nesnesi tanimi yapiyoruz.
SDL_Event event;
// SDL_PollEvent()
fonksiyonu ile hazirda bekleyen birsonraki event i
// event yapisi icerisinde elde ediyoruz.
while (SDL_PollEvent(&event)) {
// event.type bize event in turunu belirtir. SDL_KEYDOWN tipi tusa
// basilma durumunda olusur.
switch (event.type) {
case
SDL_KEYDOWN:
// event.key.keysym.sym degiskeni basilan tusun kodunu
icermektedir.
// SDL icerisinde tus kodlari SDLK_* biciminde tanimlanmistir. Kod
// SDLK_ESCAPE ise kontrol degiskenimizi gunleyerek donguden cikma isini
// gerceklestiriyoruz.
switch (event.key.keysym.sym) {
case SDLK_ESCAPE:
quit = true;
break;
// Yukari ok tusuna basiliyor ise kuzeye(-z yonu) gitme
olayini aktif et.
// Ayni anda hem kuzey hemde guneye(-z yonu) gidilemeyeceginden
// guneye gidilme durumunu ortadan kaldiriyoruz.
case SDLK_UP:
mov_north = true;
mov_south = false;
break;
// Yukarida yaptigimiz islemi
bu seferde tersi durum
// icin gerceklestiriyoruz.
case SDLK_DOWN:
mov_north = false;
mov_south = true;
break;
// +x ve -x yonlerindeki hareketler
icin yine +z -z
// durumlarinda davrandigimiz gibi davraniyoruz.
case SDLK_LEFT:
mov_east = false;
mov_west = true;
break;
case SDLK_RIGHT:
mov_east = true;
mov_west = false;
break;
}
break;
// Basilan bir tus birakildigi zaman SDL_KEYUP event i
olusur.
case
SDL_KEYUP:
switch (event.key.keysym.sym) {
// kuzeye gidilme durumunu iptal ediyoruz..
case SDLK_UP:
mov_north = false;
break;
// guneye gidilme durumunu iptal ediyoruz..
case SDLK_DOWN:
mov_south = false;
break;
// batiya (-x) gidilme durumu ortadan
kaldiriliyor
case SDLK_LEFT:
mov_west = false;
break;
// doguya (+x) gidilme durumu sonlandiriliyor.
case SDLK_RIGHT:
mov_east = false;
break;
}
break;
// Pencerenin kapatma tusuna basilmasi ise yine
bir event uretir.
// Bu
event in tipi SDL_QUIT dir. Bu durumda da yine cikis islemini
// yapiyoruz.
case
SDL_QUIT:
quit = true;
}
}
}
return 0;
}
Yukarıdaki koda dikkat ederseniz, topa yön verme işlemlerini tuşa
basılmaları kontrol ettiğimiz ana yordam içerisinden yapmadığımızı
görürsünüz. Eğer böyle yapmış olsaydık kesikli
bir hareket elde ederdik (Bunun sebebi klavyede tuşa basılma olayının donanım
tarafından kesikli biçimde taranmasıdır.). Kontrol değişkenleri aracılığı
ile kesiksiz, düzgün bir hareket elde etmiş olduk.
2. Oyun Alanı Sınıfının Oluşturulması:
Şu ana kadar görüntülediğimiz top nesnesi altında bir yüzey
olmadığı için havada asılı olarak duruyordu. Şimdi isterseniz oyun
alanı olarak kullanacağımız yüzeyi ifade eden nesneyi oluşturalım.
Bu sınıfı yine Ball sınıfında yaptığımız gibi Entity sınıfından türeterek
oluşturacağız. "render()" yordaminda ise şimdilik düz bir dörtgen
yüzey görüntülemekle yetineceğiz. Bu sınıfımıza "Arena"
adını verelim. Aşağıda sınıfa ait kod görüntüleniyor.
// --- arena.h --------------------
#ifndef __ARENA_H__
#define __ARENA_H__
#include "entity.h"
class Arena : public Entity {
public:
Arena(int width=30,int height=30);
~Arena() {};
void setWidth(int w);
void setHeight(int h);
virtual void render();
private:
int width, height;
};
#endif
// --- arena.cpp --------------------
#include "arena.h"
Arena :: Arena(int width,int height) {
setWidth(width);
setHeight(height);
}
void Arena :: setWidth(int w) {
width = w;
}
void Arena :: setHeight(int h) {
height = h;
}
void Arena :: render() {
glPushMatrix();
glTranslatef(position.x,position.y,position.z);
glRotatef(90,1,0,0);
glRectf(-width/2,-height/2,width/2,height/2);
glPopMatrix();
}
Oluşrurduğumuz arena nesnesini görüntüleyen ve kameranın
konumunu arena nın tümünü gösterecek şekilde ayarlayan
değişiklikler "main.cpp" içerisinde yapılmıştır. Bu kodun tamamını
sitemizin dosyalar bölümünden indirebilirsiniz. Gelecek dersimizde
oyunun amacına karar vereceğiz(nihayet :) ve bu doğrultuda yeni elemanlar
eklemeye devam edeceğiz.
Deniz Aydınoğlu :: 2002
|
|