转自我的Gitee项目
SDL2使用简介
- SDL2使用简介
- 开发环境搭建
- Windows
- Visual Studio
- Code::Blocks
- Dev-Cpp
- CMake(CLion)
- 问题总结
- SDL2库使用介绍
- 初始化
- 创建窗口
- 绘制矩形
- 刷新屏幕
- 读取输入
- 直接扫描键盘
- 读取系统事件
- 实例
- 绘制图片
SDL2使用简介
开发环境搭建
Windows
Visual Studio
VS2019+SDL2.0环境准备
Code::Blocks
Code::Blocks如何植入SDL2
Dev-Cpp
Dev-Cpp开发环境配置SDL库
CMake(CLion)
本条需要预先安装CMake
下载SDL2源代码
在源代码目录下输入指令
cmake -S . -B build
cmake --build build --target install
然后在项目的CMakeLists.txt下的add_executable(xxx ...)
命令之后加入target_link_libraries(xxx SDL2::SDL2 SDL2::SDL2main)
add_executable(YourProjectName main.cpp)target_link_libraries(YourProjectName SDL2::SDL2 SDL2::SDL2main)
问题总结
Q : undefined reference to “xxxx” ?
A : 请统一使用i686(32位)的头文件和库,目前还没有找到用x86_64(64位)头文件和库的方法
SDL2库使用介绍
首先包含SDL2头(先要搭建好环境)
#include <SDL.h>
或
#include <SDL2/SDL.h>
然后按格式创建main函数(很关键,不然SDL2找不到)
int main(int argc, char** argv) {return 0;
}
初始化
SDL初始化需要调用SDL_Init(unsigned int flag)
函数。该函数接收一个参数用于表示初始化哪些模块,这里直接填入SDL_INIT_EVERYTHING
这一flag初始化所有模块。
当初始化成功时函数返回0。因此在main函数中,使用如下代码完成初始化。
int main(int argc, char** argv) {if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {return -1;}return 0;
}
PS:如果在此处报错,那就是环境搭建仍有问题
创建窗口
使用SDL_CreateWindow(const char* title, int x, int y, int w, int h, unsigned int flag)
来取得一个SDL_Window*(这是表示一个窗口的变量)未来将通过一系列函数操作这个变量。
其中
- title: 窗口名。
- x, y: 窗口位置,用SDL_WINDOWPOS_UNDEFINED来表示不预定位置。
- w, h: 窗口的长(width)宽(height),这里就直接写800, 600了。
- flag: 窗口创建的一些flag,这里直接填入SDL_WINDOW_SHOWN。
在程序执行完毕后,使用SDL_DestroyWindow(SDL_Window* window)
来销毁一个窗口。
int main(int argc, char** argv) {SDL_Window* window = NULL;if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {return -1;}window = SDL_CreateWindow("Your Window Title", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, SDL_WINDOW_SHOWN);SDL_DestroyWindow(window);return 0;
}
这时候编译运行应该会闪一个黑框,可以在销毁窗口前调用SDL_Delay(2000)
来使窗口持续显示(阻塞线程)2000毫秒。
int main(int argc, char** argv) {SDL_Window* window = NULL;if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {return -1;}window = SDL_CreateWindow("Your Window Title", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, SDL_WINDOW_SHOWN);SDL_Delay(2000);SDL_DestroyWindow(window);return 0;
}
绘制矩形
注:SDL的坐标系是以左上角为原点,往右为x正方向,下为y正方向。
下面的代码将在(350, 250)处绘制出一个边长为100像素的红色的正方形。下面将对代码进行讲解。
int main(int argc, char** argv) {SDL_Window* window = NULL;SDL_Renderer* renderer = NULL;struct SDL_Rect rect = { 350, 250, 100, 100 };if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {return -1;}window = SDL_CreateWindow("Your Window Title", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, SDL_WINDOW_SHOWN);renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);SDL_SetRenderDrawColor(renderer, 0xff, 0, 0, 0xff);SDL_RenderFillRect(renderer, &rect);SDL_RenderPresent(renderer);SDL_Delay(2000);SDL_DestroyRenderer(renderer);SDL_DestroyWindow(window);return 0;
}
使用SDL_CreateRenderer(SDL_Window* window, int index, unsigned int flag)
来对这个窗口创建一个渲染器(SDL_Renderer*)。
- window: 先前创建的window变量
- index: 标识渲染器的序号,这里只用一个所以是-1
- flag: 标识渲染器的渲染方式,这里使用GPU渲染所以用
SDL_RENDERER_ACCELERATED
类似地,可以使用SDL_DestroyRenderer(SDL_Renderer* renderer)
来销毁一个渲染器。
可以用渲染器+图形绘制图形,例如填充一个矩形:SDL_RenderFillRect(SDL_Renderer* renderer, const SDL_Rect* rect)
不过首先要通过SDL_SetRenderDrawColor(SDL_Renderer* renderer, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
来设置渲染器颜色。
在画完所有东西以后,调用SDL_RenderPresent(SDL_Renderer* renderer)
来提交改动。
刷新屏幕
上面的代码都只是一段顺序执行的代码,画的再多也只能画一张静态的图片,而做游戏,肯定是得让画面动起来的。动起来自然就需要反复对画面进行绘制,因此我们通过while
循环来做到这一点。
而每一帧开始绘制之前,需要清除上一帧所绘制的内容。不然会在屏幕上出现拖影。换句话说,先前画的所有东西都会堆在一起。
调用SDL_RenderClear(SDL_Renderer* renderer)
来清除屏幕。别忘了在清除前设定好颜色。
//...省略上面的代码...
// 用白色清空屏幕
SDL_SetRenderDrawColor(renderer, 0xff, 0xff, 0xff, 0xff);
SDL_RenderClear(renderer);
//...省略下面的代码...
读取输入
在这之前,需要介绍SDL读取输入的方式。不然程序就没办法通过正常方式关掉了。
SDL读取输入的方式有两种:
- 直接扫描当前键盘的状态。
- 通过系统事件间接读取输入。
直接扫描键盘
通过调用SDL_GetKeyboardState(int* len)
来获取一个数组的指针。通过if
判断键盘按键对应该数组的下标的值。举例,如果要判断W键是否被按下:
const unsigned char* keyMap = SDL_GetKeyboardState(NULL);
if (keyMap[SDL_SCANCODE_W]) {printf("W键被按下!!");
}
读取系统事件
函数SDL_PollEvent(SDL_Event* event)
在有事件时会返回1,并将事件写入event
,否则返回0。因此我们可以用以下方式来读取系统事件。
SDL_Event event;
while (SDL_PollEvent(&event)) {// 处理事件...
}
实例
下面的代码将让上一节中的矩形按WASD键动起来,而且可以单击窗口上的“叉”来关闭这个窗口。
int main(int argc, char** argv) {SDL_Window* window = NULL;SDL_Renderer* renderer = NULL;// 创建矩形struct SDL_Rect rect = { 350, 250, 100, 100 };int running = 1;if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {return -1;}window = SDL_CreateWindow("Your Window Title", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, SDL_WINDOW_SHOWN);renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);while (running) {SDL_Event event;while (SDL_PollEvent(&event)) {if (event.type == SDL_QUIT) {running = 0;}}// 扫描键盘const unsigned char* keyMap = SDL_GetKeyboardState(NULL);// 如果W或S按下,更新矩形的上下位置if (keyMap[SDL_SCANCODE_W]) {rect.y -= 1;} else if (keyMap[SDL_SCANCODE_S]) {rect.y += 1;}// 如果A或D按下,更新矩形的左右位置if (keyMap[SDL_SCANCODE_A]) {rect.x -= 1;} else if (keyMap[SDL_SCANCODE_D]) {rect.x += 1;}// 清除屏幕SDL_SetRenderDrawColor(renderer, 0xff, 0xff, 0xff, 0xff);SDL_RenderClear(renderer);// 绘制矩形SDL_SetRenderDrawColor(renderer, 0xff, 0, 0, 0xff);SDL_RenderFillRect(renderer, &rect);// 更新内容SDL_RenderPresent(renderer);}SDL_DestroyWindow(window);return 0;
}
绘制图片
绘制图片需要先读取再使用SDL_RenderCopy()
将其作为材质附加到SDL_Renderer上。以下代码展示了如何简单读取图片并渲染出来。
#include <SDL2/SDL.h>
#include <stdio.h>int main(int argc, char *argv[])
{const int SCREEN_WIDTH = 800;const int SCREEN_HEIGHT = 600;SDL_Window *window = NULL;SDL_Renderer *renderer = NULL;if (SDL_Init(SDL_INIT_EVERYTHING) != 0){printf("SDL could not initialize! SDL error: %s\n", SDL_GetError());return -1;}window = SDL_CreateWindow("SDL Guide", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);//读取图片,SDL_LoadBMP中的字符串是图片路径SDL_Surface* surface = SDL_LoadBMP("dummy.bmp");renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);//创建一个Rect设定图片渲染时的位置和大小,这里直接用上面的矩形const struct SDL_Rect rect = {350, 250, 100, 100};//把SDL_Surface转换为SDL_Texture,即材质SDL_Texture* tex = SDL_CreateTextureFromSurface(renderer,surface);//设定背景颜色SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);SDL_RenderClear(renderer);//附加材质SDL_RenderCopy(renderer, tex, NULL, &rect);SDL_RenderPresent(renderer);SDL_Delay(2000);SDL_DestroyRenderer(renderer);SDL_Quit();return 0;
}
效果图
SDL_Surface
接收SDL_LoadBMP
读取的图片,再使用SDL_CreateTextureFromSurface
转换为材质。
图片素材