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

SDL2窗口失焦时矩形动画停止,如何实现持续运行?

解决SDL矩形仅在输入时移动的问题

嘿,我一眼就看出问题所在了——你把矩形的更新和渲染逻辑全都塞进了SDL_PollEvent的循环内部!

问题根源

SDL_PollEvent()的循环只会在有事件发生(比如鼠标移动、按键按下、窗口关闭)的时候执行迭代。没有事件的时候,这个循环根本不会跑,你的矩形自然就停住了。要让动画持续运行,必须把状态更新和渲染逻辑移到事件循环的外面,放在主游戏循环里,这样不管有没有输入事件,每一次主循环都会执行更新和渲染操作。

修改后的完整代码

#include <stdio.h> 
#include <SDL_image.h> 
#include <SDL.h> 

const int SCREEN_WIDTH = 640; 
const int SCREEN_HEIGHT = 480; 

SDL_Window *gWindow = nullptr; 
SDL_Renderer *gRenderer = nullptr; 

bool init() { 
    bool in = true; 
    if (SDL_Init(SDL_INIT_VIDEO)<0) { 
        printf("SDL_ did not init, %s", SDL_GetError()); 
        in = false; 
    } else { 
        if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1")) { 
            printf("linear texture filtering boned.\n"); 
            in = false; 
        } else { 
            gWindow = SDL_CreateWindow("CELLULA_CHARLIE", 1000, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN | SDL_WINDOW_ALWAYS_ON_TOP); 
            if (gWindow == nullptr) { 
                printf("gwindow did not load, %s", SDL_GetError()); 
                in = false; 
            } else { 
                gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); 
                if (gRenderer == nullptr) { 
                    printf("main renderer failed loading, %s", SDL_GetError()); 
                    in = false; 
                } else { 
                    SDL_SetRenderDrawColor(gRenderer, 255, 255, 255, 255); 
                    int imgFlags = IMG_INIT_PNG; 
                    if (!(IMG_Init(imgFlags)&imgFlags)) { 
                        printf("Img did not init, %s", IMG_GetError()); 
                        in = false; 
                    } 
                } 
            } 
        } 
    } 
    return in; 
} 

void close() { 
    SDL_DestroyRenderer(gRenderer); 
    SDL_DestroyWindow(gWindow); 
    gWindow = nullptr; 
    gRenderer = nullptr; 
    IMG_Quit(); 
    SDL_Quit(); 
} 

int main(int argc, char*args[]) { 
    int i = 0; 
    SDL_Rect rectangle; 
    rectangle.h = rectangle.w = 32; 
    rectangle.x = rectangle.y = 0; 

    if (!init()) { 
        printf("init failed\n"); 
    } else { 
        bool quit = false; 
        SDL_Event e; 

        while (!quit) { 
            // 单独处理事件,只负责响应输入/系统事件
            while (SDL_PollEvent(&e) != 0) { 
                if (e.type == SDL_QUIT) { 
                    quit = true; 
                } 
            } 

            // 状态更新:移动矩形
            rectangle.x = i * 32; 
            rectangle.y = rectangle.x; 
            i++; 
            if (rectangle.x > 500) { 
                i = 0; 
            } 

            // 渲染流程:清屏→绘制矩形→显示画面
            SDL_SetRenderDrawColor(gRenderer, 255, 255, 255, 255); 
            SDL_RenderClear(gRenderer); 

            SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 255); 
            SDL_RenderFillRect(gRenderer, &rectangle); 

            SDL_RenderPresent(gRenderer); 

            // 可选:添加延迟控制移动速度,否则会非常快
            SDL_Delay(30); 
        } 
    } 

    close(); 
    return 0; 
}

关键修改点

  1. 拆分循环结构:把事件处理、状态更新、渲染分成三个独立的部分,都放在主while(!quit)循环内,但事件处理是单独的子循环。
  2. 控制帧率:添加了SDL_Delay(30)让矩形移动速度更合理(大约30帧/秒),你可以根据需求调整这个数值。
  3. 逻辑分离:事件处理只负责处理退出等事件,更新和渲染逻辑每次主循环都会执行,保证动画持续运行。

额外优化建议

如果想要更精确的帧率控制,推荐使用SDL_GetTicks()来计算时间差,替代固定的SDL_Delay,这样可以让动画在不同性能的设备上保持一致的速度。比如:

Uint32 lastTime = SDL_GetTicks();
const int FPS = 30;
const int frameDelay = 1000 / FPS;

while (!quit) {
    Uint32 currentTime = SDL_GetTicks();
    Uint32 frameTime = currentTime - lastTime;

    // ...事件处理、更新、渲染逻辑...

    if (frameTime < frameDelay) {
        SDL_Delay(frameDelay - frameTime);
    }
    lastTime = currentTime;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:48:59