SDL2基本使用

news/2025/1/22 12:51:16/

前言

  在这里记录SDL的环境基本搭建和使用,方便回忆。使用该图形库也是为了方便在没有单片机和显示模块的使用,也能对简单验证些关于图形构建或界面管理的猜想和测试,所以下述不会探讨过于深入的东西。当然,也可以通过SDL官网查看介绍。


下载

在官网看到,SDL2的最新稳定版本为2.30.11,点击跳转到其GitHub下,下载SDL2-devel-2.30.11-mingw.zip

在这里插入图片描述


CLion中

这里我是在CLion创建Demo项目,并且将下载好的SDL2-devel-2.30.11-mingw.zip解压后放入,并且编写好CMakeLists.txt,对SDL2进行链接。具体CMake流程可以参考CMake。

在这里插入图片描述


SDL2_30">SDL2的基本使用

  教程参考至SDL2官网维基中C++ Programming (thenumb.at),其目录 - SDL2章节下的8个基本教程,下述将基于C语言实现代码,且加上对应的注释。还有就是为了保证代码看起来清晰些,把创建是否成功的状态判断,都去掉了,默认成功创建窗口、表面、图形等对象。然后在没有看到SDL2的交互函数时,暂且先用while(1);,来保持绘制界面。除此之外,除了在第一个案例末尾演示内存释放流程外其它案例,也不在演示释放函数。

