Oyun Yapımı - 1
Oyun Yapimi - 1

1. Giriş:

Oyun yapımı ile ilgili bu döküman serisinde sizlerle birlikte adım adım basit bir oyun yazılımı gerçekleştireceğiz. Yazılımın programlanması sırasında yeri geldiğince kullanılan teknikler hakkında açıklayıcı bilgilerde bulunup, ilgili grafik teknikleri hakkında bilgiler verilecek. Bu şekilde hem bir oyun projesinde uygulanan yöntemler hakkında bilgi sahibi olacak, hemde sonuçta üzerinde istediğimiz değişimleri yapabileceğimiz bir oyun elde edeceğiz.

Geliştirme dili olarak C++ kullanacağız. Yazılımı nesneye yönelik bir programlama mantığı ile geliştirmek düşüncesindeyim. Böylelikle üzerinde eklemeler yapmak daha kolay olacaktır. Grafik kütüphanesi olarak ise SDL kullanacağız. Geliştireceğimiz oyun 3 boyutlu olacağı için bu alanda da OpenGL ‘den faydalanacağız. SDL kütüphanesini bir pencere oluşturmak ve kullanıcıdan girdi almak için kullanacağımız için aslında SDL kullanmak istemeyen arkadaşlar bu kısımları kendi istedikleri API ile yazıp, diğer oyun ile ilgili nesneleri kendi programlarına ekleyebilirler. Projenin SDL ye bağımlı kısımları en alt düzeyde olacağından bu ayrım işini gerçekleştirmek inanıyorum ki çok zor olmayacaktır. GLUT kütüphanesindeki bazı OpenGL yordamlarından da faydalanmak istiyorum. Böylelikle daha az kod yazarak daha çabuk sonuçlara ulaşabiliriz. Dileyen arkadaşlar GLUT, WinAPI gibi ortamları pencere yönetimi ve girdi/çıktı için SDL yerine kullanabilirler. Kodumuzun geri kalan kısımları zaten standart olan C++ yapıları ve OpenGL çağırımlarından oluşacak. Ben gerçekleştirim platformu olaran Windows ve VC++ kullanacağım. Windows platformunu bu ortamın yaygın kullanımı nedeniyle seçmiş bulunmaktayım. İsteyen arkadaşlar daha farklı derleyici ve ortamları kullanabilirler. SDL ve OpenGL kullanımı bu konuda bir sorun yaratmayacaktır. Ben kod içerisinde derleyici ve işletim sisteminden bağımsız şekilde yapılar kullanacağım.

Bu projenin amacı sizlere C++ ya da OpenGL kullanımını öğretmek değil. Bunu önceden belirtmek istiyorum. Amacımız bir oyun yazılımı gerçekleştirme aşamalarını programlama yaparak özümsetmek. Tabiki elimden geldiğince OpenGL çağırımlarını açıklayacağım, SDL ile ilgili kısımlarda da gerekli açıklamalarda bulunacağım. Fakat yinede özellikle OpenGL ile ilgili hiçbirşey bilmiyorsanız, bu konuda bir kaynaktan başlangıç bilgilerini edinmenizi tavsiye ediyorum. SDL kullanımı konusunda ise bir kaynağa ihtiyacınız olacağını düşünmüyorum. Açıklamalarım başlangıç için yeterli olacaktır. Evet, artık başlayabiliriz :).

2. SDL Kurulumu ve Derleyici Ayarları:

SDL kütüphanesini www.libsdl.org adresinden indirin ve örneğin bilgisayarınızın c:\SDL dizini altına kurun. Kurulum işlemi indirdiğiniz zip kütüğünü bu dizine açmaktan ibarettir. Bu işlemden sonra yapacağınız bazı kopyalama işlemleri bulunmakta. İlk olarak SDL içindeki include dizinini VC++ ın include dizinine kopyalamamız gerekmekte. Bu işlem için öncelikle VC++ ın include dizinini bulun ve bu dizin altında SDL isimli bir alt dizin oluşturun. Bu dizin içerisine SDL include kütüklerini kopyalayın. SDL içerisindeki lib dizininde bulacağınız sdl.lib ve sdlmain.lib isimli kütükleri de yine VC++ ın lib dizini altına direk olarak kopyalayın. Sdl.dll isimli kütüğü ise bilgisayarınızın Windows\System dizinine kopyalayın. Artık geriye sadece VC++ derleyici ayarlarını yapmak kaldı.

