Home > OS >  Window closes only after clicking exit button multiple times?
Window closes only after clicking exit button multiple times?

Time:07-07

When I try to exit the window by clicking the X at the top corner, the program wouldn't end and just continue running. Only after repeatedly clicking the X button, the window managed to close. Why is this the case?

main.cpp:

#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include "window.hpp"
#include "utils.hpp"

int main(int argc, char *argv[]) {

    if (SDL_Init(SDL_INIT_VIDEO) > 0){
        std::cout << "SDL has failed to initialize." << std::endl;
        std::cout << "SDL ERROR: " << SDL_GetError() << std::endl;
    }

    if (!(IMG_Init(IMG_INIT_PNG))) {
        std::cout << "SDL image has failed to initialize." << std::endl;
        std::cout << "SDL_image ERROR: " << IMG_GetError() << std::endl;
    } 

    RenderWindow window("game", 950, 720);

    bool gameLoopRunning = true;
    SDL_Event event;

    const float deltaTime = 0.01f;
    float accumulator = 0.0f;
    float currentTime = utils::timeInSeconds();

    while (gameLoopRunning) {

        int startTicks = SDL_GetTicks();

        float newTime = utils::timeInSeconds();
        float frameTime = newTime - currentTime;
        currentTime = newTime;
        accumulator  = frameTime;

        while (accumulator >= deltaTime) {

            while (SDL_PollEvent(&event)) {
                
                switch(event.type) {
                    case SDL_QUIT:
                        gameLoopRunning = false;
                }
                accumulator -= deltaTime;
            }
        }

        const float alpha = accumulator / deltaTime;

        int frameTicks = SDL_GetTicks() - startTicks;
        if (frameTicks < 1000/window.getRefreshRate()) {
            SDL_Delay(1000/window.getRefreshRate() - frameTicks);
        }

    }
    
    window.cleanUp();
    SDL_Quit();

    return 0;
}

window.cpp:

RenderWindow::RenderWindow(const char* p_title, int p_width, int p_height)
: window(NULL), renderer(NULL) {

    window = SDL_CreateWindow(p_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 
    p_width, p_height, SDL_WINDOW_SHOWN);

    if (window == NULL) {
        std::cout << "Failed to create window: " << std::endl;
        std::cout << "SDL Error: " << SDL_GetError() << std::endl;
    }

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

}

int RenderWindow::getRefreshRate() {
    int displayIndex = SDL_GetWindowDisplayIndex(window);
    SDL_DisplayMode mode;

    SDL_GetDisplayMode(displayIndex, 0, &mode); 
    return mode.refresh_rate;
}


void RenderWindow::cleanUp() {
    SDL_DestroyWindow(window);
}

void RenderWindow::clear() {
    SDL_RenderClear(renderer);
}

utils.hpp:

namespace utils {
    
    inline float timeInSeconds() {
        float ticks = SDL_GetTicks();
        ticks *= 0.001f;
        return ticks;
    }
}

CodePudding user response:

Those two loops will not exit just because you clicked exit:

    while (accumulator >= deltaTime) {
        while (SDL_PollEvent(&event)) {
            switch(event.type) {
                case SDL_QUIT:
                    gameLoopRunning = false;
            }
            accumulator -= deltaTime;
        }
    }

The accumulator loop is especially likely to run for a while if you game is behind, in game time. You should make it explicit that you want to break out of those loops, and not just wait later:

    while (accumulator >= deltaTime && gameLoopRunning) {
        while (SDL_PollEvent(&event) && gameLoopRunning) {
            switch(event.type) {
                case SDL_QUIT:
                    gameLoopRunning = false;
            }
            accumulator -= deltaTime;
        }
    }

Notice the extra && gameLoopRunning.

  • Related