用 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 }