VC++ ı açın ve yeni bir proje oluşturun. Proje tipi olaran Win32 application veya Win32 consol application seçebilirsiniz. Bu aşamadan sonra çıkan diyaloglardan boş bir proje oluşturma seçeneğini seçin. Proje oluşturulduktan sonra Project->Settings menüsüne girin. Burada Link tabında bulunan Object/library modules kısmına sdl.lib sdlmain.lib opengl32.lib glu32.lib glut32.lib satırlarını ekleyin. Sisteminde opengl kütüphanesi ve glut kütüphanesi bulunmayan arkadaşlar bunları sistemlerine kurmuş olmalıdırlar. VC++ kurulu olduğu için OpenGL ile ilgili kütüphaneler zaten sisteminizde hazır olarak bulunuyor olacaktır. Fakat GLUT kütüphanesini eğer daha önce kurmadıysanız http://www.xmission.com/~nate/glut.html adresinden son sürümünü indirip sisteminize kurun.  Daha sonra C++ tabındaki code generation bölümüne girin. Burada use runtime library kısmında multithreaded DLL seçeneğini seçin. Evet böylece derleyici ayarlarını da tamamlamış bulunuyoruz.

3. Proje Gerçekleştirim Yöntemi Hakkında:

İsterseniz kod yazma işine hemen dalmadan önce gerçekleştireceğimiz yazılımın ana hatlarına karar verelim. Her yazılım projesinde olduğu gibi oyunları da gerçekleştirirken programlama öncesi yapılan düzenli bir tasarım aşaması daha sonra işimizi çok kolaylaştır. Biz burada çok kapsamlı bir tasarım yapmayacağız. Çünkü proje adım adım gelişirken kafamızda yeni fikirler oluştukça bunları ekleyeceğimiz bir yöntem izliyoruz. Amacımız oyun yapımı teknikleri yönünde ders nitelikli bir çalışma yapmak olduğu ve işin yazılım mühendisliği kısmı ile ilgilenmeden öncelikli olarak oyun yapımının grafiksel gerçekleştirimi yönü daha ağır bastığı için bu seçimi yaptım, lütfen bu konuda acımasız yargılarda bulunmayın :). Derslerimiz ilerledikçe gereksinim duyacağımız modülleri nesneye yönelik olarak tasarlayacak ve kodlayacağız. Bu şekilde ilerleyerek kodlarımızı birbirine entegre etmemiz kolaylaşacaktır. (Bakın, en azından yazılım mühendisliğinin ilkelerinden birine sadık kalıyoruz ;) ).

Şimdi kod yazma işine girişelim isterseniz. Bu kadar teorik bilgi yeterli...

4. SDL ve OpenGL e İlk Adımlar:

Herşeyden önce üzerinde görsel işlemlerimizi yapacağımız bir pencereye ihtiyacımız var. Bu iş için SDL kütüphanesini kullanacağımıza göre, şimdi nasıl kullanacağımızı kod yazarak öğrenelim.

İlk olarak projemize main.cpp isimli bir kütük ekleyelim. Bu kütük içerisinde C++ programımızın main() giriş yordamı bulunacak. Aşağıdaki kodu bu kütük içerisine yazın.

#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif

#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <gl/glut.h>
#include <sdl/sdl.h>

#include <stdio.h>
#include <stdlib.h>

int main(int argc,char *argv[]) {

   return 0;
}



Bu kodu hatasız bir biçimde derlediğinizden emin olun. Burada yaptığımız tek şey SDL ve OpenGL ile ilgili include ları yapmak ve Win32 platformunda çalışıyor isek olmazsa olmaz olan windows.h ı include etmek. Şimdi SDL ile ilgili başlangıç ayarlarını gerçekleştiren ve bir pencere açan yordamı yazalım.

