Пятница, 26.04.2024, 09:31
PIXELCODEПриветствую Вас Гость | RSS
Главная | Каталог статей | Регистрация | Вход
Меню сайта

Категории раздела
SDL и C/C++ [6]

Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

Форма входа

Главная » Статьи » SDL и C/C++

Уроки SDL - основы
   Здравствуйте! С этой первой статьи начинаю публиковать переведенные на русский язык замечательные статьи Тима Джонса (Tim Jones), размещенные им на сайте http://www.sdltutorials.com.
   Сразу скажу, что тем из вас, кто хоть немного читает по-английски необходимо читать эти статьи в оригинале. Причины тут минимум две: я могу по незнанию или по невнимательности что-нибудь переврать (хотя стараюсь, конечно, передать материал качественно и полно), а вторая: вы сможете получить ответ автора на возникшие у вас вопросы по статье и скачать исходные коды к ним.
   Так-же обращаюсь ко всем читателям: если материал уроков вам нравится, прошу оказать безвозмездную помощь автору проекта SDL Tutorials Тиму Джонсу - там есть кнопочка Donations. Это поможет ему в его нелегком деле - написании для нас новых туторов.
   Оригинал статьи здесь: SDL Tutorial Basics. Итак, начнем =)

   Что нужно иметь: желательно иметь среду разработки (т.н. IDE) подойдет любая, например Code::Blocks или NetBeans; настроить Вашу IDE для компиляции под нужные платформы, т.е. настроить компиляторы, скачать и подключить SDL для Ваших целей компиляции. В этой статье подготовительные вопросы не рассматриваются, они неплохо освещены в Интернете (на этом сайте кое-что есть. Прим. переводчика).
   Для начала создадим главный класс — класс приложения CApp. Для этого создадим 2 файла: CApp.h следующего содержания:

#ifndef _CAPP_H_
    #define _CAPP_H_
#include <SDL.h>
class CApp {
    public:
        CApp();
        int OnExecute();
};
#endif


и CApp.cpp:

#include "CApp.h"
CApp::CApp() {
}
int CApp::OnExecute() {
    return 0;
}
int main(int argc, char* argv[]) {
    CApp theApp;
    return theApp.OnExecute();
}


Этот класс закладывает основы для всей нашей игры. Здесь нужно сделать небольшое отступление. Любая игра имеет, как правило, 5 функций:

1. Initialization (инициализация)- эта ф-я обрабатывает загрузку таких данных как текстуры, карты, персонажи и др.
2. Events (события)- эта ф-я обрабатывает события мыши, клавиатуры, джойстиков и др.
3. Loop (вычислительный цикл)- эта ф-я  отвечает за просчет текущих игровых данных, перемещение персонажей, уменьшение лайфбара и тому подобное.
4. Render (отображение графики)- эта ф-я занимается именно отображением графики на экране, здесь уже ничего не просчитывается, все расчеты делает ф-я Loop.
5. Cleanup (уборка)- эта ф-я просто освобождает память от загруженных ранее игровых ресурсов и обеспечивает корректный выход из игры.
   Важно понять, что игра - это один гигантский цикл. В этом цикле мы обрабатываем события, просчитываем данные, а также выводим графику. Таким образом, основная структура может  быть представлена как:

Initialize();
while(true) {
    Events();
    Loop();
    Render();
}
Cleanup();


В каждой итерации цикла мы пересчитываем данные, и изменяем картинку соответственно. Так же опрашиваются события, это позволяет пользователю (игроку) работать с данными. Поясним эту мысль на примере: скажем, герой нашей игры - рыцарь. Все, что мы хотим сделать, это просто его переместить, чтобы при нажатии клавиши «влево», он шел влево. Мы должны уяснить, как это сделать в цикле. Во-первых, мы знаем, что нужно проверить наличие события от клавиатуры. При поступлении событий от клавиатуры мы должны соответствующим образом изменить некоторые переменные, тогда мы можем управлять нашим рыцарем на экране. Мы могли бы сделать так:

if(Key == LEFT) X--;
if(Key == RIGHT) X++;
if(Key == UP) Y--;
if(Key == DOWN) Y++;//… еще какой-либо ваш код…
RenderImage(KnightImage, X, Y);


