2.1 SystemCore - Application

2.1 SystemCore - Application

Думаю из названия понятно, что в этом уроке будет рассматриваться системное ядро, а конкретнее его составляющая - приложение.
[spoiler]
В этом уроке начнем писать движок и разработаем класс приложения.

Писать все я буду в своем любимом Code::Blocks 10.05

(сейчас будет пояснение о том как сделать все с самих азов, позже сделаю урок по разным IDE)

2.1.1 Подготовка

И так запускаем IDE, создаем новый проект (там есть кнопочка Create New Project), выбираем Empty project, потом next, указываем название проекту (я указал New_Engine_v0.1), указываем компилятор - GNU GCC Compiler и жмем Finish.

этот двиг почему то я назвал FEngine, называйте как хотите, я выбрал такое название

Теперь надо создать следующие файлы - main.cpp FEngine.h SystemCore.h cApplication.cpp cApplication.h Public.h Public.cpp

main.cpp - в этом файле будем тестировать наш движок

FEngine.h - этот файл у меня содержит линковку всех библиотек, всех ядер и других фалов

SystemCore.h - этот файл линкует все составляющие системного ядра

cApplication.h
cApplication.cpp
- эти файлы содержат класс для работы приложения

Public.h
Public.cpp
- этот файл я сделал для того что бы ложить туда разные переменные которые не относятся к какому либо классу и они требуются для работы юзера



2.1.2 Разбираемся и пишем код

И так, в main.cpp нам нужно написать только

/*http://esate.ru, isaer*/

#include "FEngine.h" //линкуем наш диг

using namespace FEngine; //используем пространство имен нашего движка

int main()//эээ..всем ясно =))
{
}


Тут все предельно просто

дальше пишем FEngine.h

/*http://esate.ru, isaer*/

#ifndef ENGINE_H //это сделано для того что бы имена не повторялись
#define ENGINE_H

#include <GL/gl.h> //линки библиотек с которыми мы будем работать
#include <GL/glu.h> //..
#include <SDL/SDL.h> //..

#include "Public.h" //линкем наш файл с переменными

#include "SystemCore.h" //линкуем наше системное ядро

#endif


все предельно просто =)

теперь SystemCore.h
/*http://esate.ru, isaer*/


#ifndef SYSTEMCORE_H
#define SYSTEMCORE_H

//все тоже самое
#include "FEngine.h"
#include "cApplication.h"

#endif


кто то может сказать что я делаю лишнее создавая отдельные файлы для каждого ядра, но блин и классы ведь все можно в одном файле записать, по моему так красивее будет, и удобнее


в Public.h и Public.cpp сейчас лежит только переменная хранящая в себе клавиши, но не все, все было лень писать, вы и сами сможете дописать остальные.

Public.h
/*http://esate.ru, isaer*/


//тут тоже все предельно просто
#ifndef PUBLIC_H
#define PUBLIC_H

#include "FEngine.h"

namespace systemCore //указываем в какому пространству имен принадлежит все что ниже
{

enum keydown { //создаем перечисление keydown в котором хранятся названия клавиш
//так сказать сделали свою переменную
   EK0, EK_1, EK_2, EK_3, EK_4, EK_5, EK_6, EK_7, EK_8, EK_9, EK_0,

   EK_F1, EK_F2, EK_F3, EK_F4, EK_F5, EK_F6, EK_F7, EK_F8, EK_F9, EK_F10, EK_F11, EK_F12,

   EK_CAPSLOCK, EK_SPACE, EK_ESCAPE,

   EK_Q, EK_W, EK_E, EK_R, EK_T, EK_Y, EK_U, EK_I, EK_O, EK_P, EK_A, EK_S, EK_D,
      EK_F, EK_G, EK_H, EK_J, EK_K, EK_L, EK_Z, EK_X, EK_C, EK_V, EK_B, EK_N, EK_M, null
   };
extern keydown KeyDown; //делаем глобальной переменную KeyDown

};

#endif


Public.cpp

/*http://esate.ru, isaer*/

#include "Public.h"

namespace systemCore
{

keydown         KeyDown; //указываем что переменная KeyDown имеет тип keydown
//позже мы сможем смотреть какая клавиша нажата через переменную KeyDown

};



Ну вот и подошли мы к тому что будем писать класс приложения.

Заходим в файл cApplication.h ну и пишем:

/*http://esate.ru, isaer*/

#ifndef APPLICATION_H //все как обычно
#define APPLICATION_H

#include "SystemCore.h"

namespace systemCore
{

enum state_cursore {SHOW, HIDE}; //этот тип хранит скрыть или показать, 
//позже пригодится

class cApplication //создаем класс
{
public:
   cApplication();//конструктор
   ~cApplication();//деструктор
};

};
#endif


но это как вы поняли это еще не весь код =))
будем ити медленно
что нам нужно сначала написать?
конечно переменные, какие переменные нам понадобятся?

/*http://esate.ru, isaer*/


public:
   bool Runing; //если true то приложение работает

