当前位置:   article > 正文

SDL游戏开发之五-解析并使用GIF_sdl gif

sdl gif

在游戏开发中,使用的图片一般情况下的格式为PNG,在我看来PNG有着以下几个好处:

  1. 不错的压缩比
  2. alpha通道(支持透明)
  3. 无损压缩

以上的几个特性使得PNG在游戏开发中大放异彩。另外,主流就是使用PNG+TexturePacker,把碎图整合成一张大的图片(一般是POT Power Of Two,图片的宽和高是2的幂),然后再在程序中使用。这样做的好处主要是为了兼容旧的设备、方便对齐处理以及字节对齐。

SDL支持一些主流的图片格式,比如png、jpg等。而这其中并不包括GIF。

表情包经常会出现各种各样的动图,这种大多是GIF。一个GIF格式的图片文件中内部一般都会有着多于一帧的图片,由于GIF格式的特性,使得它在每隔一段时间会切换当前显示的图片,以达到动画的效果,这也是目前的2D游戏中的动画的最常用的形式。

如上图,则是一个标准的动图。

虽然SDL官方并没有提供一个解析GIF的方式,不过网上是有着对应的库的。

这个并不是我开发的,是一个外国人,好像从2006年起就没有更新过了,在以前心血来潮,就发了封邮件给SDL官方,官方说并不提供 animated gif,然后推荐了个网址,源文件是以SDL1.x写的,因为现在的主流是SDL2,所以就稍微改变了下代码。
SDL_AniGIF是我更改后的文件,SDL_AniGIF-1.0.0是原先的文件,具体关于gif解码的,我就不多说了(我也不会。。)见附件

 

在游戏开发中,一般的动画是每隔一段时间就切换图片,如果第一张和倒数第二张图片有着明显连贯性的时候,就会感觉到非常流畅,就比如上面贴的关羽的图片。

SDL_angif会先判断这个文件有着几帧,之后在申请到足够的空间后调用相应的函数后,就会得到一个帧数组,它里面包含着每一帧图片以及对应的坐标(在这里指的是SDL_Surface,如果使用的SDL 2.x,建议转换成SDL_Texture)以及该图片的持续时间。注意需要预先设置好SDL2的开发环境

代码:

  1. #include <iostream>
  2. #include <SDL.h>
  3. #include <cstdio>
  4. #include <vector>
  5. #include "SDL_anigif.h"
  6. using namespace std;

首先包含到这个例子所需要的库文件和外国热心网友写的gif解析库。

  1. int main(int argc,char**argv)
  2. {
  3. SDL_Event event;
  4. bool g_bRunning = true;
  5. int currentFrame = 0;
  6. SDL_Init(SDL_INIT_EVERYTHING);
  7. SDL_Window*gWin = SDL_CreateWindow("gif test",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,640,480,SDL_WINDOW_SHOWN);
  8. SDL_Renderer*gRen = SDL_CreateRenderer(gWin,-1,SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC);

使用SDL的时候,需要先初始化SDL库(SDL_Init),接着创建一个窗口(SDL_CreateWindow)和渲染器(SDL_CreateRenderer)。

  1. //先获取最大数量
  2. int number = AG_LoadGIF("2.gif",NULL,0);
  3. AG_Frame*frames = new AG_Frame[number];
  4. AG_LoadGIF("2.gif",frames,number);

SDL_angif库仅仅提供了几个简单的函数,而用得最多的就是AG_LoadGIF,它的使用过程如下:

  1. 调用该函数获取到了2.gif的帧个数;
  2. 根据个数创建了一个数组,
  3. 再次调用该函数,把GIF的图片加载到内存之中。
  1. //由frames创建texture
  2. std::vector<SDL_Texture*> textures;
  3. for(int i=0;i<number;i++)
  4. {
  5. SDL_Texture*texture = SDL_CreateTextureFromSurface(gRen,frames[i].surface);
  6. textures.push_back(texture);
  7. }

SDL 1.x使用的是SDL_Surface进行图片的绘制;而在SDL 2.x后,就转而创建了一个新的结构体SDL_Texture,代替了SDL_Surface的大部分功能。

  1. SDL_Rect destRect = { 0,0,0,0 };
  2. SDL_Rect srcRect = { 0, 0, 0, 0 };
  3. SDL_SetRenderDrawColor(gRen,255,200,100,255);
  4. while(g_bRunning)
  5. {
  6. //①
  7. while(SDL_PollEvent(&event))
  8. {
  9. switch(event.type)
  10. {
  11. case SDL_QUIT:
  12. g_bRunning = false;
  13. break;
  14. }
  15. }
  16. //②
  17. SDL_RenderClear(gRen);
  18. destRect.x = frames[currentFrame].x;
  19. destRect.y = frames[currentFrame].y;
  20. srcRect.w = destRect.w = frames[currentFrame].surface->w;
  21. srcRect.h = destRect.h = frames[currentFrame].surface->h;
  22. SDL_RenderCopy(gRen, textures.at(currentFrame), &srcRect, &destRect);
  23. SDL_RenderPresent(gRen);
  24. SDL_Delay(frames[currentFrame].delay);
  25. currentFrame = (currentFrame + 1) % number;
  26. }

无论什么游戏,其底层一般都是一个大的循环体,在这个循环体的内部则进行绘制以及事件响应等。

在①处注释中,这个循环体是为了从事件队列中拿取事件,使用循环的原因是要在每次循环时把事件队列取空,以避免延迟响应。

处注释后,则是具体的绘制代码,SDL_RenderClear()的功能是清空画布;而SDL_RenderPresent()则是把已经绘制的图片显示到画布上。由于SDL内部提供了双缓冲机制,所以一般不需要自己再实现双缓冲机制。

在SDL_RenderClear()和SDL_RenderPresent()的中间进行调用绘制函数进行绘制即可。

在之前的AG_LoadGIF中,已经读取到了图片,所以在这个时候只需要调用SDL_RenderCopy()绘制图片即可。srcRect表示从源图片中按照srcRect进行提取;然后把取出的图片绘制到destRect大小的矩形之中。

虽然是同一个GIF,但是内部的图片的大小和偏移可能会不同,所以在绘制的过程中还需要加上一定的偏移。

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/303535
推荐阅读
相关标签
  

闽ICP备14008679号