void initSDL(int width,int height,int bpp) {

   // Bu yoram SDL kütüphanesini başlatan yordamdır. SDL kütüphanesinin VIDEO
   // ve zamanlama kısımlarını kullanmayı düşündüğümüz için buna uygun
   // parametreleri kullandık. Herhangi bir hata durumunda ise SDL_GetError()
   // yordamı ile hatanın sebebini öğrenip ekrana (yada stdout.txt kütüğüne)
   // yazdırıyor ve programdan çıkıyoruz.

   if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) {
      fprintf(stderr,"SDL başlatımında hata!\n%s",SDL_GetError());
      exit(-1);
   }

   // exit() yordamı çağırıldığında buna ek olarak SDL_Quit() isimli SDL yordamının da
   // çağırışmasını aşağıdaki kod ile belirtmiş oluyoruz. SDL_Quit() yordamı SDL
   // kütüphanesini kapatan yordamdır. Bu şekilde artık program sonunda SDL_Quit()
   // yordamını çağırmak yerine sadece exit() yordamı ile bu işin otomatik gerçekleşmesini
   // sağlamış olduk.

   atexit(SDL_Quit);

   // Bu yordam ile nihayet genişliğini, yüksekliğini ve renk çözünürlüğünü belirlediğimiz
   // bir pencere açıyoruz. SDL_OPENGL  parametresi bu pencereyi OpenGL altından
   // kullanacağımızı belirtiyor.

   if (SDL_SetVideoMode(width,height,bpp,SDL_OPENGL) == NULL) {
      fprintf(stderr,”SDL ekranı açamadı!”);
      exit(-1);
   }

}

Şimdi main() fonksiyonu içerisinde yer alması gereken ana program döngüsünü gerçekleştirelim. Tüm yazacağınız oyun projelerinde şu yada bu şekilde bir ana döngünüz olmak zorunda. Sonuçta devamlı olarak kullanıcıdan girdi almak, işlemler yapmak ve ekrandaki görüntüyü tazelemek zorundasınız. Bizim yazacağımız basit ana döngü kullanıcı ESC tuşuna basıncaya kadar hiç bir şey yapmadan programı devam ettiriyor. Böylelikle SDL tarafından oluşturulan pencereyi gözlemleyebiliyoruz. Main() yordamimiza aşağıdaki şekilde eklentileri yapalım. Bu arada artık yazdığımız koda yeni bir eklenti yapıldığı zaman bunu farklı bir biçimde yazarak belirteceğiz. Böylelikle yeni yazılan satırları daha rahat takip edebilirsiniz

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);

      
   while (!quit) {

      // 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;
               }
               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;
}

Evet artık bir penceremiz var ve kullanıcıdan tuşa basılmaları almayı da görmüş olduk. Fakat henüz penceremize birşey çizmediğimiz için pencere içi sizinde gördüğünüz gibi ekranda varolan görüntüyü aynen koruyor. Grafik uygulamalarında görüntü oluşturma mantığı aslında çok basittir. Bir görüntüyü devamlı olarak pencerenize çizersiniz, işte bu kadar. Yani yapmamız gereken bir yordam hazırlamak, bu yordam içerisinde pencere içine çizim yapmak ve bu yordamı ana program döngümüz içerisinden devamlı olarak çağırarak görüntünün tazelenmesini sağlamak. Fakat çizim işlemlerinde OpenGL kullanacağımız için öncelikle OpenGL ile ilgili bazı başlangıç ayarlarını yazmamız gerekmekte. Aynen SDL için yaptığımız gibi OpenGL içinde bu ayarları gerçekleştireceğimiz bir yordam yazalım. Aşağıda bu yordamı görüyorsunuz.

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,4,4000);
   glMatrixMode(GL_MODELVIEW);

}

Bu yordam içerisinde çok basit olarak ilgili açıklamalar yapıldı. Açıkçası bu açıklamalarda çok teknik konuşmamaya dikkat ettim. Daha fazla bilgiyi OpenGL ile ilgili kaynaklarda bulabilirsiniz. Aslında yukarıdaki kodu ilk seferde anlamanızda pek gerekli değil. Yani anlamadım diye fazla üzülmeyin, bunlar neredeyse standart olmuş OpenGL ayar prosedürleridir.

Şimdi çizim işlemini yapacak olan yordamı yazalım.

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);
      
   // Bellekte olusturulan cizim pencere icine aktariliyor. Bu sekilde
   // goruntuyu ekranda gorebiliyoruz.

   SDL_GL_SwapBuffers();

}

