之前我们已经设置了 SDL,是时候制作一个在屏幕上呈现四边形的 SDL 图形应用程序了。
我们在上一卷的基础上编写,我会对重要的地方做出适当的解释。
// 使用 SDL 和 iostream
#include
#include
// 链接库
#pragma comment(lib, "SDL2.lib")
#pragma comment(lib, "SDL2main.lib")
// 屏幕尺寸常量
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
在源文件顶部,我们包含 SDL.h
,因为我们需要 SDL 函数和数据类型,还将包含 iostream
用来打印日志信息到控制台。
这里我在源代码中链接了库,你也可以在项目的属性中设置,这里我选择了我更容易看到的地方,但如果是一个比较大的工程,我可能会在这两者中考虑一会。
最后声明窗口的宽度和高度
接下来是 main 函数部分
/* 此源代码版权归 AnnihilateSword (2022-*)所有,未经书面许可不得转载。*/
// 使用 SDL 和 iostream
#include
#include
// 链接库
#pragma comment(lib, "SDL2.lib")
#pragma comment(lib, "SDL2main.lib")
// 屏幕尺寸常量
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
int main(int argc, char* argv[]) // 必须要填写此参数,不然会出现链接错误
{
// 定义 SDL 窗口
SDL_Window* window = nullptr;
// 初始化 SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
std::cout << "[Error]: SDL could not initialize! SDL_Error: " << SDL_GetError() << std::endl;
}
else
{
// 创建窗口
SDL_Window* window = SDL_CreateWindow("HelloSDL", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (window == nullptr)
{
std::cout << "[Error]: Window could not be created! SDL_Error: " << SDL_GetError() << std::endl;
}
else
{
// 获取窗口所包含的表面
SDL_Surface* screenSurface = SDL_GetWindowSurface(window);
// 将表面填充为蓝色
SDL_FillRect(screenSurface, nullptr, SDL_MapRGB(screenSurface->format, 51, 76, 204));
// 更新表面
SDL_UpdateWindowSurface(window);
// 窗口循环
SDL_Event e;
bool quit = false;
while (quit == false)
{
while (SDL_PollEvent(&e))
{
if (e.type == SDL_QUIT)
quit = true;
}
}
}
}
// 销毁窗口
SDL_DestroyWindow(window);
// 退出 SDL
SDL_Quit();
return 0;
}
这里要注意的是:我们要让入口函数(这里是 main)的参数是一个整数,后跟一个 char*
数组,返回值是一个整数。任何其他 main 函数的类型将导致对 main 的未定义引用。SDL 需要这种类型的主设备,以便与多个平台兼容。
声明窗口和屏幕表面后,我们初始化 SDL。如果不先初始化 SDL,则无法调用任何 SDL 函数。因为我们所关心的只是使用 SDL 的视频 子系统,我们只会传递它 SDL_INIT_VIDEO 标志。
SDL_Init() 函数用来初始化 SDL
参考官方文档:
成功返回 0,失败返回负;可以使用 SDL_GetError() 获取更多信息。
Returns 0 on success or a negative error code on failure; call SDL_GetError() for more information.
说到 API,最重要的就是文档,许多库官方都有提供文档(只能说大部分,因为我确实遇到过没有文档的…)
✨ SDL参考文档
SDL_GetError 是一个非常有用的功能。每当出现问题时,您都需要知道原因。SDL_GetError 会通知您 SDL 函数内部是否发生任何错误。
接下来就是创建窗口了,SDL_CreateWindow
函数的参数需要提供窗口的位置、宽高、标志
这里代码很简单,我们创建了一个标题是 “HelloSDL”,位置让 SDL 决定所以填写 SDL_WINDOWPOS_UNDEFINED
,宽高是我们声明的 640x480,最后指定 SDL_WINDOW_SHOW
让窗口正常显示,可以用 OR 运算指定多个标志。
如果窗口创建成功,我们还希望获取窗口的表面,以便我们可以绘制到它。
获取窗口的表面使用 SDL_GetWindowSurface
然后我们用 SDL_FillRect
函数使用特定颜色快速填充矩形。SDL_MapRGB
的第一个参数是描述像素格式的 SDL_PixelFormat
结构,我们直接使用窗口表面的格式。
关于渲染,需要了解的重要一点是,仅仅因为我们在屏幕表面绘制了某些内容并不意味着你会看到它。完成所需的所有绘图后,我们还需要更新窗口,使其显示您绘制的所有内容。
所以还需调用 SDL_UpdateWindowSurface
更新窗口表面
如果我们现在运行程序,窗口会一闪而过,一般我们都会用一个循环让程序持续运行,直到我们想要关闭,游戏不就是这样吗。
这里使用了 SDL_PollEvent
轮询处理事件,之后会放在单独的模块介绍事件系统,我不想在这里花大量篇幅介绍,让我们保持简单
参考文档
如果有可获取的事件返回 1,如果没有返回 0
Returns 1 if there is a pending event or 0 if there are none available.
最后,在我们结束循环后,我们将销毁窗口以释放其内存,并且退出 SDL
这一节花了较长篇幅来讲解 API,不过我推荐大家多看官方文档,我这里解释的 API 大部分其实都是查阅官方文档的解释,之后我会缩短单一解释 API 的篇幅(因为文档上都能找到)
如果是比较重要的或是难以理解的地方,我会写在文章中,所以,在之后的篇章中,我打算尽量减少不必要的解释,我认为这样能让我们更轻松。
不知道你们的想法是怎样,可以给我评论或留言。
本节内容就到这里了,下卷会继续分享 SDL 的基本使用
The End.