private:
   int Width; //ширина приложения
   int Height; // высота приложения
   int BPP; // это показывает какое количество цветов будет 32 или 16

   bool Fullscreen; //полноэкранный режим или нет

   char* Caption; //название окна
   SDL_Surface* Icon; //иконка

   SDL_Surface* Surface; //это область окна
   SDL_Event   Event; //это переменная событий


думаю все ясно =)


в спп файле пишем следующее:

/*http://esate.ru, isaer*/

cApplication::cApplication()
{
   Runing          = true;

   Fullscreen       = false;

   Caption         = "FEngine";
   Icon           = NULL;

   Surface         = NULL;
}

cApplication::~cApplication()
{
}


тут мы просто указываем какие значения должны быть когда программа запустится

теперь будем писать методы, все методы у нас публичные

и так нам в начале главным образом надо вот эти 4 метода:

/*http://esate.ru, isaer*/

bool Init();//в принципе тут тоже самое что и в конструкторе
bool Run();//тут будет обработка клавиш и проверка на выход из программы
bool Reset();//этим мы будем перезагружать программу, например изменив некоторые 
//параметры запустив этот метод они будут применены, вы  наверное выдели такое в 
//настройках какой нить игры, там есть такая кнопочка применить, после нажатия все 
//параметры которые вы ставили применяются
void Shutdown()//метод завершения программы
;

реализуем эти методы(cApplication.cpp):

/*http://esate.ru, isaer*/

bool cApplication::Init()
{
   bool Runing         = true;

   bool Fullscreen       = false;

   Caption            = "FEngine";
   SDL_Surface* Icon     = NULL;

   SDL_Surface* Surface   = NULL;
}

bool cApplication::Reset()
{
   SDL_WM_SetCaption(Caption, NULL);
   SDL_WM_SetIcon(Icon, NULL);

   if(Fullscreen == true)
   {
      if((Surface = SDL_SetVideoMode(Width, Height, BPP, SDL_OPENGL | SDL_FULLSCREEN)) == NULL)
        return false;
   }
   else
   {
      if((Surface = SDL_SetVideoMode(Width, Height, BPP, SDL_OPENGL)) == NULL)
        return false;
   }
}

void cApplication::Shutdown()
{
   SDL_Quit();
   delete this;
}


Я думаю тут пояснять ничего не надо, и так все понятно из кода

а теперь метод Run

/*http://esate.ru, isaer*/

bool cApplication::Run()
{
   SDL_PollEvent(&Event);//тут мы обрабатываем события

   KeyDown = null; //устанавливаем что не нажата никакая клавиша

   switch(Event.type) //смотрим какие события сейчас происходят
   {
      case SDL_QUIT: {return false;}break; //события закрытия программы, как 
//только оно то мы сразу завершаем работу

      case SDL_KEYDOWN: //нажатие клавиш
      {
        switch(Event.key.keysym.sym) //смотрим какая клавиша нажата
        {//если нажата клавиша то мы переменной KeyDown передаем эту клавишу
//в итоге у нас переменная KeyDown хранит нажатую клавишу
           case SDLK_0:        KeyDown = EK_0;         break;
           case SDLK_1:        KeyDown = EK_1;         break;
           case SDLK_2:        KeyDown = EK_2;         break;
           case SDLK_3:        KeyDown = EK_3;         break;
           case SDLK_4:        KeyDown = EK_4;         break;
           case SDLK_5:        KeyDown = EK_5;         break;
           case SDLK_6:        KeyDown = EK_6;         break;
           case SDLK_7:        KeyDown = EK_7;         break;
           case SDLK_8:        KeyDown = EK_8;         break;
           case SDLK_9:        KeyDown = EK_9;         break;

           case SDLK_F1:        KeyDown = EK_F1;        break;
           case SDLK_F2:        KeyDown = EK_F2;        break;
           case SDLK_F3:        KeyDown = EK_F3;        break;
           case SDLK_F4:        KeyDown = EK_F4;        break;
           case SDLK_F5:        KeyDown = EK_F5;        break;
           case SDLK_F6:        KeyDown = EK_F6;        break;
           case SDLK_F7:        KeyDown = EK_F7;        break;
           case SDLK_F8:        KeyDown = EK_F8;        break;
           case SDLK_F9:        KeyDown = EK_F9;        break;
           case SDLK_F10:       KeyDown = EK_F10;        break;
           case SDLK_F11:       KeyDown = EK_F11;        break;
           case SDLK_F12:       KeyDown = EK_F12;        break;

           case SDLK_CAPSLOCK:    KeyDown = EK_CAPSLOCK;    break;
           case SDLK_SPACE:      KeyDown = EK_SPACE;       break;
           case SDLK_ESCAPE:     KeyDown = EK_ESCAPE;      break;

           case SDLK_q:        KeyDown = EK_Q;         break;
           case SDLK_w:        KeyDown = EK_W;         break;
           case SDLK_e:        KeyDown = EK_E;         break;
           case SDLK_r:        KeyDown = EK_R;         break;
           case SDLK_t:        KeyDown = EK_T;         break;
           case SDLK_y:        KeyDown = EK_Y;         break;
           case SDLK_u:        KeyDown = EK_U;         break;
           case SDLK_i:        KeyDown = EK_I;         break;
           case SDLK_o:        KeyDown = EK_O;         break;
           case SDLK_p:        KeyDown = EK_P;         break;
           case SDLK_a:        KeyDown = EK_A;         break;
           case SDLK_s:        KeyDown = EK_S;         break;
           case SDLK_d:        KeyDown = EK_D;         break;
           case SDLK_f:        KeyDown = EK_F;         break;
           case SDLK_g:        KeyDown = EK_G;         break;
           case SDLK_h:        KeyDown = EK_H;         break;
           case SDLK_j:        KeyDown = EK_J;         break;
           case SDLK_k:        KeyDown = EK_K;         break;
           case SDLK_l:        KeyDown = EK_L;         break;
           case SDLK_z:        KeyDown = EK_Z;         break;
           case SDLK_x:        KeyDown = EK_X;         break;
           case SDLK_c:        KeyDown = EK_C;         break;
           case SDLK_v:        KeyDown = EK_V;         break;
           case SDLK_b:        KeyDown = EK_B;         break;
           case SDLK_n:        KeyDown = EK_N;         break;
           case SDLK_m:        KeyDown = EK_M;         break;
        }
      }break;
   }

   if(Runing){ return true;} else{ return false}; //смотрим, если программа работает то возвращаем true иначе false 
}