Это работает, потому что каждый цикл происходит проверка клавиш LEFT, RIGHT и т.д., и если хоть одна из них нажата, то происходит уменьшение или увеличение соответствующих координат. Поэтому, если наша игра делает 30 кадров в секунду и  мы нажали LEFT, тогда наш парень будет двигаться влево со скоростью 30 пикселей в секунду. Если вы пока не понимаете, что такое игровой цикл, не расстраивайтесь, вы скоро поймете. Любая игра нуждается в игровом цикле для правильного функционирования.

Возвращаясь к нашей концепции (5 функций), мы можем добавить следующие дополнительные страницы нашего проекта:

CApp_OnInit.cpp
CApp_OnEvent.cpp
CApp_OnLoop.cpp
CApp_OnRender.cpp
CApp_OnCleanup.cpp


Теперь вернемся к файлу CApp.h и добавим в него следующие функции и переменные:

#ifndef _CAPP_H_
    #define _CAPP_H_
#include <SDL.h>
class CApp {
    private:
        bool    Running;
    public:
        CApp();
        int OnExecute();
    public:
        bool OnInit();
        void OnEvent(SDL_Event* Event);
        void OnLoop();
        void OnRender();
        void OnCleanup();
};
#endif

Перейдем к нашим пяти только что созданным файлам и добавим в них следующие функции:

#include "CApp.h"
bool CApp::OnInit() {
    return true;
}

#include "CApp.h"
void CApp::OnEvent(SDL_Event* Event) {
}

#include "CApp.h"
void CApp::OnLoop() {
}

#include "CApp.h"
void CApp::OnRender() {
}

#include "CApp.h"
void CApp::OnCleanup() {
}

Давайте вернемся к нашему код CApp.cpp, чтобы связать все эти функции вместе:

#include "CApp.h"
CApp::CApp() {
    Running = true;
}
int CApp::OnExecute() {
    if(OnInit() == false) {
        return -1;
    }
    SDL_Event Event;
    while(Running) {
        while(SDL_PollEvent(&Event)) {
            OnEvent(&Event);
        }
        OnLoop();
        OnRender();
    }
    OnCleanup();
    return 0;
}
int main(int argc, char* argv[]) {
    CApp theApp;
    return theApp.OnExecute();
}
   
   Вы видите несколько новых переменных, но давайте посмотрим, что происходит в первую очередь. Во-первых, мы стараемся инициализировать нашу игру, если инициализация завершилась неудачей - выходим из нее с кодом -1 (код ошибки). Если все будет хорошо, мы по-прежнему остаемся в игровом цикле. В игровом цикле мы используем SDL_PollEvent для проверки событий и передаем их по одному за раз в функцию OnEvent. После обработки событий, мы переходим к OnLoop для пересчета данных, затем для отображения игрового экрана. Мы повторяем, этот цикл бесконечно. Если пользователь выходит из игры, то приступаем к очистке OnCleanup игровых ресурсов. Довольно просто.
   Теперь, давайте обратим внимание на SDL_Event и SDL_PollEvent. Первый является структурой, которая содержит информацию о событиях. Вторая - функция, которая будет захватывать любые события в очереди. Эта очередь может иметь любое количество событий, это и является причиной, почему мы делаем это в цикле. Так, например, пользователь нажимает и перемещает мышь во время работы функции OnRender(). SDL обнаружит это и поместит два события в очередь, одно - от нажатия клавиши и одно от перемещения мыши. Мы можем взять эти события из очереди с помощью SDL_PollEvent, а затем добавить его в OnEvent и обработать соответствующим образом. Если события в очереди закончились, SDL_PollEvent вернет false, что приведет к выход из цикла вызова  функции OnEvent.
   Другая добавленная переменная, Runing, является нашей собственной. Это наш выход из игрового цикла. Когда она установлена в false, она приводит к завершению
программы, и к выходу из нее. Так, например, мы можем утановить эту переменную в false, если пользователь нажимает на кнопку Escape, и таким образом инициировать выход из игры.
   Теперь вы можете скомпилировать свой проект, все как бы отлично, но вы не сможете выйти из программы. Скорее всего, придется использовать Системный монитор (в Linux) или Task Manager (в Windows)  для ее завершения.
            
   Сейчас, когда все настроено, давайте начнем с создания окна нашей игры. Прейдем к CApp.h и добавим переменную SDL поверхности  в код:

