SDL 2.0课程周期:第5课-切片Sprite表

图片

来自翻译者:

这是Twinklebear教程系列翻译的延续,可在此处获得该翻译是部分免费的,可能包含翻译的少量修改或补充。前两节课的翻译-作者身份无效指针第三和第四 k1-801


课程清单:



雪碧切片


通常在2D游戏中,他们使用一个大图像来存储几个较小的图像,例如,在图块集中的图块而不是每个图块的许多小图片。这样的图像称为Sprite Sheet,它非常方便工作,因为我们不需要更改要绘制的纹理,而仅指示要使用纹理的哪一部分。

在本教程中,我们将看到如何使用SDL_RenderCopy选择纹理的一部分,以及有关如何检测特定按键事件的一些知识,这些事件将用于选择要绘制的纹理的一部分。Sprite表上将有四个彩色圆圈:

图片


在本教程中,子画面表由许多大小相同的子画面组成,在这种情况下切片并不困难。否则,对于大小不同的精灵,我们将需要一个元数据文件,其中包含有关零件位置的信息。在本教程中,我们将使用4个大小为100x100的精灵。本课程的代码基于第4课,如果您尚无要编写的代码,则可以从Github获取

零件选择


使用SDL,可以很容易地选择要绘制的纹理部分。在第4课中,带有NULL值的其余SDL_RenderCopy参数指示确定要绘制的纹理的哪一部分的矩形的坐标。当传递NULL值时,表明需要整个纹理,但是我们可以轻松地添加矩形的参数并仅绘制纹理的一部分。为此,请更改renderTexture函数,使其可以采用矩形区域,但为了方便起见,仍保留旧版本语法的简短版本。

更改renderTexture


为了不将越来越多的参数附加到renderTexture函数中,同时又保留默认值的便利性,我们将其分为两个函数。第一个与调用SDL_RenderCopy几乎相同,但是它提供了一个带有nullptr值的剪切区域参数。此版本的renderTexture将以矩形区域的形式接收位置,我们可以自行配置或使用其他专门的renderTexture函数之一。新的基本渲染功能变得非常简单。

/**
*  SDL_Texture  SDL_Renderer   .
*     
* @param tex  ,   
* @param ren ,    
* @param dst     
* @param clip     ( )
*                 nullptr   
*/
void renderTexture(SDL_Texture *tex, SDL_Renderer *ren, SDL_Rect dst,
        SDL_Rect *clip = nullptr)
{
        SDL_RenderCopy(ren, tex, clip, &dst);
}

为了方便起见,我们将编写另一个函数,在该函数中无需为该位置创建SDL_Rect,而只需提供x和y并让我们的显示函数填充纹理的宽度和高度。我们将创建renderTexture的重载版本,该版本将通过一些设置来处理剪切。添加带有默认值nullptr的cut矩形作为参数,如果通过了cut,我们将使用cut的宽度和高度而不是纹理的宽度和高度。因此,在绘制时,我们不会将小精灵拉伸到其可能非常大的精灵片的大小。该函数是对原始renderTexture函数的修改,看起来非常相似。

/**
*  SDL_Texture  SDL_Renderer   x, y, 
*          
*    ,       
*          
* @param tex  ,   
* @param ren ,    
* @param x  x,    
* @param y  y,    
* @param clip     ( )
*                 nullptr   
*/
void renderTexture(SDL_Texture *tex, SDL_Renderer *ren, int x, int y,
        SDL_Rect *clip = nullptr)
{
        SDL_Rect dst;
        dst.x = x;
        dst.y = y;
        if (clip != nullptr){
                dst.w = clip->w;
                dst.h = clip->h;
        }
        else {
                SDL_QueryTexture(tex, NULL, NULL, &dst.w, &dst.h);
        }
        renderTexture(tex, ren, dst, clip);
}

定义裁剪矩形


在我们的案例中,使用与第3课中的平铺方法非常相似的方法来计算剪切矩形非常容易,但是,我们将逐列进行,而不是逐行进行。因此,第一块将是绿色,第二块将是红色,第三块将是蓝色,第四块将是黄色。计算的想法与第3课中的相同,但是我们遍历列而不是行。因此,我们的y坐标是通过将瓦片索引除以瓦片数(2)时获得的余数来计算的,而x坐标是通过将索引除以瓦片数而获得的。这些x和y坐标分别是x和y索引,因此我们通过乘以切口的宽度和高度将它们转换为真实像素坐标,这对于所有图块(100x100)都是相同的。最后,选择要绘制的部分,在本例中为第一个。

我们还想在屏幕的中央绘制块,因此我们使用图块的宽度和高度而不是纹理的宽度和高度来计算这些x和y坐标。

//iW  iH    
//   ,     ,     
int iW = 100, iH = 100;
int x = SCREEN_WIDTH / 2 - iW / 2;
int y = SCREEN_HEIGHT / 2 - iH / 2;

//    
SDL_Rect clips[4];
for (int i = 0; i < 4; ++i){
        clips[i].x = i / 2 * iW;
        clips[i].y = i % 2 * iH;
        clips[i].w = iW;
        clips[i].h = iH;
}
//     
int useClip = 0;

取而代之的是,如果我们使用更加复杂的Sprite表,将大小不同的旋转Sprite打包在一起,则需要将有关其位置和旋转的信息存储在某些元数据文件中,以便我们轻松找到零件。

根据输入更改图像


要检查我们创建的图像的所有部分,我们将键盘输入处理添加到事件处理循环中,并使用键1-4选择显示的部分。要确定是否已按下某个键,可以检查事件是否为SDL_KEYDOWN类型,如果是,则可以使用e.key.keysym.sym通过检查事件内部的键代码来找出按下了哪个键。Wiki提供了有关SDL_Event 的事件类型键代码和其他信息的完整列表 当按下键时,我们需要将useClip的值更改为我们要绘制的图像部分的编号。经过这些更改,事件循环如下所示:



while (SDL_PollEvent(&e)){
        if (e.type == SDL_QUIT)
                quit = true;
        //       
        if (e.type == SDL_KEYDOWN){
                switch (e.key.keysym.sym){
                        case SDLK_1:
                                useClip = 0;
                                *break;
                        case SDLK_2:
                                useClip = 1;
                                *break;
                        case SDLK_3:
                                useClip = 2;
                                *break;
                        case SDLK_4:
                                useClip = 3;
                                *break;
                        case SDLK_ESCAPE:
                                quit = true;
                                *break;
                        default:
                                *break;
                }
        }
}

绘制裁剪的图像


最后要做的是在屏幕上获得图像的正确部分!为此,我们将调用更方便的renderTexture版本来绘制图像的一部分,而无需额外缩放,并转移我们要使用的部分(useClip中使用的部分)。

SDL_RenderClear(renderer);
renderTexture(image, renderer, x, y, &clips[useClip]);
SDL_RenderPresent(renderer);

第5课结束


启动程序时,您应该在屏幕中央看到部分0(绿色圆圈),并能够使用数字键选择图像的不同部分。如果遇到任何问题,请仔细检查您的代码和/或向原始作者发送电子邮件或推文。

All Articles