无法在 C 中的 SDL2 中绘制正方形数组

Not able to draw an array of squares in SDL2 in C

我正在使用 C 语言的 SDL2 根据数组 (terrain[something][something]) 绘制不同颜色的方块。但是当我 运行 它时,会发生一个红色方块被绘制在左上方,然后 window 停止响应。

基本上我正在做的是使用几个 for 循环遍历数组,并根据给定元素的值,每次在不同的位置绘制一个不同颜色的方块。我实际上不确定我绘制的东西是否会在我绘制下一个时自动清除,因为我使用相同的矩形结构。

int terrain_print()
{
    if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
    {
        printf("Error initializing SDL: %s\n", SDL_GetError());
        return 0;
    }
    SDL_Window* wind = SDL_CreateWindow("Terrain Generator",
        SDL_WINDOWPOS_CENTERED,
        SDL_WINDOWPOS_CENTERED,
        WIDTH, HEIGHT, 0);
    if (!wind)
    {
        printf("Error creating window: %s\n", SDL_GetError());
        SDL_Quit();
        return 0;
    }
    Uint32 render_flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC;
    SDL_Renderer* rend = SDL_CreateRenderer(wind, -1, render_flags);
    if (!rend)
    {
        printf("Error creating renderer: %s\n", SDL_GetError());
        SDL_DestroyWindow(wind);
        SDL_Quit();
        return 0;
    }
    bool running = true;
    float x_pos = 0, y_pos = 0;
    SDL_Rect rect = { (int)x_pos, (int)y_pos, PIXELSIZE, PIXELSIZE };
    SDL_Event event;
    while (running)
    {
        while (SDL_PollEvent(&event))
        {
            switch (event.type)
            {
                case SDL_QUIT:
                    running = false;
                    break;
            }
        }
        for (int i = ARRAYH - 1; i >= 0; i--)
        {
            for (int j = 0; j < ARRAYW; j++)
            {
                switch (terrain[i][j])
                {
                    case air:
                        SDL_SetRenderDrawColor(rend, 75, 163, 255, 255);
                    case grass:
                        SDL_SetRenderDrawColor(rend, 0, 181, 16, 255);
                    case dirt:
                        SDL_SetRenderDrawColor(rend, 74, 26, 0, 255);
                    case stone:
                        SDL_SetRenderDrawColor(rend, 85, 85, 85, 255);
                }
                SDL_SetRenderDrawColor(rend, 255, 0, 0, 255);
                SDL_RenderFillRect(rend, &rect);
                SDL_RenderPresent(rend);
                SDL_Delay(1000 / FPS);
                x_pos += PIXELSIZE;
            }
            y_pos += PIXELSIZE;
        }
    }
    SDL_DestroyRenderer(rend);
    SDL_DestroyWindow(wind);
    SDL_Quit();
    return 0;
}

正如其他人在评论部分中指出的那样,您的 switch 语句中可能缺少 break 语句。但是,即使您有这些 break 语句,整个 switch 语句的内容也会通过在以下行中将颜色改回红色来覆盖:

SDL_SetRenderDrawColor(rend, 255, 0, 0, 255);

此外,您必须更新 rect.xrect.y,而不是更新 x_posy_pos。否则,您将始终覆盖同一个矩形。

另一个问题可能是根据 SDL_RenderPresent, it is recommended to call SDL_RenderClear before starting each new frame's drawing. The documentation states that you should not rely on the previous frame's contents still existing in the backbuffer, when you start drawing the next frame. However, you seem to be relying on this. Even if your program works on your computer without calling SDL_RenderClear, it may stop working when you change the configuration or run the program on a different platform. I assume that this warning was put in the documentation for a good reason. Therefore, you might want to change your algorithm to render everything in one frame, or, if you want maintain the appearance of a new rectangle being added in one frame, render all rectangles from the previous frames in the new frame. Alternatively, you could use SDL_SetRenderTarget 上的官方文档呈现到 SDL_Texture 而不是直接呈现到屏幕,这样您就可以确保内容永远不会丢失。


and then the window stops responding.

这并不奇怪。您正在为每个 terrain 元素调用一次 SDL_RenderPresentSDL_Delay,即每次最内层循环迭代一次。每帧渲染之间有 1000 / FPS 毫秒的停顿。根据 terrain 数组的大小(您未在发布的代码中显示),渲染所有这些帧的总时间可能为数秒。在此期间,您不处理事件。只要您不处理事件,您的 window 就会没有响应。在呈现整个 terrain 数组后,您只能在外循环中再次开始处理事件。

不使用 SDL_Delay,我建议您使用 SDL_AddTimer. That way, a callback function will be called when it is time to render the next frame. Meanwhile, you can process events and your window will be responsive. I recommend that your callback function should do nothing more than call SDL_PushEvent with an application-defined event (registered using SDL_RegisterEvents), while your main thread is waiting for these and other possible events using SDL_WaitEvent

或者,在帧之间调用 SDL_PumpEvents 应该足以保持 window 响应。但是如果你希望能够响应事件,上段提到的解决方案更干净。

另一种选择是使用函数 SDL_PollEvent,它隐式调用 SDL_PumpEvents 并允许您在不阻塞的情况下检查新事件。