Многие из предыдущих руководств по SDL2 были посвящены работе с изображениями. В этой статье мы собираемся поднять это на следующий уровень, используя очень простую технику, чтобы оживить наши изображения и сделать их более живыми.
Наши настройки проекта для этой статьи такие же, как в « Загрузка изображений в SDL2 с помощью SDL_image », и фактически наш стартовый код адаптирован из этой статьи:
#include <SDL.h>
#include <SDL_image.h>
int main(int argc, char ** argv)
{
bool quit = false;
SDL_Event event;
SDL_Init(SDL_INIT_VIDEO);
IMG_Init(IMG_INIT_PNG);
SDL_Window * window = SDL_CreateWindow("SDL2 Sprite Sheets",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
SDL_Surface * image = IMG_Load("spritesheet.png");
SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, image);
while (!quit)
{
SDL_WaitEvent(&event);
switch (event.type)
{
case SDL_QUIT:
quit = true;
break;
}
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
}
SDL_DestroyTexture(texture);
SDL_FreeSurface(image);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
IMG_Quit();
SDL_Quit();
return 0;
}
Это изображение 128 пикселей в ширину и 64 пикселей в высоту. Он состоит из 4 подизображений (называемых спрайтами или кадрами ), каждое из которых имеет ширину 32 пикселя. Если мы сможем быстро рендерить каждое изображение, как мультфильм, то у нас есть анимация!
Теперь эти уродливые границы на изображении выше только для демонстрационных целей Вот то же изображение, без границ и с прозрачностью:
Если мы сейчас попытаемся нарисовать выше на черном фоне по умолчанию, мы ничего не увидим, не так ли? К счастью, легко изменить цвет фона, и мы делали это раньше в разделе « Обработка событий клавиатуры и мыши в SDL2 ». Просто добавьте следующие две строки перед while
циклом:
SDL_SetRenderDrawColor(renderer, 168, 230, 255, 255);
SDL_RenderClear(renderer);
Теперь мы посмотрим, как будет выглядеть вывод. Нажмите Ctrl + Shift + B, чтобы построить проект, а затем скопируйте SDL2.dll , все библиотеки DLL SDL_image и таблицу спрайтов в папку Debug, где создается исполняемый файл.
Как только это будет сделано, нажмите F5:
Итак, на данный момент есть две проблемы, которые мы хотим решить. Во-первых, мы не хотим, чтобы наше изображение занимало все окно, как это делается выше. Во-вторых, мы хотим рисовать только один спрайт за раз. И то, и другое довольно легко решить, если вы помните последние два параметра SDL_RenderCopy () : исходный прямоугольник (для рисования только части изображения) и целевой прямоугольник (для рисования изображения только в части экрана) ,
Итак, давайте добавим следующее в начале while
цикла:
SDL_Rect srcrect = { 0, 0, 32, 64 };
SDL_Rect dstrect = { 10, 10, 32, 64 };
… А затем обновите наш вызов SDL_RenderCopy () следующим образом:
SDL_RenderCopy(renderer, texture, &srcrect, &dstrect);
Обратите внимание , что синтаксис мы используем для инициализации нашего SDL_Rect s только обсчитывать , чтобы установить все x
, y
, w
(ширина) и h
(высота) члены все сразу.
Давайте снова запустим программу и посмотрим, как она выглядит:
Итак, вот так мы просто визуализируем первый спрайт для части окна. Теперь давайте поработаем над анимацией. В начале while
цикла добавьте следующее:
Uint32 ticks = SDL_GetTicks();
SDL_GetTicks () дает нам количество миллисекунд, прошедших с момента запуска программы. Благодаря этому мы можем использовать текущее время при расчете, какой спрайт использовать. Затем мы можем просто разделить на 1000, чтобы преобразовать миллисекунды в секунды:
Затем мы делим секунды на количество спрайтов в нашей таблице спрайтов, в данном случае 4. Использование оператора модуля гарантирует, что число спрайтов будет округлено, поэтому оно никогда не будет больше 3 (помните, что подсчет всегда начинается с нуля, поэтому наш спрайты пронумерованы от 0 до 3).
Uint32 sprite = seconds % 4;
Наконец, мы заменяем нашу srcrect
декларацию следующим:
SDL_Rect srcrect = { sprite * 32, 0, 32, 64 };
Вместо использования x
нулевого значения, как мы делали раньше, мы передаем sprite
значение (от 0 до 3, основанное на текущем времени), умноженное на 32 (ширина одного спрайта). Таким образом, с каждой прошедшей секундой спрайт будет извлечен из изображения при x = 0, затем x = 32, затем x = 64, затем x = 96, обратно в x = 0 и так далее.
Давайте запустим это снова:
Вы заметите две проблемы на этом этапе. Во-первых, анимация очень нерегулярная, фактически она вообще не анимируется, если вы не двигаете мышью или чем-то еще. Во-вторых, спрайты, кажется, сбрасываются друг на друга, как показано на грязном изображении выше.
К счастью, обе эти проблемы можно решить с помощью кода, который мы уже использовали в « Обработка событий клавиатуры и мыши в SDL2 ». Первая проблема заключается в том, что мы используем SDL_WaitEvent () , поэтому программа ничего не делает, если не происходит какое-либо событие. Таким образом, нам нужно заменить наш вызов SDL_WaitEvent () на вызов SDL_PollEvent () :
while (SDL_PollEvent(&event) != NULL)
{
switch (event.type)
{
case SDL_QUIT:
quit = true;
break;
}
}
Вторая проблема заключается в том, что мы рисуем спрайты без очистки тех, которые мы рисовали раньше. Все, что нам нужно сделать, это добавить вызов SDL_RenderClear (), прежде чем мы вызовем SDL_RenderCopy () :
SDL_RenderClear(renderer);
Большой! Теперь вы можете восхищаться нашим маленьким персонажем, тасующим со скоростью один кадр в секунду:
Это хорошо, но немного медленно. Мы можем сделать это быстрее, заменив код анимации перед srcrect
объявлением следующим (10 кадров в секунду):
Uint32 ticks = SDL_GetTicks();
Uint32 sprite = (ticks / 100) % 4;
Woohoo! Посмотри на этого маленького парня, танцуй! (Изображение ниже является анимированным, но, похоже, это работает только в Firefox.)
Итак, в этой статье мы узнали, как анимировать простых персонажей, используя спрайт-листы, которые на самом деле являются просто цифровой версией мультфильма. Мы использовали параметр SDL_RenderCopy () , srcrect
чтобы рисовать только один спрайт из листа за раз, и выбрали этот спрайт, используя текущее время, на основе SDL_GetTicks ().
Это обновленная версия « SDL2: Анимации со списками спрайтов », первоначально опубликованная 30 марта 2014 года на ранчо программистов. Исходный код доступен в репозитории Gigi Labs BitBucket .