Взагалі то, це просто пишеться руками, через функцію
SDL_BlitSurface(surf,&cut,dst,&pos);
Але є одне але. Нам потрібно вказувати поверхню з якої вирізаємо спрайт, прямокутник який вирізаємо, поверхню на яку ліпимо спрайт, і прямокутник в який ліпимо. Якщо нам потрібно зробити це раз, то можна всі координати прописувати руками.
Ось так, я намалював кілька сотень спрайтів. Не зважайте на білі огризки по краях, це все через те, що картинка була в jpeg.
Але програмісти ліниві, і шукають легші способи. Щоб полегшити собі і вам життя, я написав клас, який завантажує листок спрайтів, і розбиває його на спрайти заданого розміру. Якщо розміри завантаженої картинки не є кратними до розміру спрайту, то краї відкидаються. Спрайти нумеруються починаючи з нуля, зліва направо, і зверху вниз:
0 1 2 3 4 5 6 7 . . .
Ну думаю, ви зрозуміли.
Тепер, щоб намалювати спрайт досить викликати метод
void blit(SDL_Surface *dst, int x,int y, int num)
якому потрібно передати цільову поверхню, координати в яких малюємо, та номер спрайту. Номер спрайту не має перевищувати Count() інакше отримаєте segmentation fault (access violation).
Щоб завантажити листок спрайтів, я використав функцію, написану Lazy Foo, і трохи її вдосконалив. Вона може завантажувати зображення будь-якого растрового формату (принаймі png, jpg і bmp вміє), і створювати прозорі області.
Прозорі області можна робити трьома способами:
- Не робити
- Використати альфа-канал зображення (якщо воно є)
- Оголосити якийсь колір прозорим.
Функція
void load(char *filename,int alpha=1, char ra=0, char ga=0, char ba=0)
завантажує зображення з файлу filename, створює прозорі області способом alpha, і при потребі може зробити прозорим колір (ra,ga,ba).
І останнє, але важливе: розміри спрайту задаються в конструкторі:
SpriteSheet ss(10,10);
Код
//universal loader of images with alpha channel
SDL_Surface *load_image(char *filename, int key=0, char rkey=0, char gkey=0, char bkey=0 )
// if key=0 don't use color keying
// if key=1 use own alpha chanal of image
// if key=2 use color key rkey,gkey,bkey
{
//Temporary storage for the image that's loaded
SDL_Surface* loadedImage = NULL;
//The optimized image that will be used
SDL_Surface* optimizedImage = NULL;
//Load the image
loadedImage = IMG_Load( filename );
//If nothing went wrong in loading the image
if( loadedImage != NULL )
{
//Create an optimized image
if(key==1) optimizedImage = SDL_DisplayFormatAlpha( loadedImage );
else optimizedImage = SDL_DisplayFormat( loadedImage );
//Free the old image
SDL_FreeSurface( loadedImage );
//If the image was optimized just fine
if((key==2)&&( optimizedImage != NULL ))
{
//Map the color key
Uint32 colorkey = SDL_MapRGB( optimizedImage->format, rkey, gkey, bkey );
SDL_SetColorKey( optimizedImage, SDL_SRCCOLORKEY, colorkey );
}
}
//Return the optimized image
return optimizedImage;
}
class SpriteSheet
{
SDL_Surface *surf;
int count,wcount,hcount;
int w,h;
vector<SDL_Rect> cuts;
public:
SpriteSheet()
{
surf=NULL;
count=0;
w=0;
h=0;
}
~SpriteSheet()
{
cuts.clear();
SDL_FreeSurface(surf);
}
SpriteSheet(int sw,int sh)
{
surf=NULL;
count=0;
w=sw;
h=sh;
}
void load(char *filename,int alpha=1, char ra=0, char ga=0, char ba=0)
{
surf=load_image(filename,alpha,ra,ga,ba);
if(!surf) return;
if((w!=0)&&(h!=0))
{
wcount = surf->w / w;
hcount = surf->h / h ;
count = wcount*hcount;
}
cuts.clear();
for(int i=0;i<count;i++)
{
SDL_Rect r;
r.x=w*(i % wcount);
r.y=h*(i/ wcount);
r.w=w; r.h=h;
cuts.push_back(r);
}
printf("loaded %i sprites\n",count);
}
void blit(SDL_Surface *dst, int x,int y, int num)
{
SDL_Rect pos;
pos.x=x;
pos.y=y;
pos.h=h;
pos.w=w;
SDL_BlitSurface(surf,&cuts[num],dst,&pos);
}
int Count()
{
return count;
}
int WCount()
{
return wcount;
}
int HCount()
{
return hcount;
}
};
Ілюстрацію зроблено кодом:
for(i=0;i<ss.WCount();i++)
for(j=0;j<ss.HCount();j++)
ss.blit(screen,i*(15),(j)*15,i+j*ss.WCount());