Bu yordam içerisinde ekranı sildik ve bellekte oluşturulan görüntüyü çizmesi için SDL kütüphanesine ilgili komutu verdik. Bu noktada teknik bir açıklama daha yapmak gerekiyor. Dikkat ederseniz bellekte oluşturulan görüntü dedim. Bunu şöyle kafanızda canlandırabilirsiniz. Bilgisayarınızın belleğinde bir alan üzerinde çizim işlemlerinizi gerçekleştiriyorsunuz. Bu aşamada ekranda bir görüntü göremessiniz. Çünkü bu bellek bölgesi henüz grafik kartınızın çizimi gösterme ile ilgili kesimlerine aktarılmamıştır. Çizim işlemlerimizi tamamladıktan sonra SDL_GL_SwapBuffers() yordamı ile bu bellek bölgesini gösterme talimatını veriyoruz. Böylelikle görüntü bir seferde grafik kartına yönlendirilerek pencere içine çizilmiş oluyor. Bu yönteme Double Buffering denilir. Peki neden direk grafik kartının belleğini kullanarak çizim yapmıyoruz da, vakit kaybederek önce başka bir belleğe çizip sonra bu belleği grafik kartına aktarıyoruz? Grafik kartları görüntü belleklerini devamli olarak tarayıp bulduğu veriler ile görüntüyü oluştururlar. Eğer siz bir tarama işlemi sırasında görüntü belleği üzerinde oynamalar yaparsanız ekrana çıkan görüntü üzerinde çeşitli tutarsızlıklar oluşur. Bu tutarsızlıklar titreme biçiminde kullanıcıya yansır ve hiçde güzel bir görünüm oluşturmazlar. Yani siz siz olun bu tekniği kullanın, inanın zararını görmessiniz :)

Yordamımızı yazdık. Şimdi tek iş bu yordamı ana döngümüz içerisinden devamlı olarak çağırmakta. Hatırlarsanız daha önce devamlı olarak görüntüyü tazelememiz gerektiğinden bahsetmiştik. Bunu gerçekleştirmenin en kolay yolu ana while döngüsü içinde renderScene() yordamını çağırmak. Aşağıda main() yordamının bu ufak ekleme ile oluşturulmuş son hali bulunmakta. Programı çalıştırdığınız zaman artık siyah bir zemine sahip küçük penceremizi izleyebileceksiniz...

int main(int argc,char *argv[]) {

   bool quit = false;

   initSDL(640,480,16);
   setupOpenGL(640,480);
    
   while (!quit) {

      // devamli olarak ekran üzerinde çizim işlemi gerçekleştiriyoruz

      renderScene();
      
      SDL_Event event;

      while (SDL_PollEvent(&event)) {

         switch (event.type) {
            case SDL_KEYDOWN:
               
               switch (event.key.keysym.sym) {
                  case SDLK_ESCAPE:
                     quit = true;
                     break;
               }
               break;

            case SDL_QUIT:
               quit = true;

         }
      }

   }
   
    return 0;
}



Oyun yapımı ile ilgili bu döküman serisinin ilk bölümü için sanırım bu kadar yazı yeterli olacaktır. Bu ilk bölümde SDL kütüphanesinden Windows altında VC++ kullanarak yararlanmak için gerekli olan ayarlamaları öğrendik. Daha sonra SDL kütüphanesini ve OpenGL i başlatmayı, ana program döngüsünü, klavyeden tuşa basılmaları almayı (bu konu daha sonra ayrıntılı olarak işlenecektir) , ve ekranda pencere ile görüntü oluşturmayı gördük. Önümüzdeki derslerde çizim işlemine geçecek ve oyun projemizin ilk sınıflarını tasarlama ve kodlamaya başlayacağız. Son olarak şunu söylemek istiyorum. Lütfen bu yazı ile ilgili görüş, eleştiri ve düzeltmelerinizi bize sitemizdeki sistem aracılığı ile ulaştırın. Böylelikle ilerki yazılarda daha faydalı ve düzgün içerikler oluşturabilirim. Aynı zamanda anlamadığınız ya da size karışık gelen noktaları sitemizdeki forumlar aracılığı ile biz ve sitemizin diğer üyeleri ile paylaşabilirsiniz. Kendinize iyi bakın, kodlamak ve araştırmaktan uzak kalmayın :) ...

5. Tüm Kaynak Kod:

// main.cpp

// *****************************************
//
// Oyun Yapimi Dersleri [www.oyunyapimi.org]
//
// Deniz Aydinoglu :: 2002 ::
//
// deniz@oyunyapimi.org
//
// *****************************************

#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif

#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <gl/glut.h>
#include <sdl/sdl.h>

#include <stdio.h>
#include <stdlib.h>

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!\n%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,4,4000);
   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);
      
   // 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);

      
   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;
               }
               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;
}
Deniz Aydınoğlu :: 2002





Bu yazının bulunduğu site: OyunYapimi.org
http://www.oyunyapimi.org

Bu yazı için adres:
http://www.oyunyapimi.org/modules.php?name=Sections&op=viewarticle&artid=2