| Урок 1 | Содержание | Урок 3 |

Приветствую вас во втором уроке. Если вы внимательно изучили первый, то это очень хорошо. Сегодня мы
научимся отображать картинки в ваших программах. Этот урок очень простой и я постараюсь объяснить каждую
строчку нашей следующей программы. Мы нарисуем приятный бэкграунд, нарисуем забавное существо и будем
передвигать его с помощью клавиатуры.
Начнем с включения заголовочных файлов. Их должно быть три: stdio.h, stdlib.h и SDL.h. Файл
stdlib.h нужен для функции atexit().
#include <stdio.h> #include <stdlib.h> #include "SDL.h"
SDL_Surface *back; SDL_Surface *image; SDL_Surface *screen; int xpos=0, ypos=0;
InitImages() нужна, чтобы загружать изображения из файлов (BMP) на наши поверхности
SDL_Surface. Позже мы вызовем эту функцию из функции main(). Внутри нашей функции мы
используем SDL_LoadBMP. Эта функция принимает имя файла изображения в качестве параметра и
возвращает указатель на структуру SDL_Surface. Мы загрузим две картинки: одну в
SDL_Surface back, которая будет отображаться в качестве фона, а другую в SDL_Surface
image, которая будет нашим существом.
/* ------------------------------------------- */
void InitImages(){
back=SDL_LoadBMP("bg.bmp");
image=SDL_LoadBMP("image.bmp");
}
|
Библиотекой SDL поддерживается только формат BMP. Вся эта поддержка состоит только из двух функций
SDL_LoadBMP, которую мы использовали и SDL_SaveBMP, которая позволяет сохранять поверхность в файл BMP.
Для этой функции передавайте в качестве параметра поверхность, которую надо сохранить и имя файла, куда
сохранять. Вот ее прототип: |
DrawIMG. Первая из
них принимает в качестве параметра поверхность, которую нужно отобразить и координаты в которых это
изображение появится на экране. Для этого нам пригодится функция SDL_BlitSurface(), с помощью
которой одну поверхность можно отобразить на другой. Вот прототип функции, взятый из документации SDL:
int SDL_BlitSurface(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect);
src это поверхность, которую мы хотим отобразить, а dst это поверхность на
которой отобразится src. Еще два параметра - это указатели на структуру SDL_Rect: srcrect и
dstrect. Эта структура содержит 4 16-битных целых числа: x, y, w(ширина) и h(высота).
srcrect указывает какую часть исходной поверхности отобразить, а dstrect задает
координаты принимающей поверхности, в которых отобразится исходная. Если в качестве второго параметра
NULL, то все исходное изображение будет отображено целиком. В структуре dstrect
элементы ширина (w) и высота (h) не обрабатываются функцией и не имеют никакого значения. Вот код первой
функции DrawIMG
/* ------------------------------------------- */
void DrawIMG(SDL_Surface *img, int x, int y){
SDL_Rect dest;
dest.x = x;
dest.y = y;
SDL_BlitSurface(img, NULL, screen, &dest);
}
|
srcrect. Элементы x и y структуры srcrect
задают координату откуда начинать копирование изображения, а ширина и высота определяют размеры исходного
копируемого изображения. То есть, мы рисуем только часть изображения. Взгляните на код функции и
постарайтесь понять, что происходит:
/* ------------------------------------------- */
void DrawIMG(SDL_Surface *img, int x, int y, int w, int h, int sx, int sy){
SDL_Rect dest;
dest.x = x;
dest.y = y;
SDL_Rect src;
src.x = sx;
src.y = sy;
src.w = w;
src.h = h;
SDL_BlitSurface(img, &src, screen, &dest);
}
|
DrawBG(), с помощью которой будем рисовать бэкграунд (задний фон).
Впоследствии, в функции main перед началом главного цикла мы вызовем ее. Как вы помните с
предыдущего урока, нам не надо блокировать экран для отображения картинок. В этой функции мы просто
копируем фоновое изображение на экранную поверхность SDL_Surface *screen. Нам не понадобится
функция обновления экрана навроде SDL_Flip(), потому что бэкграунд нужно нарисовать только
один раз. Заметьте, что копировать изображение поверхности можно на любую поверхность, а не только на
экран. Вот код для рисования заднего фона:
/* ------------------------------------------- */
void DrawBG(){
DrawIMG(back, 0, 0);
}
|
SDL_Flip() (так как все рисование происходит в
невидимом буфере screen, который мы выводим в итоге на экран). С этого места подробнее. Стандартный
алгоритм для анимации движения таков:
/* ------------------------------------------- */
void DrawScene(){
DrawIMG(back, xpos-2, ypos-2, 132, 132, xpos-2, ypos-2);
DrawIMG(image, xpos, ypos);
SDL_Flip(screen);
}
|
main. Создадим для начала указатель на переменную типа Uint8,
который будем использовать для определения нажатия клавиш клавиатуры. После этого происходит
инициализация, о которой вы читали в первом уроке.
int main(int argc, char *argv[]){
Uint8* keys;
if ( SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO) < 0 ){
printf("Unable to init SDL: %s\n", SDL_GetError());
exit(1);
}
atexit(SDL_Quit);
SDL_WM_SetCaption("SDL Gfx Example #2","ex2");
SDL_WM_SetIcon(SDL_LoadBMP("icon.bmp"), NULL);
screen=SDL_SetVideoMode(640,480,32,SDL_HWSURFACE|SDL_DOUBLEBUF);
if ( screen == NULL ){
printf("Unable to set 640x480 video: %s\n", SDL_GetError());
exit(1);
}
|
InitImages(); DrawBG(); |
int done=0;
while(done == 0){
SDL_Event event;
while ( SDL_PollEvent(&event) ){
if ( event.type == SDL_QUIT ){ done = 1; }
if ( event.type == SDL_KEYDOWN ){
if ( event.key.keysym.sym == SDLK_ESCAPE ){ done = 1; }
}
}
|
Uint8 *keys? Так
вот, функция SDL_GetKeyState() возвращает указатель на массив Uint8. Каждый
элемент массива содержит состояние определенной клавиши клавиатуры (нажата или нет). Мы не проверяем все
клавиши в event-цикле (там где проверка на нажатие ESCAPE), потому что SDL_PollEvent
реагирует только на события (например KEYDOWN), но не будет реагировать на удерживание клавиши. После
этого рисуем сцену:
keys = SDL_GetKeyState(NULL);
if(keys[SDLK_UP]){ ypos -= 1; }
if(keys[SDLK_DOWN]){ ypos += 1; }
if(keys[SDLK_LEFT]){ xpos -= 1; }
if(keys[SDLK_RIGHT]){ xpos += 1; }
DrawScene();
}
return 0; } |
| Урок 1 | Содержание | Урок 3 |
©opyleft PLG, 2003.