#ifndef _CAPP_H_
    #define _CAPP_H_
#include <SDL.h>
class CApp {
    private:
        bool  Running;
        SDL_Surface*  Surf_Display;
    public:
        CApp();
        int OnExecute();
    public:
        bool OnInit();
        void OnEvent(SDL_Event* Event);
        void OnLoop();
        void OnRender();
        void OnCleanup();
};
#endif

Теперь, давайте перейдем к файлу CApp_OnInit чтобы создать эту SDL  поверхность:

#include "CApp.h"
bool CApp::OnInit() {
    if(SDL_Init(SDL_INIT_EVERYTHING) < 0) {
        return false;
    }
    if((Surf_Display = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE | SDL_DOUBLEBUF)) == NULL) {
        return false;
    }
    return true;
}

   Сначала инициализируем сам SDL, чтобы иметь доступ к его функциям. Мы вызываем Функцию SDL_Init для того, чтобы инициализировать все подсистемы SDL. Понимание остальных, опущенных здесь параметров этой функции на данном этапе не существенно.
   Следующая функция, которую мы применили – SDL_SetVideoMode. В данном случае она создает нам окно приложения и саму SDL-поверхность Surf_display. У этой функции 4 параметра: ширина окна (пикс.), высота окна (пикс.), бит-на-пиксель (кол-во бит) – рекомендуются значения 16 или 32, затем флаги отображения (на самом деле это все один флаг, собранный из двух оператором ||). Мы использовали SDL_HWSURFACE – по возможности использовать для хранения нашей поверхности память видеоадаптера (это быстрее, чем SDL_SWSURFACE), следующий флаг SDL_DOUBLEBUF – использовать двойную буферизацию, что позволяет избежать мерцания экрана при его обновлении. Есть еще флаг, который может показаться вам полезным: SDL_FULLSCREEN  - он дает команду перейти SDL в полноэкранный режим.

    Теперь, когда SDL инициализирована и настроено окно отображения с основной поверхностью, давайте сразу опишем функцию удаления этой поверхности при выходе. Откроем CApp_OnCleanup.cpp и добавим следующее:

#include "CApp.h"
void CApp::OnCleanup() {
    SDL_FreeSurface(Surf_Display);
    SDL_Quit();
}

   Попробуйте скомпилировать код, и понаблюдайте за его работой. Вы должны получить чистое черное окно размером 640х480.

   Ну вот, у нас есть окно, давайте сделаем так, чтобы мы смогли его закрыть когда оно нам надоест.
Откройте файл CApp_OnEvent.cpp, добавить следующее:

#include "CApp.h"
void CApp::OnEvent(SDL_Event* Event) {
    if(Event->type == SDL_QUIT) {
        Running = false;
    }
}

   SDL рассматривает события по их типам. Эти типы могут варьироваться: нажатия клавиш, перемещения мыши и др. То, что мы делаем здесь – простая проверка типа события. Тип события, который мы ищем – запрос на закрытие окна (например, когда пользователь нажимает «крестик» – закрыть окно). Если это событие произойдет, мы присваиваем переменной Running значение false, тем самым завершая нашу программу. Все просто. Мы рассмотрим работу с событиями (Events) более подробно и расширенно в следующих уроках.
   Теперь у нас есть все начальные установки, и хорошая основа для работы в дальнейшем. Хорошая идея – сделать из этой заготовки шаблон в вашей IDE под названием SDL Application. В следующем уроке мы рассмотрим координатную систему SDL и блиттинг поверхностей на экран.

   Все права на статью и исходный код в ней принадлежат Tim Jones by sdltutorials.com.

   Следующая статья: SDL - система координат и блиттинг.
Категория: SDL и C/C++ | Добавил: J3d1 (30.11.2010)
Просмотров: 8331 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Поиск

Друзья сайта
  • Все для веб-мастера
  • Программы для всех
  • Мир развлечений
  • Лучшие сайты Рунета

  • Copyright MyCorp © 2024 Создать бесплатный сайт с uCoz