SDL2 游戏窗口搭建详情

SDL2 游戏窗口搭建详情
使用 SDL 和使用原始 Windows API 创建的过程基本一致,不同之处在于 SDL 做了一定程度上的简化。例如,注册窗口创建窗口的过程合并为一个 SDL_CreateWindow 函数,消息循环 也从 GetMessage、DispatchMessage 变为了 SDL_PollEvent 函数,原有的窗口过程也被封装成了事件消息,接下来就简单的介绍一下 SDL 创建窗口的基本过程。

WinMain 入口函数

首先和创建普通的 Windows 程序一样,创建一个 Win32 桌面程序。流程可以参考第一个 Windows 项目中介绍步骤,先确定入口函数:
//main.c

#include 

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 文件:
//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退出程序即可。

代码案例

整个窗口创建过程的代码如下:
//main.c

#include 
#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 静态编译的文章。

大佬,给点反馈?

平均评分 / 5. 投票数:

很抱歉,这篇文章不能帮助到你

请让我们改进这篇文章

告诉我们我们如何改善这篇文章?

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top