SDL2 游戏窗口搭建详情
- W_Z_C
- 共 1265 字,阅读约 3 分钟
使用 SDL 和使用原始 Windows API 创建的过程基本一致,不同之处在于 SDL 做了一定程度上的简化。例如,注册窗口和创建窗口的过程合并为一个 SDL_CreateWindow 函数,消息循环 也从 GetMessage、DispatchMessage 变为了 SDL_PollEvent 函数,原有的窗口过程也被封装成了事件消息,接下来就简单的介绍一下 SDL 创建窗口的基本过程。
WinMain 入口函数
首先和创建普通的 Windows 程序一样,创建一个 Win32 桌面程序。流程可以参考第一个 Windows 项目中介绍步骤,先确定入口函数:
#include <Windows.h>
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR lpCmdLine, INT nCmdShow)
{
return 0;
}
初始化 SDL
在使用 SDL 之前,需要初始化 SDL 的子系统,并指定需要使用哪些子模块。具体的接口如下:
int SDL_Init(Uint32 flags)
void SDL_Quit(void);
这两个函数就是 SDL 库用来初始化和注销的两个函数,其中 flags 代表需要初始化子系统的标记位:
SDL_INIT_TIMER | TIMER SUBSYSTEM |
---|---|
SDL_INIT_AUDIO | audio subsystem |
SDL_INIT_VIDEO | video subsystem; automatically initializes the events subsystem |
SDL_INIT_JOYSTICK | joystick subsystem; automatically initializes the events subsystem |
SDL_INIT_HAPTIC | haptic (force feedback) subsystem |
SDL_INIT_GAMECONTROLLER | controller subsystem; automatically initializes the joystick subsystem |
SDL_INIT_EVENTS | events subsystem |
SDL_INIT_EVERYTHING | all of the above subsystems |
SDL_INIT_NOPARACHUTE | compatibility; this flag is ignored |
这些标记位之间可以使用或运算组合。对于初学者,这里推荐直接无脑使用 SDL_INIT_EVERYTHING 宏,这个宏是所有这些标记位的综合。
#define SDL_INIT_EVERYTHING (
SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS |
SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_SENSOR
)
将初始化代码加入到 main.c 文件:
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR lpCmdLine, INT nCmdShow)
{
int ret = SDL_Init(SDL_INIT_EVERYTHING);
if (ret != 0) {
return -1;
}
SDL_Quit();
return 0;
}
创建 Windows 窗口
接着步骤就是创建窗口,这里可以使用 SDL 库自带的 SDL_CreateWindow 函数:
SDL_Window* SDL_CreateWindow(const char* title,
int x,
int y,
int w,
int h,
Uint32 flags)
这个函数的参数非常简单,title 代表的窗口标题,x、y、w、h 分别代表着窗口的位置和大小,最后这个标记位代表着一些常用的窗口设置,例如全屏、最小化、焦点等内容。 默认情况下,你可以将 flags 标记位设为 0,创建窗口代码如下:
SDL_Window* pWin = SDL_CreateWindow("Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, 0);
和创建相对应的,就是销毁:
void SDL_DestroyWindow(SDL_Window* window)
参数 windows 就是 SDL_CreateWindow 返回的指针变量。程序中可以这样使用:
if (pWin) {
SDL_DestroyWindow(pWin);
}
这里有一个地方需要注意,在 SDL 中,默认的字符集是 UTF8,所以如果你想显示中文标题,需要转换字符编码,因为默认情况下 vs2019 在中文系统中使用的是 GB2312 字符集。
消息循环
在 SDL 创建窗口的过程中,不需要设置窗口回调函数,SDL 已经将其封装到了内部,你可以在消息循环的代码中直接获取你关注的消息,具体可以通过 SDL_PollEvent 函数获得:
int SDL_PollEvent(SDL_Event* event)
其中如果队列中存在事件,则函数返回 1,参数 event 中存放事件的具体内容。在原来的消息循环中,我们需要不断的通过 GetMessage 获取消息,然后通过 TranslateMessage、DispatchMessage 函数转换分派消息,SDL 已将将这些所有的过程都封装到了 SDL_PollEvent 函数中:
int quit = 0;
SDL_Event evt;
while (!quit) {
if (SDL_PollEvent(&evt)) {
if (evt.type == SDL_QUIT) {
quit = 1;
}
} else {
//TODO: 渲染窗口
}
}
其中 SDL_QUIT 代表程序退出事件,当收到这个消息的时候,直接退出循环销毁窗口,注销 SDL退出程序即可。
代码案例
整个窗口创建过程的代码如下:
#include <Windows.h>
#include "SDL.h"
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR lpCmdLine, INT nCmdShow)
{
int ret = SDL_Init(SDL_INIT_EVERYTHING);
if (ret != 0) {
return -1;
}
SDL_Window* pWin = SDL_CreateWindow("Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, 0);
if (pWin == NULL) {
return -2;
}
int quit = 0;
SDL_Event evt;
while (!quit) {
if (SDL_PollEvent(&evt)) {
if (evt.type == SDL_QUIT) {
quit = 1;
}
}
else {
//TODO: 渲染窗口
}
}
if (pWin) {
SDL_DestroyWindow(pWin);
}
SDL_Quit();
return 0;
}
如果你在 Windows 平台写 SDL 程序,在编译程序的时候,可能会出现链接失败的问题,具体可以查看 SDL 静态编译的文章。