как видите ничего сложного

теперь разберем эти методы:

/*http://esate.ru, isaer*/

   void SetCaption(char* caption);//вызываем этот метод и указываем 
//какое название будет у окна
   void SetIcon(SDL_Surface* icon); //указываем иконку

   void SetSizeWindow(int width, int height); //указываем размер
   void SetBPP(int bpp); //указываем BPP

   void Cursor(state_cursore state); //можем скрыть или показать курсор
//если передать этому методу HIDE то курсор будет скрыт а если SHOW то показан

   void ToggleFullscreenMode(); //вызываем когда хотим перейти в широкоэкранный
   void ToggleWindowMode();
//оконный режим


реализуем эти методы:

тут все очень просто, мы просто глобальным переменным передаем переданные значения

/*http://esate.ru, isaer*/

void cApplication::SetCaption(char* caption)
{
   Caption = caption;
}

void cApplication::SetIcon(SDL_Surface* icon)
{
   Icon = icon;
}

void cApplication::SetSizeWindow(int width, int height)
{
   Width     = width;
   Height    = height;
}

void cApplication::SetBPP(int bpp)
{
   BPP = bpp;
}

void cApplication::Cursor(state_cursore state)
{
   if(state == SHOW)
      SDL_ShowCursor(SDL_ENABLE);
   else if(state == HIDE)
      SDL_ShowCursor(SDL_DISABLE);
}

void cApplication::ToggleFullscreenMode()
{
   Fullscreen = true;
}

void cApplication::ToggleWindowMode()
{
   Fullscreen = false;
}


ну и наконец то последний метод это метод создания окна:

/*http://esate.ru, isaer*/

bool CreateWindow(int width, int height, int bpp);


и его реализация:

/*http://esate.ru, isaer*/

bool cApplication::CreateWindow(int width, int height, int bpp)
{
   Width    = width;
   Height   = height;
   BPP     = bpp;

   if(SDL_Init(SDL_INIT_VIDEO) < 0)
      return false;

   SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,   1);

   SDL_WM_SetCaption(Caption, NULL);
   if(Fullscreen == true)
   {
      if((Surface = SDL_SetVideoMode(Width, Height, BPP, SDL_OPENGL | SDL_FULLSCREEN)) == NULL)
        return false;
   }
   else
   {
      if((Surface = SDL_SetVideoMode(Width, Height, BPP, SDL_OPENGL)) == NULL)
        return false;
   }
}


тут все очень просто так что я думаю объяснять не нужно




2.1.3 Итоги
Теперь вы можете в main.cpp
создать приложение очень малым количеством строк, вот пример:


/*http://esate.ru, isaer*/

#include "FEngine.h"

using namespace systemCore;

cApplication* app = new cApplication();

void Keydown()
{
   switch(KeyDown)
   {
      case EK_ESCAPE:
      {
        app->Runing = false;
      }break;
   }
}

int main()
{
   app->Init();

   app->CreateWindow(800, 600, 32);

   while(app->Run())
   {
      Keydown();
   }

   app->Shutdown();
}


как видите приложение работает нормально, при нажатии на Esc приложение закрывается

на этом урок закончен, надеюсь он вам помог хоть чем нубуть
0       1777        03.02.2011        5

0  
03.02.2011 00:00:00
а я думал на с# будет код)
0  
03.02.2011 00:00:00
но все равно) хороший урок)
0  
03.02.2011 00:00:00
я шарп плохо знаю, но там я понимаю тоже самое, немного изенить придется, главное это сделать ПУСТОЕ приложение
0  
13.02.2011 00:00:00
Отличный урок!!! Я из него почерпнул много интересного. =)
SDL правда для меня загадка.((
0  
14.02.2011 00:00:00
рад помоч =))
^