Search code examples
c++sfml

sfml event::close called when window starts


When creating the sfml window for some reason the sf::Event::Closed is called and then closes the window is there anyway to fix this?

Also note that sometimes when changing the sfml functions and recompiling and running for the first time this issue doesn't occur only after the second run and so on

  • Note i am still learning sfml and c++

here is snakepart header

struct  snakepart{

    int x, y;
    snakepart(int col, int row);
    snakepart();
};

here is the main function

#include "Snake.cpp"

int main() {
        SnakeClass s;
        s.start();
        return 0;
    }

here is the main header file with most file declarations

#include "SnakePart.hpp"
#include <vector>
enum class Keys {
    key_up,
    key_down,
    key_left,
    key_right,
    quit,
    nothing,
    };
class IsdlClass {

public:
    virtual bool    OnInit() = 0;
    virtual Keys    OnEvent() = 0;
    virtual void    OnCleanup() = 0;
    virtual bool    pollEvent() = 0;
};

#endif

here is the header file for the SFML functions

#include "../libsfmld/include/SFML/Window.hpp"
#include "../libsfmld/include/SFML/Graphics.hpp"
#include "../../includes/IFunctions.hpp"

class SFML :public IsdlClass {

public:
    SFML();
    virtual ~SFML();
    virtual bool    OnInit();
    virtual Keys    OnEvent();
    virtual void    OnCleanup();
    virtual bool    pollEvent();
    sf::RenderWindow window;

private: 

    sf::ContextSettings settings;
    sf::Event event;

};

extern "C"   {
    SFML    *start(void);
    void        deletesdl(SFML *sfml);
}

#endif

here is the header for the snake functions

#include <iostream>
#include <vector>
#include <unistd.h>

#include "IFunctions.hpp"

class SnakeClass{

public:
    SnakeClass();
    ~SnakeClass();
    int    start();
    int     points, delay, maxW, maxH;
    char    direction, body, border, foodItem;
    bool    get;
    snakepart food;
    std::vector<snakepart> snake;
    void    dlerror_wrapper();

private:
    void    putfood();
    bool    collision();
    void    movesnake(Keys key);
    IsdlClass   *SFML;
    void    *dl_handle;
    bool    Running;
};

#endif

Below is the code used to call the SFML functions.

  snakepart::snakepart(int col, int row) {

        x = col;
        y = row;
    }

    snakepart::snakepart() {

        x = 0;
        y = 0;
    }  


bool    SnakeClass::collision() {

        if (snake[0].x == 0 || snake[0].x == maxW / 10 - 1 || snake[0].y == 0 || snake[0].y == maxH / 10 - 3)
            return true;
        for (size_t i = 2; i < snake.size(); i++)
            if (snake[0].x == snake[i].x && snake[i].y == snake[0].y)
                return true;
        if (snake[0].x == food.x && snake[0].y == food.y) {

            get = true;
            // points += 10;
            // char c[5];
            // sprintf(c, "%d", points);
            if ((points%50) == 0 && delay > 0)
                delay -= 10;
        }else 
            get = false;
        return false;
    }

    void    SnakeClass::movesnake(Keys key) {

            while(this->SFML->pollEvent()) {
                std::cout << "after poll event\n";
                    switch(key)
                    {
                        case Keys::key_left:
                                if(direction!='r')
                                        direction='l';
                                break;
                        case Keys::key_up:
                                if(direction !='d')
                                        direction='u';
                                break;
                        case Keys::key_down:
                                if(direction!='u')
                                        direction='d';
                                break;
                        case Keys::key_right:
                                if(direction!='l')
                                        direction='r';
                                break;
                        case Keys::quit: //this is called when window is opened
                                direction = 'q';
                                break;
                        default:
                               break;
                    }
                if (key == Keys::nothing)
                    continue;
            }
        }

        void    SnakeClass::dlerror_wrapper(void) {
            std::cerr << "Error: " << dlerror() << std::endl;
            exit(EXIT_FAILURE);
        }

        int    SnakeClass::start() {
            dl_handle = dlopen("sfml/libsfml.dylib", RTLD_LAZY);
            IsdlClass * (*func)(void);
            func = (IsdlClass * (*)(void)) dlsym(dl_handle, "start");
            if (!func)
                dlerror_wrapper();
            this->SFML = NULL;
            this->SFML = func();
            if (this->SFML == NULL)
                std::cout << "error\n";
            maxH = 480;
            maxW = 640;
            if (this->SFML->OnInit() == false)
               Running = false;
            for (int i = 0; i < 5; i++)
                snake.push_back(snakepart(40 + i, 10));
            points = 0;
            delay = 110;
            get = false;
            direction = 'l'; //snake moves to the left
            srand(time(NULL));
                while(Running)
                {

                    if(collision())
                    {
                        std::cout << "game over" << std::endl;
                        break;
                    }
                    // while(this->SFML->pollEvent()) {
                        // std::cout << " events\n";
                        movesnake(this->SFML->OnEvent());
                    // }
                    // 
                    if(direction=='q')
                            break;
                }
            void    (*del)(IsdlClass *);
            del = (void (*)(IsdlClass *)) dlsym(dl_handle, "deletesdl");
            dlclose(dl_handle);
           return (0);
        }

below is the SFML graphics functions *Note i am returning enums for the above function

    bool    SFML::pollEvent() {
        return (window.pollEvent(event));
}

bool    SFML::OnInit() {
    settings.antialiasingLevel = 8;
    window.create(sf::VideoMode(640, 480), "My window", sf::Style::Default, settings);
    window.setVerticalSyncEnabled(true);
    return true;
}

Keys    SFML::OnEvent() {

    window.setKeyRepeatEnabled(false);
    switch(event.type) {
            case sf::Event::Closed:
            std::cout << "Event close\n"; //this is called and returns the enum quit
                return (Keys::quit);
                break;
            case sf::Event::KeyPressed:
                if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
                {
                    std::cout <<"a\n";
                    return (Keys::key_left);
                }
                else if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
                {
                    std::cout <<"d\n";
                    return (Keys::key_right);
                }
                else if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
                {
                    std::cout <<"s\n";
                    return (Keys::key_down);
                }
                else if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
                {
                    std::cout <<"w\n";
                    return (Keys::key_up);
                }
                else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
                {
                    return (Keys::quit);
                }
                break;
            default:
                break;
        }
}



SFML    *start() {
    std::cout << "create\n";
    return new SFML();
}

void    deletesdl(SFML *sfml) {
    delete sfml;
}

P.S I am having to call it using its dynamic library and keep the game logic and the graphic libraries separate from each other


Solution

  • You have an issue on the order that some of your functions are being called. When you do:

    movesnake(this->SFML->OnEvent());
    

    OnEvent will be called first, followed by movesnake. However, since you've never polled before hand and OnEvent is using your event variable, anything can happen. Indeed, event is never properly filled by window.pollEvent, therefor you have undefined behavior.

    In the end, OnEvent returns the Keys::quit because UB, and so movesnake handle it as such. Move the polling outside of movesnake(possibly in OnEvent, just before handling the events) can solve the problem.