Sprites are rendered as bars

Good afternoon everyone. I’m doing a task - to write a game on SDL2. I faced a problem: sprites are vertically unsynchronized when rendering and all this turns into stripes. When I move the window or click the mouse, the sprites are rendered as they should be. Attached screenshots. I have never worked with SDL2 before. I couldn’t find a solution on google.

How my window looks:

I attached code below

main() function:

#include "Game.hpp"
 
int main(int argc, char* argv[])
{
    return run(new Game);
}

Class Game:

#include "Game.hpp"
 
Game::Game() : w(800), h(600), fullscr(false) {}
 
Game::Game(int width, int height, bool fullscreen) : w(width), h(height), fullscr(fullscreen) {}
 
void Game::PreInit(int& width, int& height, bool& fullscreen)
{
    width = w;
    height = h;
    fullscreen = fullscr;
}
 
bool Game::Init()
{
    doodle = createSprite("../assets/doodle/blue-lik-left.png");
    background = createSprite("../assets/bck.png");
    platform = createSprite("../assets/platform.png");
 
 
    // Random placement of platforms
    int plat_width{}, plat_height{};
    getSpriteSize(platform, plat_width, plat_height);
    srand(time(0));
    for (std::size_t i = 0; i < 10; ++i)
    {
        plat[i].x = rand() % w - plat_width;
        plat[i].y = rand() % h - plat_height;
    }
 
    return true;
}
 
void Game::Close()
{
    destroySprite(doodle);
    destroySprite(background);
    destroySprite(platform);
}
 
bool Game::Tick()
{
    drawTestBackground();
 
    drawSprite(background, 0, 0);
    drawSprite(doodle, doodle_pos.x, doodle_pos.y);
 
    for (std::size_t i = 0; i < 10; ++i)
        drawSprite(platform, plat[i].x, plat[i].y);
 
    return false;
}
 
void Game::onMouseMove(int x, int y, int xrelative, int yrelative)
{
}
 
void Game::onMouseButtonClick(FRMouseButton button, bool isReleased)
{
}
 
void Game::onKeyPressed(FRKey k)
{
}
 
void Game::onKeyReleased(FRKey k)
{
}
 
const char* Game::GetTitle()
{
    return "Doodle Jump";
}

run() function:

static SDL_Renderer *g_renderer;
static int g_width = 800;
static int g_height = 600;
static int g_framework_initialized = false;
 
FRAMEWORK_API int run(Framework* framework)
{
    SDL_Window *window;
    Uint32 flags;
    int done;
    SDL_Event event;
 
    for (int i = 0; i < (int)FRKey::COUNT; ++i)
    {
        GKeyState[i] = false;
    }
 
    Framework* GFramework = framework;
 
    bool fullscreen;
    GFramework->PreInit(g_width, g_height, fullscreen);
    
    flags = SDL_WINDOW_HIDDEN;
    if (fullscreen) {
        SDL_ShowCursor(0);
        flags |= SDL_WINDOW_FULLSCREEN;
    }
 
    if (SDL_Init(SDL_INIT_VIDEO) == -1) {
        fprintf(stderr, "SDL_Init(SDL_INIT_VIDEO) failed: %s\n", SDL_GetError());
        return(2);
    }
 
    if (SDL_CreateWindowAndRenderer(0, 0, flags, &window, &g_renderer) < 0) {
        fprintf(stderr, "SDL_CreateWindowAndRenderer() failed: %s\n", SDL_GetError());
        return(2);
    }
 
    {
        /* Show the window */
        SDL_SetWindowTitle(window, GFramework->GetTitle());
        SDL_SetWindowSize(window, g_width, g_height);
        SDL_ShowWindow(window);
 
        g_framework_initialized = true;
 
 
        if (!GFramework->Init())
        {
            fprintf(stderr, "Framework::Init failed\n");
            SDL_Quit();
            exit(1);
        }
 
        done = 0;
        while ( ! done ) {
            while ( SDL_PollEvent(&event) ) {
                switch (event.type) {
                    case SDL_KEYUP:
                        switch (event.key.keysym.sym) {
                            case SDLK_RIGHT:
                            case SDLK_LEFT:
                            case SDLK_DOWN:
                            case SDLK_UP:
                            {
                                int key_index = (event.key.keysym.sym - SDLK_RIGHT);
                                if (GKeyState[key_index])
                                {
                                    GFramework->onKeyReleased((FRKey)key_index);
                                    GKeyState[key_index] = false;
                                }
                                break;
                            }
                            case SDLK_ESCAPE:
                                done = 1;
                            break;
                            default:
                                break;
                        }
                        break;
                    case SDL_KEYDOWN:
                        switch (event.key.keysym.sym) {
                        case SDLK_RIGHT:
                        case SDLK_LEFT:
                        case SDLK_DOWN:
                        case SDLK_UP:
                        {
                            int key_index = (event.key.keysym.sym - SDLK_RIGHT);
                            if (!GKeyState[key_index])
                            {
                                GFramework->onKeyPressed((FRKey)key_index);
                                GKeyState[key_index] = true;
                            }
                        }
                            break;
 
                        default:
                            break;
                        }
                        break;
                    case SDL_MOUSEBUTTONDOWN:
                        if (event.button.button <= SDL_BUTTON_RIGHT) {
                            GFramework->onMouseButtonClick((FRMouseButton)(event.button.button - SDL_BUTTON_LEFT), false);
                        }
                        break;
                    case SDL_MOUSEBUTTONUP:
                        if (event.button.button <= SDL_BUTTON_RIGHT) {
                            GFramework->onMouseButtonClick((FRMouseButton)(event.button.button - SDL_BUTTON_LEFT), true);
                        }
                        break;
                    case SDL_MOUSEMOTION:
                        GFramework->onMouseMove(event.motion.x, event.motion.y, event.motion.xrel, event.motion.yrel);
                        break;
                    case SDL_QUIT:
                        done = 1;
                        break;
                    default:
                        break;
                }
            }
 
            SDL_RenderClear(g_renderer);
 
            SDL_Rect viewport;
            SDL_RenderGetViewport(g_renderer, &viewport);
 
            /* Draw a gray background */
            SDL_SetRenderDrawColor(g_renderer, 0xA0, 0xA0, 0xA0, 0xFF);
            SDL_RenderClear(g_renderer);
 
            done |= GFramework->Tick() ? 1 : 0;
 
            SDL_RenderPresent(g_renderer);
 
            SDL_Delay(1);
        }
    }
 
    GFramework->Close();
 
    SDL_DestroyRenderer(g_renderer);
    SDL_DestroyWindow(window);
 
    g_framework_initialized = false;
 
    /* We're done! */
    SDL_Quit();
    return(0);
}

