SDL绘制矩形异常:部分帧显示切片拉伸矩形问题求助
SDL绘制矩形出现拉伸切片异常的解决方法
问题原因
你遇到的异常是因为程序未处理窗口尺寸变化事件:当窗口被拖动时,系统会临时同步窗口缓冲区与显示区域,此时绘制正常;但停止拖动后,窗口缓冲区尺寸可能发生了变化,而你的代码始终使用固定的SCREEN_WIDTH和SCREEN_HEIGHT计算矩形位置,且未同步更新渲染器的适配逻辑,导致绘制内容与窗口实际显示区域不匹配,出现拉伸、切片的异常。
修复方案
- 监听
SDL_WINDOWEVENT_SIZE_CHANGED事件,实时获取窗口的实际尺寸 - 基于窗口当前尺寸计算矩形的位置与大小,替代固定常量
- 可选:通过
SDL_SetRenderLogicalSize设置渲染器逻辑尺寸,确保逻辑坐标与窗口物理坐标的映射一致
修改后的完整代码
#include <SDL2/SDL.h> #include <iostream> SDL_Window* gWindow = NULL; SDL_Renderer* gRenderer = NULL; int currentScreenWidth = 1280; int currentScreenHeight = 720; bool init() { bool success = true; if (SDL_Init(SDL_INIT_VIDEO) < 0) { std::cout << "SDL couldn't init! SDL_Error: " << SDL_GetError() << std::endl; success = false; } else { // 添加SDL_WINDOW_RESIZABLE标志,支持窗口调整 gWindow = SDL_CreateWindow("Snake", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, currentScreenWidth, currentScreenHeight, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); if (gWindow == NULL) { std::cout << "Window couldn't be created! SDL_Error: " << SDL_GetError() << std::endl; success = false; } else { // 添加SDL_RENDERER_PRESENTVSYNC避免画面撕裂 gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); if (gRenderer == NULL) { std::cout << "Renderer couldn't be created! SDL_Error: " << SDL_GetError(); success = false; } else { SDL_SetRenderDrawColor(gRenderer, 0x00, 0x00, 0x00, 0x00); // 设置渲染器逻辑尺寸,保持坐标映射一致 SDL_SetRenderLogicalSize(gRenderer, currentScreenWidth, currentScreenHeight); } } } return success; } bool loadMedia() { bool success = true; return success; } void close() { SDL_DestroyRenderer(gRenderer); SDL_DestroyWindow(gWindow); gWindow = NULL; gRenderer = NULL; SDL_Quit(); } int main(int argc, char* args[]) { if (!init()) { std::cout << "Failed to init!" << std::endl; } else { SDL_Event e; bool quit = false; while(!quit) { while( SDL_PollEvent( &e ) != 0 ){ if( e.type == SDL_QUIT ) { quit = true; } // 处理窗口尺寸变化事件 else if (e.type == SDL_WINDOWEVENT) { if (e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { currentScreenWidth = e.window.data1; currentScreenHeight = e.window.data2; // 更新渲染器逻辑尺寸,适配新窗口大小 SDL_SetRenderLogicalSize(gRenderer, currentScreenWidth, currentScreenHeight); } } } SDL_SetRenderDrawColor(gRenderer, 0x00, 0x00, 0x00, 0x00); SDL_RenderClear(gRenderer); // 基于当前窗口尺寸计算居中矩形 SDL_Rect fillRect = {currentScreenWidth / 4, currentScreenHeight / 4, currentScreenWidth / 2, currentScreenHeight / 2 }; SDL_SetRenderDrawColor(gRenderer, 0x00, 0xFF, 0x00, 0xFF); SDL_RenderFillRect(gRenderer, &fillRect); SDL_RenderPresent(gRenderer); } } close(); return 0; }
关键修改说明
- 将固定尺寸常量改为可变的
currentScreenWidth和currentScreenHeight,实时同步窗口实际大小 - 创建窗口时添加
SDL_WINDOW_RESIZABLE标志,支持窗口手动调整(可选,但提升兼容性) - 新增
SDL_WINDOWEVENT_SIZE_CHANGED事件处理,更新窗口尺寸并同步渲染器逻辑尺寸 - 渲染器创建时添加
SDL_RENDERER_PRESENTVSYNC,避免画面撕裂问题 - 使用
SDL_SetRenderLogicalSize确保无论窗口如何缩放,逻辑坐标与物理坐标的映射始终一致,矩形保持居中且比例正确
内容的提问来源于stack exchange,提问作者Evan Marsh
相关产品推荐
相关产品推荐

