You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
}

关键修改说明

  1. 将固定尺寸常量改为可变的currentScreenWidth和currentScreenHeight,实时同步窗口实际大小
  2. 创建窗口时添加SDL_WINDOW_RESIZABLE标志,支持窗口手动调整(可选,但提升兼容性)
  3. 新增SDL_WINDOWEVENT_SIZE_CHANGED事件处理,更新窗口尺寸并同步渲染器逻辑尺寸
  4. 渲染器创建时添加SDL_RENDERER_PRESENTVSYNC,避免画面撕裂问题
  5. 使用SDL_SetRenderLogicalSize确保无论窗口如何缩放,逻辑坐标与物理坐标的映射始终一致,矩形保持居中且比例正确

内容的提问来源于stack exchange,提问作者Evan Marsh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 00:04:53