Как стать автором
Обновить

Уроки по SDL 2: Урок 3 — События

Время на прочтение5 мин
Количество просмотров13K
Всем привет! Это третий урок по SDL 2. Информация берется из этого источника. Уроки по обработке событий на Lasy Foo' мне не понравились, так что я напишу свой, но материал можно найти здесь и здесь.

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

События


Сегодня научим нашу программу реагировать на события с помощью Джона.

Итак, начнем. подключаем SDL 2 и создаем 3 глобальных переменных и 2 константы.

#include <SDL2/SDL.h>

const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

SDL_Window *win = NULL;
SDL_Surface *scr = NULL;
SDL_Surface *john = NULL;

Далее пишем 3, уже известные и прошлого урока, функции:

Init
int init() {
    if (SDL_Init(SDL_INIT_VIDEO) != 0) {
        std::cout << "Can't init: " << SDL_GetError() << std::endl;
        system("pause");
        return 1;
    }

    win = SDL_CreateWindow("События", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
    if (win == NULL) {
        std::cout << "Can't create window: " << SDL_GetError() << std::endl;
        system("pause");
        return 1;
    }

    scr = SDL_GetWindowSurface(win);

    return 0;
}

Load
int load() {
    john = SDL_LoadBMP("john.bmp");

    if (john == NULL) {
        std::cout << "Can't load image: " << SDL_GetError() << std::endl;
        system("pause");
        return 1;
    }

    return 0;
}

Quit
int quit() {
    SDL_FreeSurface(john);
    
    SDL_DestroyWindow(win);

    SDL_Quit();

    return 0;
}


Внимание(!), если вы копируете код из предыдущего урока, не забудьте smile поменять на john.

Все, что следует сказать: я решил показывать ошибки на этапе инициализации и загрузки изображения.

Итак, продолжим. открываем main и вызываем функции Init и Load.

int main (int argc, char ** args) {
    if (init() == 1) {
        return 1;
        
    }

    if (load() == 1) {
        return 1;
    }
}

Теперь разберем, как устроено любое приложение. Любая программа, которую вы запускаете(Google Chrome, Paint, Minecraft), имеет главный цикл, выполняющийся огромное количество раз. Это нужно для динамичности. Раньше мы писали программу, которая просто 2 секунды показывала смайла, но для того, чтобы программа могла научится отвечать на действия пользователя (или хотя бы бесконечно показывать изображение), ей нужен цикл While.

Он будет постоянно повторяться и в нем мы сможем уже делать, что захотим, например обрабатывать события. Но перед тем, как запускать гланый цикл, создадим несколько переменных.

    bool run = true;
    SDL_Event e;
    SDL_Rect r;

    int x = 0;
    int y = 0;

    r.x = x;
    r.y = y;

Сечас все разберем. Первым делом создаем переменную run типа boolean. Эта переменная отвечает за выполнение цикла: пока программа выполняется, она равна значению true, если же мы хотим остановить выполнение, то присваем этой переменной значание false. Далее создаем объект e класса SDL_Event. В свойствах этого объекта будут находится данные полученного события, дальше будет подробнее. После этого создаем объект r класса SDL_Rect. Это прямоугольник, требуемый для отрисовки объекта с какими-то нужными нам координатами. Затем создаем переменные x и y типа int. Сразу же присваиваем их значания нулю. Это будут координаты нашего персонажа. Следующим пунктом мыприсваиваем переменным r.x и r.y значения x и y соответственно. r.x и r.y — координаты прямоугольника r.

Пришло время к открытию главного цикла.

    while (run) {
        while(SDL_PollEvent(&e) != 0) {
            if (e.type == SDL_QUIT) {
                run = false;
            }

            if (e.type == SDL_KEYDOWN) {
                if (e.key.keysym.sym == SDLK_UP) {
                    y -= 1;
                }
                if (e.key.keysym.sym == SDLK_DOWN) {
                    y += 1;
                }
                if (e.key.keysym.sym == SDLK_RIGHT) {
                    x += 1;
                }
                if (e.key.keysym.sym == SDLK_LEFT) {
                    x -= 1;
                }
            }
        }
        r.x = x;
        r.y = y;

        SDL_FillRect(scr, NULL, SDL_MapRGB(scr -> format, 255, 255, 255));

        SDL_BlitSurface(john, NULL, scr, &r);

        SDL_UpdateWindowSurface(win);
    }

Давайте разберем этот код. У нас есть два цикла. Первый основной — главный, который работает засчет переменной run, как было сказано ранее. Второй цикл отвечает за обработку событий.

Функция SDL_PollEvent() открывает очередь событий, полученных за одно выполнение главного цикла, удаляет последнее событие и записывает данные об этом событии в переменные объекта, которого мы передали в эту функцию, у нас это e. Эта функция возвращает 0, NULL или false, если все события из очереди были удалены, так что мы пишем условие while(SDL_PollEvent(&e) != NULL).

Смотрим дальше: первая проверка у нас идет на нажатие крестика в рамке окна. Если мы его нажимаем, то переменной type объекта e присваивается значение SDL_QUIT. Если это произошло, то переменной run мы присваеиваем false и цикл заканчивается.

Далее я написал проверку на нажатие клавиш клавиатуры. Если кнопка нажата, то переменная e.type равна SDL_KEYDOWN. Дальше проверяем значения клавиш. в переменной e.key.keysym.sym хранится значание кнопки. Мы сравниваем это значение с нужным и выполняем те или иные действия. У нас будет меняться координата Джона. Если нажата стрелка вверх, то y уменьшается на 1, если вниз, то увеличивается и т. д. Суть, я думаю, вы поняли.

После обработки событий переприсваиваем r.x и r.y, чтобы обновить координаты Человечка. Дальше пишем уже знакомую функцию SDL_FilRect, у нее очень больша роль. Если бы мы её не написали, то при движении Джон оставлял бы некрасивый след, а так, каждый кадр мы зарисовываем белым цветом фон и рисуем поверх него спрайт. После этого мы рисуем нашего героя функцией SDL_BlitSurface. Здесь-то мы и воспользуемся нашим прямоугольником r, точнее его переменными x и y, чтобы рисовать не просто слева вверху, а с какими-то нужными координатами. Дальше просто обновляем окно.

После главного цикла пишем return quit();, чтобы завершить программу.

Вот и всё, этот урок закончился. Вот такой вот вышел код:

Код
#include <SDL2/SDL.h>
#include <iostream>

const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

SDL_Window *win = NULL;
SDL_Surface *scr = NULL;
SDL_Surface *john = NULL;

int init() {
    if (SDL_Init(SDL_INIT_VIDEO) != 0) {
        std::cout << "Can't init: " << SDL_GetError() << std::endl;
        system("pause");
        return 1;
    }

    win = SDL_CreateWindow("События", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
    if (win == NULL) {
        std::cout << "Can't create window: " << SDL_GetError() << std::endl;
        system("pause");
        return 1;
    }

    scr = SDL_GetWindowSurface(win);

    return 0;
}

int load() {
    john = SDL_LoadBMP("john.bmp");

    if (john == NULL) {
        std::cout << "Can't load image: " << SDL_GetError() << std::endl;
        system("pause");
        return 1;
    }

    return 0;
}

int quit() {
    SDL_FreeSurface(john);
    
    SDL_DestroyWindow(win);

    SDL_Quit();

    return 0;
}
int main (int argc, char ** args) {
    if (init() == 1) {
        return 1;
        
    }

    if (load() == 1) {
        return 1;
    }

    bool run = true;
    SDL_Event e;
    SDL_Rect r;

    int x = 0;
    int y = 0;

    r.x = x;
    r.y = y;

    while (run) {
        while(SDL_PollEvent(&e) != NULL) {
            if (e.type == SDL_QUIT) {
                run = false;
            }

            if (e.type == SDL_KEYDOWN) {
                if (e.key.keysym.sym == SDLK_UP) {
                    y -= 1;
                }
                if (e.key.keysym.sym == SDLK_DOWN) {
                    y += 1;
                }
                if (e.key.keysym.sym == SDLK_RIGHT) {
                    x += 1;
                }
                if (e.key.keysym.sym == SDLK_LEFT) {
                    x -= 1;
                }
            }
        }
        r.x = x;
        r.y = y;

        SDL_FillRect(scr, NULL, SDL_MapRGB(scr -> format, 255, 255, 255));

        SDL_BlitSurface(john, NULL, scr, &r);

        SDL_UpdateWindowSurface(win);
    }

    return quit();
}


А я с вами прощаюсь, всем пока!

<< Предыдущий урок || Следущий урок >>
Теги:
Хабы:
Всего голосов 4: ↑4 и ↓0+4
Комментарии5

Публикации

Истории

Работа

QT разработчик
8 вакансий
Программист C++
136 вакансий

Ближайшие события