I don’t have to change anything in the run() function at all. It’s kind of a part of the framework. And I don’t understand what the hell is going on))) Does anyone know what’s going on here? Thanks in advance for your help.

I’m not sure what is wrong here.

Maybe try removing the line flags = SDL_WINDOW_HIDDEN; and see if that makes a difference (I’m just guessing).

Otherwise, are you sure the sprite file paths are correct? Maybe try with absolute paths just to make sure.

I tried doing what you suggested, but it didn’t work.
The sprites are displayed normally when I move the window, resize it, click on it (screenshot). And when nothing happens, the sprites are broken up into stripes (effect like in games, if they have vertical synchronization turned off).
Screenshot 2024-01-25 193456

The way window looks when no events happen:
Screenshot 2024-01-25 193659

vertical synchronization = vsync ?

Doesn’t that normally only cause tearing? This phenomenon seems to be much more noticeable.

Yeah, that’s it. I just didn’t know what it was called.

There are many things that could potentially go wrong but without seeing the rest of the code I’m afraid I would just be guessing. It would be easier to help if you posted the complete code so that we could test it ourselves. If you don’t want to share the whole code maybe you could create a minimal example that is enough to be able to reproduce the bug?

How do I post the code? On github? I shouldn’t be doing this.
By the way, I noticed that this problem is not present in full screen mode.
Ok, I can make minimal example.

Ahahahahahahaha. I’m just in shock. I changed a lot of things, added things, removed things, googled, tried running on linux and windows - nothing worked. And then I put everything back the way it was and it worked! How is that possible?!

Probably undefined behaviour (UB). You did something wrong somewhere (e.g. accessed an array element out of bounds or dereferenced a dangling pointer) which corrupted memory or caused some other problems, possibly in a totally different part of the program.

When you changed the code you might have accidentally fixed or removed the underlying problem, but it’s also possible that you still have UB and when you change something else in the future it might cause problems again. Changing your compiler settings (e.g. turning on/off optimizations) might make a difference.

There are tools that you can use to find UB. On Linux you can use valgrind. Many modern compilers also come with sanitizers which you can use. If you use GCC, just compile with
-fsanitize=address,undefined and run the program and see if it finds any problems. These tools don’t catch all problems but they are still very useful and I don’t know what I would do without them.

I’ll still have a look at your code if you want (just post it on github or whatever) but it’s preferable if it’s a version where the bug still shows up otherwise there is a chance that the underlying problem was in one of the parts that you removed (even if it seemed unrelated) and then I would not be able to find it.

That your game is “escaping” the window (which shouldn’t happen, even if your game is completely broken!) could also be a driver or window compositor bug. Having vsync turned off should, at worst, cause tearing, but not what you’re seeing.

Also, you don’t need the line SDL_Delay(1) after calling SDL_RenderPresent()

What does your source control say that you changed? (if you aren’t using source control, take this as a hint to use it even for small projects that only you work on)

edit: So, in your code you create a hidden window with size 0, set its title and size, then show it. This could very well be confusing the window compositor or driver, which causes it to set the wrong clipping rectangle or something, and thus why your game is able to escape the window.

Just create the window with the size and title you want from the outset. No need to create it as hidden and then show it later, either.

edit 2: I also recommend creating the window and renderer separately, so you can specify creation flags for both the window and the renderer. And if renderer creation fails, you can tell the player and then try a different backend or software renderer as a fallback.