用 SDL2 处理精灵图

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用 SDL2 处理精灵图相关的知识,希望对你有一定的参考价值。

技术分享

上面就是一个精灵图,由多个固定间隔的图标组成。利用精灵图的好处就是不必将图标逐个读入内存进行操作。我们可以将精灵图中需要的部分用一个个矩形截取下来,然后再输出到渲染器上。

环境:SDL2 + VC++2015

下面的代码将打开sprite.png,并对相应的操作做出响应。

技术分享

sprite.png

  1 #include <stdexcept>
  2 #include <string>
  3 #include <iostream>
  4 #include "SDL.h"
  5 #include "SDL_image.h"
  6 
  7 //屏幕宽度
  8 const int SCREEN_WIDTH = 500;
  9 const int SCREEN_HEIGHT = 500;
 10 
 11 //全局窗口和渲染器
 12 SDL_Window *window = nullptr;
 13 SDL_Renderer *renderer = nullptr;
 14 
 15 //记录SDL错误
 16 void logSDLError(std::ostream &os, const std::string &msg)
 17 {
 18     os << msg << " error: " << SDL_GetError() << std::endl;
 19 }
 20 
 21 //加载图像材质
 22 SDL_Texture* loadTexture(const std::string &file, SDL_Renderer *ren)
 23 {
 24     SDL_Texture *texture = IMG_LoadTexture(ren, file.c_str());
 25     if (texture == nullptr) logSDLError(std::cout, "LoadTexture");
 26     return texture;
 27 }
 28 
 29 
 30 //根据坐标生成截取区域并复制输出到渲染器
 31 void renderTexture(SDL_Texture *tex, SDL_Renderer *ren, int x, int y, SDL_Rect *clip = nullptr)
 32 {
 33     //目标截面区域初始化,提供目标在渲染器的坐标
 34     SDL_Rect dst; dst.x = x; dst.y = y;
 35     //源截面区域不为空,将其值赋给目标截面
 36     if (clip != nullptr) { dst.w = clip->w; dst.h = clip->h; }
 37     //将截面输出到渲染器
 38     SDL_RenderCopy(ren, tex, clip, &dst);
 39 }
 40 
 41 int main(int argc, char** argv)
 42 {
 43     //初始化SDL
 44     if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
 45     {
 46         std::cout << SDL_GetError() << std::endl;
 47         return 1;
 48     }
 49 
 50     //创建窗口
 51     window = SDL_CreateWindow("Lesson 5",
 52         SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
 53         SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
 54     if (window == nullptr)
 55     {
 56         std::cout << SDL_GetError() << std::endl;
 57         return 2;
 58     }
 59 
 60     //创建渲染器
 61     renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
 62     if (renderer == nullptr)
 63     {
 64         std::cout << SDL_GetError() << std::endl;
 65         return 3;
 66     }
 67 
 68     //创建纹理
 69     SDL_Texture *image = nullptr;
 70     try
 71     {
 72         image = loadTexture("sprite.png", renderer);
 73     }
 74     catch (const std::runtime_error &e)
 75     {
 76         std::cout << e.what() << std::endl;
 77         return 4;
 78     }
 79 
 80     //iW,iH 表示截面宽高
 81     int iW = 100, iH = 100;
 82     //x,y 分别为截面在渲染器输出的坐标
 83     int x = SCREEN_WIDTH / 2 - iW / 2;
 84     int y = SCREEN_HEIGHT / 2 - iH / 2;
 85 
 86     //为精灵图设置截面
 87     SDL_Rect clips[4];
 88 
 89     //初始化截面信息
 90     for (int i = 0; i < 4; ++i)
 91     {
 92         clips[i].x = i / 2 * iW;
 93         clips[i].y = i % 2 * iH;
 94         clips[i].w = iW;
 95         clips[i].h = iH;
 96     }
 97 
 98     //表示将要输出的截面
 99     int useClip = 0;
100 
101     SDL_Event e;
102     bool quit = false;
103     //主循环
104     while (!quit)
105     {
106         //事件轮询
107         while (SDL_PollEvent(&e))
108         {
109             //按右上角的X退出
110             if (e.type == SDL_QUIT) quit = true;
111 
112             //点击鼠标随机输出截面
113             if (e.type == SDL_MOUSEBUTTONDOWN) useClip = rand() % 4;
114 
115             //使用数字键决定输出截面,分别有1,2,3,4
116             if (e.type == SDL_KEYDOWN)
117             {
118                 switch (e.key.keysym.sym)
119                 {
120                 case SDLK_1:
121                 case SDLK_KP_1:
122                     useClip = 0;
123                     break;
124                 case SDLK_2:
125                 case SDLK_KP_2:
126                     useClip = 1;
127                     break;
128                 case SDLK_3:
129                 case SDLK_KP_3:
130                     useClip = 2;
131                     break;
132                 case SDLK_4:
133                 case SDLK_KP_4:
134                     useClip = 3;
135                     break;
136                 case SDLK_ESCAPE:
137                     quit = true;
138                     break;
139                 default:
140                     break;
141                 }
142             }
143         }
144         //清空渲染器
145         SDL_RenderClear(renderer);
146         //绘制材质
147         renderTexture(image, renderer, x, y, &clips[useClip]);
148         //呈现渲染器
149         SDL_RenderPresent(renderer);
150     }
151 
152     //释放资源
153     SDL_DestroyTexture(image);
154     SDL_DestroyRenderer(renderer);
155     SDL_DestroyWindow(window);
156 
157     SDL_Quit();
158 
159     return 0;
160 }

 

以上是关于用 SDL2 处理精灵图的主要内容,如果未能解决你的问题,请参考以下文章

如何在片段着色器中平铺部分纹理

用 SDL2 在屏幕上打印文本

无法使用 IMG_Load() 加载图像

实施英特尔实感和 SDL2 的问题

片段着色器中的OpenGL点精灵旋转

精灵图和字体图标