如果觉得下述讲解的太过累赘的,可以直接看上面的原教程链接。

  1. 创建窗口并显示出来的基本流程:

    调用SDL_Init()初始化SDL2,在通过SDL_CreateWindow()创建窗口对象win,在通过SDL_GetWindowSurface基于窗口对象创建表面对象winSurface。然后将要绘制的矩形通过SDL_FillRect()绘制到表面对象winSurface上,最后通过SDL_UpdateWindowSurface()更新窗口对象win,显示在界面上。在结束时,调用SDL_DestroyWindow()SDL_Quit()完成释放变量和关闭SDL2

    表面:SDL 将您可以绘制的任何区域(包括加载的图像)抽象为“表面”

    #include <stdio.h>
    #include <stdlib.h>
    #include <SDL.h>
    #include <synchapi.h>int main(int argc, char* argv[]) {SDL_Init( SDL_INIT_EVERYTHING );    // 初始化SDL2所有部分SDL_Window* win = SDL_CreateWindow( "my window", 100, 100, 640, 480, SDL_WINDOW_SHOWN );    // 创建窗口SDL_Surface* winSurface = SDL_GetWindowSurface( win );   // 基于窗口创建“表面”SDL_UpdateWindowSurface( win );                          // 更新窗口SDL_FillRect( winSurface, NULL, SDL_MapRGB( winSurface->format, 255, 90, 120 ));            // 绘制矩形SDL_UpdateWindowSurface( win ); // 更新窗口while (1);                              // 卡住界面(保持窗口,)SDL_DestroyWindow( win );       // 销毁窗口win = NULL; winSurface = NULL;         // 释放变量SDL_Quit();                            // 关闭SDL2return 0;
    }
    

    在这里插入图片描述

  2. 位图显示

    该节主要讲解了位图在SDL的保存、绘制和缩放等。同时相比于第1节教程多了SDL_Rect结构,来控制显示位置。

    #include <SDL.h>SDL_Window* win;
    SDL_Surface* winSurface;
    SDL_Rect dest;
    SDL_Surface* image1;
    SDL_Surface* image2;// 显示BMP图片
    void ShowBMP()
    {dest.x = 20; dest.y = 20;SDL_BlitSurface( image1, NULL, winSurface, &dest );  // 图片1加载到表面SDL_UpdateWindowSurface( win ); // 更新窗口while (1);                              // 卡住界面(保持窗口)
    }
    // 缩放BMP图片
    void ScaledBMP()
    {dest.x = 20; dest.y = 20; dest.w = 200; dest.h = 100;                      // 重新设置SDL_Rect结构对象SDL_BlitScaled( image1, NULL, winSurface, &dest );  // 缩放图片SDL_UpdateWindowSurface( win ); // 更新窗口while (1);                              // 卡住界面(保持窗口)
    }
    // 转换表面
    void ConvertSurface()
    {dest.x = 20; dest.y = 20;image2 = SDL_ConvertSurface( image1, winSurface->format, 0 ); // 将图片1进行转换SDL_BlitSurface( image2, NULL, winSurface, &dest );  // 图片2加载到表面SDL_FreeSurface(image1);                                             // 图片1随后释放SDL_UpdateWindowSurface( win ); // 更新窗口while (1);                              // 卡住界面(保持窗口)
    }int main(int argc, char* argv[]) {SDL_Init( SDL_INIT_EVERYTHING );                                                             // 初始化SDL2所有部分win = SDL_CreateWindow( "MyWindow", 100, 100, 640, 480, SDL_WINDOW_SHOWN ); // 创建窗口winSurface = SDL_GetWindowSurface( win );                                                  // 基于窗口创建“表面”image1 = SDL_LoadBMP( "../../../../logo.bmp" );                                                    // 加载BMP图形(相对路径)// 下述三个案例逐个解开注释查看// ShowBMP();// ScaledBMP();ConvertSurface();return 0;
    }
    

    在这里插入图片描述

  3. 事件活动

    在教程中该节主要讲解到了事件,如健值的输入事件,关闭事件等。且通过SDL_Event 定义的结构对象,和SDL_PollEvent()函数获取到事件的类型和触发健值等等。还有我怀疑,教程是不是把SDL_PollEvent函数写成SDL_PolLEvent,这压根就没有找到。下述就健值获取事件退出事件鼠标事件列出函数案例,至于官方不推荐的健值轮询,和自定义用户就举例了,有需要的可以调整教程详细观看,还有更多的其它事件可以浏览SDL的文档网站查看。

    #include <SDL.h>
    #include "SDL_events.h"SDL_Window* win;
    SDL_Surface* winSurface;
    SDL_Event ev;char running = 1;// 按键输入验证
    // 简述:通过识别按下的'1'、'2'、'3'键来,切换纯色界面。按下'4'退出案例。
    void KeyInPut()
    {running = 1;while( running){while ( SDL_PollEvent( &ev ) != 0 ) {switch (ev.type) {case SDL_KEYDOWN:// 健值分支switch ( ev.key.keysym.sym ) {case SDLK_KP_1:SDL_FillRect( winSurface, NULL, SDL_MapRGB( winSurface->format, 255, 0, 0 ));            // 绘制红色矩形break;case SDLK_KP_2:SDL_FillRect( winSurface, NULL, SDL_MapRGB( winSurface->format, 0, 255, 0 ));            // 绘制绿色矩形break;case SDLK_KP_3:SDL_FillRect( winSurface, NULL, SDL_MapRGB( winSurface->format, 0, 0, 255 ));            // 绘制蓝色矩形break;case SDLK_KP_4:// 退出该案例running = 0;break;}break;}}SDL_UpdateWindowSurface( win ); // 更新窗口SDL_Delay(100);}
    }// 窗口退出验证
    // 简述:只有在 SDL_QUIT 类型的事件下,点击'x'关闭窗口,才能得到响应关闭。
    void WinClose()
    {running = 1;while ( running ) {// Event loopwhile ( SDL_PollEvent( &ev ) != 0 ) {switch (ev.type) {case SDL_QUIT:running = 0;break;}}SDL_Delay(100);}
    }// 鼠标输入
    // 简述:通过按下鼠标左键、中键、右键切换纯色界面。
    void MouseInput()
    {while ( running ) {while ( SDL_PollEvent( &ev ) != 0 ) {switch (ev.type) {case SDL_MOUSEBUTTONUP:// test buttonswitch ( ev.button.button ) {case SDL_BUTTON_LEFT:   // 鼠标左键SDL_FillRect( winSurface, NULL, SDL_MapRGB( winSurface->format, 255, 255, 0 ));break;case SDL_BUTTON_RIGHT:  // 鼠标右键SDL_FillRect( winSurface, NULL, SDL_MapRGB( winSurface->format, 0, 255, 255 ));break;case SDL_BUTTON_MIDDLE: // 鼠标中键SDL_FillRect( winSurface, NULL, SDL_MapRGB( winSurface->format, 255, 0, 255 ));break;}break;}}SDL_UpdateWindowSurface( win ); // 更新窗口SDL_Delay(100);}
    }// 退出后清理释放内存
    void kill() {// Free imagesSDL_FreeSurface( winSurface );// QuitSDL_DestroyWindow( win );SDL_Quit();
    }int main(int argc, char* argv[]) {SDL_Init( SDL_INIT_EVERYTHING );                                                              // 初始化SDL2所有部分win = SDL_CreateWindow( "MyWindow", 100, 100, 640, 480, SDL_WINDOW_SHOWN );  // 创建窗口winSurface = SDL_GetWindowSurface( win );                                                   // 基于窗口创建“表面”SDL_FillRect( winSurface, NULL, SDL_MapRGB( winSurface->format, 0, 0, 0 )); // 绘制矩形SDL_UpdateWindowSurface( win ); // 更新窗口// KeyInPut();// WinClose();MouseInput();kill(); // 清理释放return 0;
    }

    在这里插入图片描述

  4. 几何渲染

    区别于上述几个案例,在绘制图形时都是使用基于软件或 CPU 渲染。在下述中将会引入到渲染器SDL_Renderer结构来进行渲染绘制,它的渲染速度会得到提高。而且不在采用基于SDL_Surface表面结构的绘制,而是通过操作渲染器SDL_Renderer结构,定位,绘制,更新,来完成帧图。如何更多的绘制,如点、线、面等可以查看函数文档。

    代码案例中,实现的效果和案例1基本相同,被注释掉的是,之前基于表面结构实现的方法。

    SDL_Window* win;
    SDL_Renderer* renderer;int main(int argc, char* argv[]) {SDL_Rect rect;rect.x = 20; rect.y = 20; rect.w = 100; rect.h = 100;SDL_Init( SDL_INIT_EVERYTHING );                                                              // 初始化SDL2所有部分// win = SDL_CreateWindow( "MyWindow", 100, 100, 640, 480, SDL_WINDOW_SHOWN );  // 创建窗口SDL_CreateWindowAndRenderer( 640, 480, NULL, &win, &renderer );     // 创建窗口和渲染器// winSurface = SDL_GetWindowSurface( win );                                                   // 基于窗口创建“表面”// SDL_FillRect( winSurface, NULL, SDL_MapRGB( winSurface->format, 0, 0, 0 )); // 绘制矩形SDL_SetRenderDrawColor( renderer, 255, 0, 0, 255 );SDL_RenderFillRect(renderer, &rect);// SDL_UpdateWindowSurface( win ); // 更新窗口SDL_RenderPresent( renderer );  // 更新窗口while (1);  // 卡住界面(保持窗口)// 清理释放SDL_DestroyRenderer( renderer );SDL_DestroyWindow( win );return 0;
    }SDL_Window* win;
    SDL_Renderer* renderer;int main(int argc, char* argv[]) {SDL_Rect rect;rect.x = 20; rect.y = 20; rect.w = 100; rect.h = 100;SDL_Init( SDL_INIT_EVERYTHING );                                                              // 初始化SDL2所有部分// win = SDL_CreateWindow( "MyWindow", 100, 100, 640, 480, SDL_WINDOW_SHOWN );  // 创建窗口SDL_CreateWindowAndRenderer( 640, 480, NULL, &win, &renderer );     // 创建窗口和渲染器// winSurface = SDL_GetWindowSurface( win );                                                   // 基于窗口创建“表面”// SDL_FillRect( winSurface, NULL, SDL_MapRGB( winSurface->format, 0, 0, 0 )); // 绘制矩形SDL_SetRenderDrawColor( renderer, 255, 0, 0, 255 );SDL_RenderFillRect(renderer, &rect);// SDL_UpdateWindowSurface( win ); // 更新窗口SDL_RenderPresent( renderer );  // 更新窗口while (1);  // 卡住界面(保持窗口)// 清理释放SDL_DestroyRenderer( renderer );SDL_DestroyWindow( win );return 0;
    }
    

    在这里插入图片描述

  5. 创建纹理

    因为上述讲了渲染可以通过表面结构或渲染器结构,所以有两种。在接下来的代码案例中,将只会介绍渲染器来进行渲染的结构。关于纹理,“纹理是表面的 GPU 渲染等效物”,应该寓意着纹理的渲染是通过GPU,且更高效的。

    下述代码只提供,纹理创建到渲染。像原教程中还举例有,纹理透明度改变,图形翻转以及改变模式之类的暂不列出。

    SDL_Rect rect;
    SDL_Window* win;
    SDL_Surface* image;
    SDL_Texture* texture;
    SDL_Renderer* renderer;int main(int argc, char* argv[]) {SDL_Init( SDL_INIT_EVERYTHING );                                                               // 初始化SDL2所有部分SDL_CreateWindowAndRenderer( 640, 480, NULL, &win, &renderer );     // 创建窗口和渲染器// 获取logo图片,并创建纹理image = SDL_LoadBMP( "D:\\Desktop\\MyData\\CLion\\Demo\\logo.bmp" );texture = SDL_CreateTextureFromSurface( renderer, image );SDL_FreeSurface( image );rect.x = 20; rect.y = 20; rect.w = 300; rect.h = 300;SDL_RenderCopy( renderer, texture, NULL, &rect );SDL_RenderPresent(renderer);// 清理释放SDL_DestroyRenderer( renderer );SDL_DestroyWindow( win );return 0;
    }

    在这里插入图片描述

  6. 声音和扩展库

    SDL虽然有着广泛的API,但是部分区域还是要借助扩展库。这里将介绍使用到SDL_ImageSDL_Mixer库。扩展库都需要导入其代码,这里暂时就先不介绍了。

    // SDL_Image
    IMG_Init( IMG_INIT_JPG | IMG_INIT_PNG );	// 初始化
    SDL_Surface* image = IMG_Load("image.png");	// 导入图片
    IMG_Quit();	// 销毁// SDL_Mixer
    Mix_OpenAudio( 44100, MIX_DEFAULT_FORMAT, 2, 1024 );	// 初始化
    /* 加载音频 */
    Mix_Music* music;
    Mix_Chunk* sound;
    music = Mix_LoadMUS("music.wav");	// 加载音乐
    sound = Mix_LoadWAV("sound.mp3");	// 加载声音
    /* 播放音乐 */
    Mix_PlayMusic( music, -1 );
    /* 播放声音 */
    Mix_PlayChannel( -1, sound, 0 );	
    Mix_Pause( channel );
    SDL_Delay( 1000 );
    Mix_Resume( channel );
    /* 销毁 */
    Mix_FreeChunk( sound );
    Mix_FreeMusic( music );
    Mix_Quit();
    
  7. 文本渲染和输入

    该功能也是基于扩展库,基于SDL_ttf.h

    SDL_Surface* text;
    SDL_Texture* text_texture;
    SDL_Color color = { 0, 0, 0 };/* 初始化 */
    TTF_Init();
    /* 渲染文本 */
    text = TTF_RenderText_Solid( font, "Hello World!", color );
    text_texture = SDL_CreateTextureFromSurface( renderer, text );
    SDL_Rect dest = { 0, 0, text->w, text->h };
    SDL_RenderCopy( renderer, text_texture, &dest );
    /* 文本输入 */
    SDL_StartTextInput();
    string in;
    bool running = true;while ( running ) {SDL_Event ev;while ( SDL_PollEvent( &ev ) ) {if ( ev.type == SDL_TEXTINPUTEVENT ) {in += ev.text.text;// cout << " > " << in << endl;} else if ( ev.type == SDL_KEYDOWN && ev.key.keysym.sym == SDLK_BACKSPACE && in.size()) {in.pop_back();// cout << " > " << in << endl;} eles if ( ev.type == SDL_QUIT ) {running = false;}}
    }SDL_StopTextInput();
    /* 关闭 */
    TTF_CloseFont( font );
    TTF_Quit();
    
  8. 计时:帧速率、物理、动画

    该章节讲到的概念案例都较为易懂,所以直接附上教程中的代码。现在先看个大概,可以在使用到的时候在多看看。

    /***** 定时 *****/
    Uint32 ticks = SDL_GetTicks();
    // ...中途操作
    Uint32 end = SDL_GetTicks();
    float secondsElapsed = (end - start) / 1000.0f;/***** 更高精度计数器 *****/
    Uint64 start = SDL_GetPerformanceCounter();
    // ...中途操作
    Uint64 end = SDL_GetPerformanceCounter();
    float secondsElapsed = (end - start) / (float)SDL_GetPerformanceFrequency();/***** 更高精度计数器 *****/
    bool running = true;
    while (running) {Uint64 start = SDL_GetPerformanceCounter();// 事件循环// 物理循环// 呈现循环Uint64 end = SDL_GetPerformanceCounter();float elapsed = (end - start) / (float)SDL_GetPerformanceFrequency();printf("Current FPS: %s\r\n",to_string(1.0f / elapsed));
    }/***** 限制FPS速率 *****/
    bool running = true;
    while (running) {Uint64 start = SDL_GetPerformanceCounter();// 事件循环// 物理循环// 呈现循环Uint64 end = SDL_GetPerformanceCounter();float elapsedMS = (end - start) / (float)SDL_GetPerformanceFrequency() * 1000.0f;// 上限为60FPSSDL_Delay(floor(16.666f - elapsedMS));}/***** 垂直同步 *****/
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED );/***** 物理 *****/
    bool running;
    Uint32 lastUpdate = SDL_GetTicks();while (running) {// 事件循环// 物理循环Uint32 current = SDL_GetTicks();// 计算dT(单位:秒)float dT = (current - lastUpdate) / 1000.0f;for ( /* 对象列表 */ ) {object.position += object.velocity * dT;}// 设置更新时间lastUpdate = current;// 呈现循环
    }/***** 动画 *****/
    float animatedFPS = 24.0f;
    bool running;while (running) {// 事件循环// 物理循环// 呈现循环Uint32 current = SDL_GetTicks();// 计算dT(单位:秒)for ( /* 对象列表 */ ) {float dT = (current - object.lastUpdate) / 1000.0f;int framesToUpdate = floor(dT / (1.0f / animatedFPS));if (framesToUpdate > 0) {object.lastFrame += framesToUpdate;object.lastFrame %= object.numFrames;object.lastUpdate = current;}render(object.frames[object.lastFrame]);}
    }
    

    资料

    原版教程用到的扩展库,和目前SDL最新稳定版的包

    SDL2-devel-2.30.11-mingw.zip * 1

    SDL2_image-devel-2.8.4-mingw.zip * 1

    SDL2_mixer-devel-2.7.2-mingw.zip * 1

    SDL2_ttf-devel-2.22.0-mingw.zip * 1

    链接: https://pan.baidu.com/s/1A8wkpUpnAkLihmaocIvxeA  提取码: v6wk


http://www.ppmy.cn/news/1565222.html

相关文章

(k8s)k8s部署mysql与redis(无坑版)

0.准备工作 在开始之前&#xff0c;要确保我们的节点已经加入网络并且已经准备好&#xff0c;如果没有可以去看我前面发表的踩坑与解决的文章&#xff0c;希望能够帮到你。 1.k8s部署redis 1.1目标 由于我们的服务器资源较小&#xff0c;所以决定只部署一个redis副本&#x…

亲测有效!如何快速实现 PostgreSQL 数据迁移到 时序数据库TDengine

小T导读&#xff1a;本篇文章是“2024&#xff0c;我想和 TDengine 谈谈”征文活动的优秀投稿之一&#xff0c;作者从数据库运维的角度出发&#xff0c;分享了利用 TDengine Cloud 提供的迁移工具&#xff0c;从 PostgreSQL 数据库到 TDengine 进行数据迁移的完整实践过程。文章…

Erlang语言的面向对象编程

Erlang语言的面向对象编程探索 引言 Erlang 是一种并发编程语言&#xff0c;最早由爱立信公司开发&#xff0c;用于电信系统的构建。由于其高可用性和容错能力&#xff0c;Erlang 在分布式系统、实时系统和大规模并发系统中得到了广泛应用。尽管 Erlang 的设计并不原生支持面…

AI刷题-小R的随机播放顺序、不同整数的计数问题

目录 一、小R的随机播放顺序 问题描述 测试样例 解题思路&#xff1a; 问题理解 数据结构选择 算法步骤 最终代码&#xff1a; 运行结果&#xff1a; 二、 不同整数的计数问题 问题描述 测试样例 解题思路&#xff1a; 问题理解 数据结构选择 算法步骤 最终…

Java设计模式 六 原型模式 (Prototype Pattern)

原型模式 (Prototype Pattern) 原型模式是一种创建型设计模式&#xff0c;通过复制现有对象来创建新对象&#xff0c;而不是直接实例化类。这种模式适用于创建成本较高的对象&#xff0c;或者需要重复创建相似对象的场景。 原型模式的核心思想是&#xff1a; 通过对象自身提供…

RestTemplate-调用远端接口应用场景

环境准备: Springboot项目 RestTemplate注入到项目中 Configurationpublic class Config {Beanpublic RestTemplate restTemplate() {return new RestTemplate(new OkHttp3ClientHttpRequestFactory());}}案例一: 使用get调用远程接口: 地址如: http://xxxx.xxx.xxx/xxx?a111&…

html与css学习笔记(2)

一、CSS引入方式 具体有 3 种引入方式&#xff0c;语法如下表格所示&#xff1a; 引入方式语法内联样式在HTML标签中使用style属性&#xff0c;例如&#xff1a;<div style"color: red;">这是一个红色的div</div>内部样式表在HTML文件的<head>标签…

Django学习笔记(安装和环境配置)-01

Django学习笔记(安装和环境配置)-01 一、创建python环境 1、可以通过安装Anaconda来创建一个python环境 # 创建一个虚拟python环境 conda create -n django python3.8 # 切换激活到创建的环境中 activate django2、安装django # 进入虚拟环境中安装django框架 pip install …