SDL 2.0课程周期:第3课-SDL扩展库

SDL2

来自翻译者:

InvalidPointer系列以前的课程的翻译者允许的情况下,我将继续使用废弃的Twinklebear教程翻译系列,该系列最初在这里提供。 列表中的一系列翻译的前两课是他的著作。 该翻译是部分免费的,并且可能包含翻译人员的少量修改或补充。

课程清单:


SDL扩展库


在此之前,我们仅使用BMP图像,因为这是SDL 2核心库支持的唯一图像类型,而且不太方便。 幸运的是,有许多SDL扩展库添加了有用的功能,例如,SDL_image允许您加载多种类型的图像,SDL_ttf添加了对使用TTF字体呈现文本的支持,SDL_net提供了对低级网络的支持,SDL_mixer提供了多通道音频输出。

安装扩展


在本教程中,我们将仅使用SDL_image,但是,其他扩展的安装过程没有什么不同,并且通常与安装SDL2本身的过程几乎一致。

  • Windows (MinGW或Visual Studio):将从扩展项目页面下载的扩展文件放在具有SDL2的文件夹中。 另外,您需要将SDL2_image,zlib和其他.dll文件(例如libpng)复制到带有可执行文件的文件夹中(或在C:\ Windows \ system32- 大约Per​​。中 ),以便在应用程序启动时加载它们。
  • Linux :使用内部软件包管理器安装扩展程序,或从源代码构建。 如果您拥有Linux-很可能您已经知道该怎么做©。
  • Mac :从官方网站下载.dmg,然后按照自述文件中的说明进行操作。

另外,要使用扩展名,您将需要更新已使用的头文件和插件库的列表,就像对SDL2本身所做的一样。

在开始使用扩展之前,需要将<SDL2 / SDL_image.h>文件或与所需扩展名相对应的文件连接到SDL本身的头文件之后,并使用它连接到.c和.cpp文件。

初始化SDL_image(可选)


每种类型的图像的第一次加载时,SDL_image都会自动初始化该类型所需的子系统,但是,这会引起轻微的延迟。 为避免这种情况,您可以使用IMG_Init函数预先初始化必要的子系统。 IMG_Init返回一个位掩码,其中包含当前已成功初始化的所有子系统的列表,因此,要验证调用是否成功,您需要检查是否已设置了指示初始化的所有子系统的位,例如,将掩码应用于按位I.结果。在本课中,我们只需要一个子系统PNG。 在SDL_Init之后执行此操作很重要。

if ((IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG) != IMG_INIT_PNG) { logSDLError(std::cout, "IMG_Init"); SDL_Quit(); return 1; } 


设定尺寸


在本课程中,我们将研究如何使用SDL_image加载图像,如何在渲染时缩放纹理,以及如何以比上一课更合理的方式用瓷砖平铺背景-基于窗口和瓷砖尺寸的循环。

但首先,让我们为图块大小设置一个常量,就在窗口大小的常量之下。

 const int SCREEN_WIDTH = 640; const int SCREEN_HEIGHT = 480; //     const int TILE_SIZE = 40; 

使用SDL_image上传图像


SDL_image允许您加载多种类型的图像,并立即使用IMG_LoadTexture函数将其转换为SDL_Texture。 该函数将替换上一课中的几乎所有loadTexture函数代码,现在只需调用IMG_LoadTexture,检查在加载过程中是否有任何错误,然后退出该函数。 由于SDL_image中定义的IMG_GetError函数只不过是SDL_GetError的同义词,因此我们可以使用它们中的任何一个来显示错误消息。

 /** *       * @param file    * @param ren ,        * @return  ,  nullptr   . */ SDL_Texture* loadTexture(const std::string &file, SDL_Renderer *ren) { SDL_Texture *texture = IMG_LoadTexture(ren, file.c_str()); if (!texture) { std::cout << IMG_GetError(); //    SDL_GetError() } return texture; } 

指定渲染的高度和宽度


如果在将纹理渲染到渲染器时指定的矩形大小与纹理的大小不同,则SDL2将对其进行相应缩放。 但是,如果不需要缩放,则每次确定初始纹理大小可能很不方便,因此我们将实现renderTexture函数的两个版本,其中一个版本将按比例绘制纹理,而第二个版本将按比例绘制纹理。

 /** *  SDL_Texture  SDL_Renderer   x, y,   * @param tex    * @param ren  * @param x  * @param y * @param w     * @param h */ void renderTexture(SDL_Texture *tex, SDL_Renderer *ren, int x, int y, int w, int h) { SDL_Rect dst; dst.x = x; dst.y = y; dst.w = w; dst.h = h; SDL_RenderCopy(ren, tex, NULL, &dst); } /** *  SDL_Texture  SDL_Renderer   x, y,   * @param tex  * @param ren  * @param x  * @param y */ void renderTexture(SDL_Texture *tex, SDL_Renderer *ren, int x, int y) { int w, h; SDL_QueryTexture(tex, NULL, NULL, &w, &h); renderTexture(tex, ren, x, y, w, h); } 

加载纹理


由于本课的主要目的是下载PNG图像,因此我们将使用一组新的图像。 另外,我们将展示在平铺背景上渲染前景图像(具有透明背景)时,PNG透明性的保留情况。

我们将使用以下图片:

平铺以填充背景:



前景的图像(写在上面,具有透明的背景,以及带有违反Habr规则的图释):



上传图片:

 SDL_Texture *background = loadTexture("background.png", renderer); SDL_Texture *image = loadTexture("image.png", renderer); //  if (!background || !image) { //  ,      cleanup(),   PS   ,     ,  ,    . SDL_DestroyTexture(background); SDL_DestroyTexture(image); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); IMG_Quit(); SDL_Quit(); return 1; } 

平铺背景


由于磁贴明显变小了,我们需要放入四块以上才能填满整个窗口,并且手动指定每个位置非常困难。 幸运的是,您可以让计算机自己确定这些位置。

我们可以通过将窗口的宽度除以瓦片的大小,以及类似地将高度除以找到多少个瓦片。

 //   ,      //  :     ceil(float(SCREEN_WIDTH) / TILE_SIZE),    ,       ,      ; ,        ,     . int xTiles = SCREEN_WIDTH / TILE_SIZE; int yTiles = SCREEN_HEIGHT / TILE_SIZE; //   for (int i = 0; i < xTiles * yTiles; ++i) { int x = i % xTiles; int y = i / xTiles; renderTexture(background, renderer, x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); } 

绘制前景图像


如前所述,前景图像放置在窗口的中间。

 int iW, iH; SDL_QueryTexture(image, NULL, NULL, &iW, &iH); int x = SCREEN_WIDTH / 2 - iW / 2; int y = SCREEN_HEIGHT / 2 - iH / 2; renderTexture(image, renderer, x, y); 

仍然只在窗口上显示结果并等待几秒钟,就像第二课一样。

 SDL_RenderPresent(renderer); SDL_Delay(2000); 

清洁用品


除了增加的调用IMG_Quit外,资源的释放与第2课中的资源释放类似(在处理错误时加载图像已在上面看到)。

 SDL_DestroyTexture(background); SDL_DestroyTexture(image); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); IMG_Quit(); SDL_Quit(); 

成功编译并启动后,如果正确完成所有操作,则窗口将如下所示:



第三课结束


因此,下一课结束了。 在第4课:处理事件中见。

Source: https://habr.com/ru/post/zh-CN437252/


All Articles