1.1:什么是精灵?
如果有很多很多的图片,不想发布游戏的时候包含n多小小的图片文件,那么可以考虑把小图片都画在一张大图上,然后“抠”下来用,不也是很方便吗?这张大图就叫精灵图(Sprite sheet)。每一个抠下来的图片就叫精灵啦。
精灵只是一种技巧,需要的知识,我们前面都已经学习过了。我们稍微修改一下类,就可以很好的演示这个技术实现。
1.2:填充背景的颜色
int SDL_FillRect(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color);
这个函数是往一个指定surface的指定矩形区域中填充指定的颜色。如果指定矩形区域为空指针,则填充整个surface。值得注意的
是,SDL_Surface结构中包含矩形区域的只读成员数据是clip_rect。我们为ScreenSurface类增加一个方法,默认填充黑色。
class ScreenSurface
{
private:
//
public:
//
void fillColor(Uint8 r = 0, Uint8 g = 0, Uint8 b = 0) const;
};
实现为:
void ScreenSurface::fillColor(Uint8 r, Uint8 g, Uint8 b) const
{
if ( SDL_FillRect(pScreen, 0, SDL_MapRGB(pScreen->format, r, g, b)) < 0 )
throw ErrorInfo(SDL_GetError());
}
1.3:思路
我们先创建一个ScreenSurface对象,并将其填充为白色作为背景。装载精灵图之后,先抠掉精灵图的背景色,然后按照区域,分4次将4个图片小精
灵blit到背景上。非常简单!需要说明的是,我修改了局部blit()方法偏移值的默认参数值。因为在之前的章节中,局部blit()主要用于blit
部分背景将背景“搽干净”,需要将偏移设为非零;而我们现在使用这个方法的主要目的是抠精灵图片,如果偏移非零的话就会把设定范围之外的图像也抠过来,而
这不是我们希望发生的。
//UVi Soft (2008)
//Long Fei (lf426), E-mail: zbln426@163.com
//FileName: SurfaceClass.h
#ifndef SURFACE_CLASS_H
#define SURFACE_CLASS_H
#include <iostream>
#include <string>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
class ScreenSurface
{
private:
static int screenNum;
int width;
int height;
int bpp;
Uint32 flags;
SDL_Surface* pScreen;
public:
ScreenSurface();
ScreenSurface(int w, int h, int b = 0, Uint32 f = 0);
~ScreenSurface();
SDL_Surface* point() const;
void flip() const;
void fillColor(Uint8 r = 0, Uint8 g = 0, Uint8 b = 0) const;
};
class DisplaySurface
{
private:
std::string fileName;
SDL_Surface* pSurface;
SDL_Surface* pScreen;
public:
DisplaySurface(const std::string& file_name, const ScreenSurface& screen);
~DisplaySurface();
SDL_Surface* point() const;
void blit() const;
void blit(int at_x, int at_y) const;
void blit(int at_x, int at_y,
int from_x, int from_y, int w, int h,
int delta_x = 0, int delta_y = 0) const;
void colorKey(Uint8 r = 0, Uint8 g = 0xFF, Uint8 b = 0xFF, Uint32 flag = SDL_SRCCOLORKEY);
};
class ErrorInfo
{
private:
std::string info;
public:
ErrorInfo():info("Unknown ERROR!")
{}
ErrorInfo(const char* c_str)
{
info = std::string(c_str);
}
ErrorInfo(const std::string& str):info(str)
{}
void show() const
{
std::cerr << info << std::endl;
}
};
#endif
//UVi Soft (2008)
//Long Fei (lf426), E-mail: zbln426@163.com
#include "SurfaceClass.h"
//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
//class ScreenSurface
int ScreenSurface::screenNum = 0;
ScreenSurface::ScreenSurface():
width(640), height(480), bpp(32), flags(0)
{
if ( screenNum > 0 )
throw ErrorInfo("DONOT create more than ONE screen!");
if ( SDL_Init(SDL_INIT_VIDEO < 0 ) )
throw ErrorInfo(SDL_GetError());
pScreen = SDL_SetVideoMode(width, height, bpp, flags);
screenNum++;
}
ScreenSurface::ScreenSurface(int w, int h, int b, Uint32 f):
width(w), height(h), bpp(b), flags(f)
{
if ( screenNum > 0 )
throw ErrorInfo("DONOT create more than ONE screen!");
if ( SDL_Init(SDL_INIT_VIDEO < 0 ) )
throw ErrorInfo(SDL_GetError());
pScreen = SDL_SetVideoMode(width, height, bpp, flags);
screenNum++;
}
ScreenSurface::~ScreenSurface()
{
SDL_Quit();
}
SDL_Surface* ScreenSurface::point() const
{
return pScreen;
}
void ScreenSurface::flip() const
{
if ( SDL_Flip(pScreen) < 0 )
throw ErrorInfo(SDL_GetError());
}
void ScreenSurface::fillColor(Uint8 r, Uint8 g, Uint8 b) const
{
if ( SDL_FillRect(pScreen, 0, SDL_MapRGB(pScreen->format, r, g, b)) < 0 )
throw ErrorInfo(SDL_GetError());
}
//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
//class DisplaySurface
DisplaySurface::DisplaySurface(const std::string& file_name, const ScreenSurface& screen):
fileName(file_name)
{
SDL_Surface* pSurfaceTemp = IMG_Load(file_name.c_str());
if ( pSurfaceTemp == 0 )
throw ErrorInfo(SDL_GetError());
pSurface = SDL_DisplayFormat(pSurfaceTemp);
if ( pSurface == 0 )
throw ErrorInfo(SDL_GetError());
SDL_FreeSurface(pSurfaceTemp);
pScreen = screen.point();
}
DisplaySurface::~DisplaySurface()
{
SDL_FreeSurface(pSurface);
}
SDL_Surface* DisplaySurface::point() const
{
return pSurface;
}
void DisplaySurface::blit() const
{
if ( SDL_BlitSurface(pSurface, 0, pScreen, 0) < 0 )
throw ErrorInfo(SDL_GetError());
}
void DisplaySurface::blit(int at_x, int at_y) const
{
SDL_Rect offset;
offset.x = at_x;
offset.y = at_y;
if ( SDL_BlitSurface(pSurface, 0, pScreen, &offset) < 0 )
throw ErrorInfo(SDL_GetError());
}
void DisplaySurface::blit(int at_x, int at_y,
int from_x, int from_y, int w, int h,
int delta_x, int delta_y) const
{
SDL_Rect offset;
offset.x = at_x - delta_x;
offset.y = at_y - delta_y;
SDL_Rect dest;
dest.x = from_x - delta_x;
dest.y = from_y - delta_y;
dest.w = w + delta_x*2;
dest.h = h + delta_y*2;
if ( SDL_BlitSurface(pSurface, &dest, pScreen, &offset) < 0 )
throw ErrorInfo(SDL_GetError());
}
void DisplaySurface::colorKey(Uint8 r, Uint8 g, Uint8 b, Uint32 flag)
{
Uint32 colorkey = SDL_MapRGB(pSurface->format, r, g, b);
if ( SDL_SetColorKey(pSurface, flag, colorkey ) < 0 )
throw ErrorInfo(SDL_GetError());
}
//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
//UVi Soft (2008)
//Long Fei (lf426), E-mail: zbln426@163.com
#include "SurfaceClass.h"
int game(int argc, char* argv[]);
int main(int argc ,char* argv[])
{
int mainRtn = 0;
try {
mainRtn = game(argc, argv);
}
catch ( const ErrorInfo& info ) {
info.show();
return -1;
}
return mainRtn;
}
int game(int argc ,char* argv[])
{
//Create a SDL screen.
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
ScreenSurface screen(SCREEN_WIDTH, SCREEN_HEIGHT);
//Fill background with white.(default is black)
screen.fillColor(0xFF, 0xFF, 0xFF);
//Load a sprite pic, and colorkey.(default color: R=0,G=0xFF,B=0xFF)
DisplaySurface sprite("dots.png", screen);
sprite.colorKey();
//the 4 dots's coordinate.
int atX[4] = {0, 540, 0, 540};
int atY[4] = {0, 0, 380, 380};
//the 4 dots's clip coordinate.
int fromX[4] = {0, 100, 0 ,100};
int fromY[4] = {0, 0, 100, 100};
//dots's size.
const int IMG_WIDTH = 100;
const int IMG_HEIGHT = 100;
//clip dots.
for ( int i = 0; i < 4; i++ )
sprite.blit(atX[i], atY[i], fromX[i], fromY[i], IMG_WIDTH, IMG_HEIGHT);
//Draw dots and screen.
screen.flip();
//press ESC or click X to quit.
bool gameOver = false;
SDL_Event gameEvent;
while( gameOver == false ){
while ( SDL_PollEvent(&gameEvent) != 0 ){
if ( gameEvent.type == SDL_QUIT ){
gameOver = true;
}
if ( gameEvent.type == SDL_KEYUP ){
if ( gameEvent.key.keysym.sym == SDLK_ESCAPE ){
gameOver = true;
}
}
}
}
return 0;
}