文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>SDL入门教程(五):3、对SDL_BlitSurface()的进..

SDL入门教程(五):3、对SDL_BlitSurface()的进..

时间:2010-12-27  来源:landuochong

3.1:矩形区域SDL_Rect。
typedef struct{
  Sint16 x, y;
  Uint16 w, h;
} SDL_Rect;         因为显示器通常是矩形的,所以,矩形是计算机图形学中最基本的操作区域单元。这个结构很简单,x和y是矩形的左上角坐标。x从左到右增加;y从上到下增加。左上角的坐标就是(0,0)——SDL中就是这样的。w是矩形的宽,h是矩形的高。

3.2:进一步了解SDL_BlitSurface()。
int SDL_BlitSurface(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect);         4个参数都是指针——2个SDL_Surface指针,2个SDL_Rect指针。src是源面,也就是被blit的面;dst是目的面,也就是源面被 blit到的面。srcrect是源面上的一个矩形区域,实际上,正是这个矩形区域被blit,如果是空指针,则整个源面被blit;dstrect虽然 是个矩形区域指针,但是实际上只用到了这个矩形左上角坐标的数据。所以,实际上,它是源面被blit到目的面上的坐标。如果是空指针,则被blit到目的 面的左上角(0,0)。

3.3:为surface类增加新的方法。
class DisplaySurface
{
public:
    bool blit(int at_x, int at_y) const;
    bool blit(int at_x, int at_y, int from_x, int from_y, int w, int h, int delta_x = 2, int delta_y = 2) const;
}; 我们重载了blit()方法。
bool 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 )
        return false;
    else return true;
} 这个方法,让整个源面被blit到目的面的(at_x,at_y)坐标上。
bool 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 )
        return false;
    else return true;
} 这个函数,把源面上,一个左上角坐标是(from_x,from_y),宽为w,高为h的矩形区域,blit到目的面的(at_x,at_y)坐标上。
要说明delta_x和delta_y的作用,我们先思考一个问题:动画效果是如何实现的。
我们假设有个作为背景的surface,名为back,我们要让一个名为front的surface在back上动起来。显然,至少有两种方法:
1) 把front blit到back上,把back blit到screen上,flit screen,显示出原来的图像;
    把back面“搽干净”;改变front的坐标,将改变坐标后的front blit到back上,把back blit到screen上,flit screen,显示出更新后的图像。
2) 把back blit到screen上,flit screen,首先显示出back图像;
    先把back面“搽干净”;把front blit到screen上(back是一直保持在screen上的,而front会被blit到back的上层),flit screen,显示出更新后的图像。
因为,第二种方法把所有的surface都直接往screen上blit,思路更为简单,所以,我们先讨论这种方法。
而对于“搽干净”这个概念,又有两种思路:
1) 全部back更新;
2) 更新back上“被弄脏”的部分。
实 际上,当前的电脑速度对在平面上的blit速度问题已经不再是问题了。但是,在不久之前,程序员们还在为了计算机图形的实现速度而绞尽脑汁。blit一部 分应该是比blit全部图像要快的。所以,这个重载的blit()方法多用于对于back的blit。delta_x和delta_y是为了保证blit 的back部分,比front大那么一点点。不然的话——实际上大家可以把delta_x和delta_y设置为0看看是什么效果。
4.1:再讨论简单的SDL event响应。
Uint8 *SDL_GetKeyState(int *numkeys);         要让图片动起来,最好是我们可以“操作”的动。按照一般思路,键盘的“上”“下”“左”“右”是不错的选择。在FPS游戏和模拟器中,我们可能更习惯 wsad四个键,所以,让他们同时起作用吧。这个函数的一般用法,是把参数设置为空指针。我们还是先忽略细节。因为有了两个新的blit()重载方法的加 入,我们设置要移动的图片在screen上的坐标是(xpos,ypos),则:
    //key event for up, down, left and right.
    Uint8* keys;
    //moving image's coordinate.
    int xpos = 0;
    int ypos = 0; 控制图片移动的代码如下:
        //key event to move image.
        keys = SDL_GetKeyState(0);
        if ( keys[SDLK_UP] || keys[SDLK_w] ){
            ypos -= 1;
        }
        if ( keys[SDLK_DOWN]|| keys[SDLK_s] ){
            ypos += 1;
        }
        if ( keys[SDLK_LEFT]|| keys[SDLK_a] ){
            xpos -= 1;
        }
        if ( keys[SDLK_RIGHT]|| keys[SDLK_d] ){
            xpos += 1;
        } 代码一目了然,不用多解释。具体对应的按键可参考:
http://www.libsdl.org/cgi/docwiki.cgi/SDLKey

4.2:对于第二种方法的分析。

        我们前面讨论了总是把surface blit到screen上的情况。如果我们的思路是把其他surface先blit到一个作为背景画布的surface上,最后把背景画布blit到screen上呢?
        我们将遇到的第一个疑问是,surface能不能把自己blit到自己上面?试验的结果是否定的,而SDL并没有给出官方的异常信息,即 SDL_GetError()没有起作用。所以,异常得我们自己来抛出。另外一个后果是,我们必须建立背景画布的拷贝,把拷贝blit到背景画布上才是可 行的。
class DisplaySurface
{
public:
    bool blitToSurface(const DisplaySurface& dst_surface,
                        int at_x = 0, int at_y = 0) const;
    bool blitToSurface(const DisplaySurface& dst_surface,
                        int at_x, int at_y,
                        int from_x, int from_y, int w, int h,
                        int delta_x = 2, int delta_y = 2) const;
}; 这和blit到screen是类似的,但是实际效果是完全不一样的。因为,没有被blit到screen上的surface,都不可能被flip显示出 来。所以,虽然参数列表是不一样的,意味着我可以继续用blit()这个名字重载。但是为了表明他们的实际效果有区别,我重新用了方法名。
bool DisplaySurface::blitToSurface(const DisplaySurface& dst_surface, int at_x, int at_y) const
{
    SDL_Rect offset;
    offset.x = at_x;
    offset.y = at_y;

    if ( &dst_surface == this )
        throw "Cannot blit surface to itself!";

    if ( SDL_BlitSurface(pSurface, 0, dst_surface.point(), &offset) < 0 )
        return false;
    else return true;
}

bool DisplaySurface::blitToSurface(const DisplaySurface& dst_surface,
                                    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 ( &dst_surface == this )
        throw "Cannot blit surface to itself!";

    if ( SDL_BlitSurface(pSurface, &dest, dst_surface.point(), &offset) < 0 )
        return false;
    else return true;
}
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载