SDL(C)-没有事件循环就不会出现窗口

时间:2019-11-23 23:03:19

标签: c sdl

我正在尝试制作一个程序,该程序在窗口中呈现几个彩色矩形,然后在几秒钟后消失。基本上,应该出现以下内容(尽管我遇到了问题,我将在短期内首先解释如何实现它):

The result (I'm new here by the way, is it possible to directly show images in a post instead of having to just include a link to it?)

我要运行的代码如下,显然可以包含以及“ WINDOW_WIDTH”和“ WINDOW_HEIGHT”的定义,它们都出现在了下面的代码(分别设置为800和640)。

SDL_Window *window;
SDL_Renderer *renderer;

SDL_Init(SDL_INIT_VIDEO);

window = SDL_CreateWindow("Game Window", 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0);

if (window == NULL) {
        // In the case that the window could not be made...
        printf("Could not create window: %s\n", SDL_GetError());
        return 1;
    }

renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

SDL_RenderClear(renderer);


SDL_SetRenderDrawColor(renderer, 140, 0, 100, 100);

SDL_Rect rect = { 0, 0, 800, 640 };

SDL_RenderFillRect(renderer, &rect);

SDL_SetRenderDrawColor(renderer, 60, 0, 255, 100);

SDL_Rect rect2 = { 40, 40, 720, 560 };

SDL_RenderFillRect(renderer, &rect2);

SDL_SetRenderDrawColor(renderer, 50, 140, 0, 100);

SDL_Rect rect3 = { 80, 80, 640, 480 };

SDL_RenderFillRect(renderer, &rect3);

SDL_SetRenderDrawColor(renderer, 200, 50, 25, 0);

SDL_Rect rect4 = { 120, 120, 560, 400 };

SDL_RenderFillRect(renderer, &rect4);

SDL_RenderPresent(renderer);

SDL_Delay(2000);

SDL_DestroyWindow(window);

SDL_DestroyRenderer(renderer);

SDL_Quit();
return 0;

该代码似乎应该可以正常工作,并且实际上对上述视频中的人也适用(像我一样,他在MacOS上使用Xcode运行此代码,尽管它的版本较旧)。但是,当我运行编写的代码时,视频中发生的同样的事情似乎并没有发生。相反,窗口根本不会出现。代码本身确实可以运行,并且就此而言,它没有任何错误或警告,完全可以正常运行,但是带有彩色矩形的窗口在延迟结束和SDL窗口被破坏之前根本不显示。

我意识到这个问题以前曾在这个网站上被问过,每个问题都有非常相似的问题,我需要弄清楚,是的,我尝试使用事件循环来代替,并且效果很好。例如,如果我运行以下代码,则该代码与第一批代码相同,只是将“ SDL_DELAY”替换为事件处理程序,该事件处理程序可检测何时按下键盘或鼠标(并且对于布尔值还包括变量)-窗口显示得很好:

SDL_Window *window;
SDL_Renderer *renderer;

SDL_Init(SDL_INIT_VIDEO);

window = SDL_CreateWindow("Game Window", 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0);

if (window == NULL) {
        // In the case that the window could not be made...
        printf("Could not create window: %s\n", SDL_GetError());
        return 1;
    }

renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

SDL_RenderClear(renderer);


SDL_SetRenderDrawColor(renderer, 140, 0, 100, 100);

SDL_Rect rect = { 0, 0, 800, 640 };

SDL_RenderFillRect(renderer, &rect);

SDL_SetRenderDrawColor(renderer, 60, 0, 255, 100);

SDL_Rect rect2 = { 40, 40, 720, 560 };

SDL_RenderFillRect(renderer, &rect2);

SDL_SetRenderDrawColor(renderer, 50, 140, 0, 100);

SDL_Rect rect3 = { 80, 80, 640, 480 };

SDL_RenderFillRect(renderer, &rect3);

SDL_SetRenderDrawColor(renderer, 200, 50, 25, 0);

SDL_Rect rect4 = { 120, 120, 560, 400 };

SDL_RenderFillRect(renderer, &rect4);

SDL_RenderPresent(renderer);

SDL_Event e;
bool quit = false;
while (!quit){
    while (SDL_PollEvent(&e)){
        if (e.type == SDL_QUIT){
            quit = true;
        }
        if (e.type == SDL_KEYDOWN){
            quit = true;
        }
        if (e.type == SDL_MOUSEBUTTONDOWN){
            quit = true;
        }
    }
}

SDL_DestroyWindow(window);

SDL_DestroyRenderer(renderer);

SDL_Quit();
return 0;

然而,这与第一次尝试要实现的目标不同,正如我所说的,这是一个渲染的窗口,经过一段时间后便被破坏了。如果我不能使用上面显示的第一组代码,我应该怎么做呢?此外,为什么使用SDL_DELAY进行的这种设置显然对视频中的人有效(为了方便起见,可以再次找到here),但是当我尝试输入时却无效?

1 个答案:

答案 0 :(得分:1)

您是对的,之前曾多次被问到。简短的答案是“窗口管理器的行为有所不同,更糟糕的是,他们可能启用了合成”。基本上,您创建窗口,开始绘制,告诉窗口管理器您已经完成,并且一段时间后,您会收到信号,表明您认为正在绘制的窗口是刚刚创建的,因此请您重新绘制要显示的内容。当调整窗口大小,从最小化状态还原,被其他窗口遮盖等等时,会发生相同的事情-这始终是一件事情,简单的3行示例只是忽略了它;窗口管理器不负责保存您的图像,只要发生任何事情,它只会向您发送重新绘制的信号(这并不意味着它不允许出于自己的目的保留图像,主要用于合成,预览等)。在合成年龄之前,它“大部分时间都有效”。

窗口管理器还可能依赖于目标应用程序的事件处理来显示“应用程序无响应”对话框。

因此,实际上您的第二个版本仍然不正确,因为您只绘制了一次,而不关注重新绘制事件。游戏通常不会打扰这些事件,因为它们的图像反而是非常动态的,可以无条件重绘。您不仅需要事件循环,还需要重绘。

关于如何在经过一段时间后中断循环-您需要查看时间以及经过给定间隔后触发quit或以其他方式中断循环。除了操作系统提供的时间功能外,还有SDL_GetTicksSDL_AddTimer等。

这里是一个例子:

#include <SDL2/SDL.h>
#include <stdio.h>
#include <stdbool.h>

#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600

int main(int argc, char **argv) {
    SDL_Window *window;
    SDL_Renderer *renderer;

    SDL_Init(SDL_INIT_VIDEO);

    window = SDL_CreateWindow("Game Window", 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0);
    if (window == NULL) { return 1; }

    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    if (renderer == NULL) { return 1; }

    const Uint32 time_started = SDL_GetTicks();
    SDL_Event e;
    bool quit = false;
    while (!quit){
        // check for timeout
        if(SDL_GetTicks() - time_started > 2000) { quit = true; }

        while (SDL_PollEvent(&e)){
            if (e.type == SDL_QUIT){
                quit = true;
            }
            if (e.type == SDL_KEYDOWN){
                quit = true;
            }
            if (e.type == SDL_MOUSEBUTTONDOWN){
                quit = true;
            }
        }

        // break early - doesn't really matter
        if(quit) { break; }

        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
        SDL_RenderClear(renderer);
        SDL_SetRenderDrawColor(renderer, 140, 0, 100, 100);
        SDL_Rect rect = { 0, 0, 800, 640 };
        SDL_RenderFillRect(renderer, &rect);
        SDL_SetRenderDrawColor(renderer, 60, 0, 255, 100);
        SDL_Rect rect2 = { 40, 40, 720, 560 };
        SDL_RenderFillRect(renderer, &rect2);
        SDL_SetRenderDrawColor(renderer, 50, 140, 0, 100);
        SDL_Rect rect3 = { 80, 80, 640, 480 };
        SDL_RenderFillRect(renderer, &rect3);
        SDL_SetRenderDrawColor(renderer, 200, 50, 25, 0);
        SDL_Rect rect4 = { 120, 120, 560, 400 };
        SDL_RenderFillRect(renderer, &rect4);
        SDL_RenderPresent(renderer);
    }

    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}