Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: event.type only executes every once in a while instead of when a key is press  (Read 1233 times)

0 Members and 1 Guest are viewing this topic.

FacuRot

  • Newbie
  • *
  • Posts: 3
    • View Profile
    • Email
I'm trying to make a ship shoot every time the space key is press but the thing is that the pressing of the key is detect randomly.
The game class is the one that manage the differents screens of the game and the PlayScene class is the one that manage the behavior of the different entities. the problem is in the ProcessEvent() function.

here's the code:

Game.h
/***
 * Clase para manejar un bucle de juego con distintas escenas
 */

class Game {
public:
        /// comenzar el bucle de juego
        void run();
       
        /// cambiar la escena actual por otra
        void switchScene(BaseScene *scene);
       
        /// obtener la instancia de juego (singleton)
        static Game &getInstance();
       
        /// crear un juego especificando el modo de video y la escena inicial
        static Game &create(const sf::VideoMode &videoMode, BaseScene *scene, const string &name = "");

private:       
        sf::RenderWindow window;
        BaseScene *currentScene, *nextScene;
        sf::Clock clock;
       
        void processEvents();
        void update();
        void draw();
        static Game *instance;
        Game();
};

#endif
 

Game.cpp
Game *Game::instance = nullptr;
Game::Game(){}

Game &Game::create(const sf::VideoMode &videoMode, BaseScene *scene, const string &name){
        if(instance){
                cerr<<"ERROR: can't call create(), game already running."<<endl;
        }else{
                Game & g = getInstance();
                g.window.create(videoMode, name, sf::Style::Close);
                g.nextScene = nullptr;
                g.currentScene = scene;
                g.window.setFramerateLimit(60);
                g.clock.restart();
        }
        return getInstance();
}


Game &Game::getInstance(){
        if(!instance){
                instance = new Game();
        }
        return *instance;
}

void Game::run(){
        while(window.isOpen() && currentScene != nullptr) {
                sf::Event e;
                while(window.pollEvent(e)){
                        if(e.type == sf::Event::Closed){
                                window.close();
                        }
                }
                update();
                processEvents();
                draw();
                if(nextScene != nullptr){
                        delete currentScene;
                        currentScene = nextScene;
                        nextScene = nullptr;
                }
        }
}




void Game::update(){
        currentScene->update(clock.getElapsedTime().asSeconds());
        clock.restart();
}

void Game::processEvents(){
        currentScene->processEvent(window);
}

void Game::draw(){
        window.clear(sf::Color(0,0,0,255));
        currentScene->draw(window);
        window.display();
}

void Game::switchScene(BaseScene *scene){
        nextScene = scene;
}
 

BaseScene.h
class BaseScene {
public:
        /// constructor
        BaseScene();
       
        /// función que será invocada para actualizar la escena
        virtual void update(float elapsed);
       
        virtual void processEvent(sf::RenderWindow &w);
       
        /// función que será invocada para dibujar la escena
        virtual void draw(sf::RenderWindow &w);

        /// agrega un nuevo actor a la escena
        void add(Entity *e);
       
        /// eliminar un actor de la escena
        void remove(Entity *e);
       
private:
        vector<Entity *> entities;
        vector<Entity *> to_delete;
};

#endif
 

BaseScene
BaseScene::BaseScene() {
       
}

void BaseScene::update(float elapsed) {
        for(auto e: entities){
                e->update(elapsed);
        }
       
        // elimina actores
        for(auto d: to_delete){
                auto it = find(entities.begin(), entities.end(), d);
                if(it != entities.end()){
                        entities.erase(it);
                }
        }
        to_delete.clear();
}

void BaseScene::processEvent(sf::RenderWindow &w){
       
}

void BaseScene::draw(sf::RenderWindow &w){
        for(auto e: entities){
                e->draw(w);
        }
}

void BaseScene::add(Entity *e){
        entities.push_back(e);
}

void BaseScene::remove(Entity *e){
        to_delete.push_back(e);
}
 

PlayScene.h
class PlayScene : public BaseScene {
private:
        ScrollingBackground background;
        Player player;
        std::vector<Enemy> enemies;
        std::vector<Bullet> bullets;
public:
        PlayScene();
       
        void update (float elapsed);
        void processEvent(sf::RenderWindow &w);
        void draw (sf::RenderWindow & w);
};
 

PlayScene.cpp
PlayScene::PlayScene() {
        for (int i=0; i<5; i++){
                Enemy *enemy = new Enemy();
                enemies.push_back(*enemy);
        }
}

void PlayScene::processEvent(sf::RenderWindow &w){
        sf::Event event;
        while(w.pollEvent(event)){
                if (event.type == sf::Event::KeyPressed){
                        if (event.key.code == sf::Keyboard::Space){
                                Bullet *bullet = new Bullet(player.getPosition().x, player.getPosition().y);
                                bullet->setRotation(-90);
                                bullet->setSpeed();
                                bullets.push_back(*bullet);
                        }
                }
        }
}

void PlayScene::update (float elapsed) {
        BaseScene::update(elapsed);
       
        background.update(elapsed);
       
        player.update(elapsed);
       
        for (size_t i=0; i<enemies.size(); i++){
                enemies[i].update(elapsed);
               
                if (enemies[i].fireEvent(elapsed)){
                        Bullet *bullet = new Bullet(enemies[i].getPosition().x-25, enemies[i].getPosition().y-34);
                        bullets.push_back(*bullet);
                }
        }
       
        for (size_t i=0; i<bullets.size(); i++){
                bullets[i].update(elapsed);
               
                if (bullets[i].getPosition().y >480+5){
                        bullets.erase(bullets.begin() + i);
                }
               
                if (bullets[i].getBounds().intersects(player.getBounds())){
                        player.getHit();
                        bullets.erase(bullets.begin()+i);
                }
        }
}

void PlayScene::draw (sf::RenderWindow & w) {
        BaseScene::draw(w);
        background.draw(w);
        player.draw(w);
        for (size_t i=0; i<bullets.size(); i++){
                bullets[i].draw(w);
        }
        for (size_t i=0; i<enemies.size(); i++){
                enemies[i].draw(w);
        }
}
 

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
It's recommended to make use of your debugger and see the code run, it most likely would've revealed to you, that you're processing events twice.

                while(window.pollEvent(e)){
                        if(e.type == sf::Event::Closed){
                                window.close();
                        }
                }
                update();
                processEvents();

The first while does "as long as there are events, I'll take them out of the queue and execute the while-body".
Thus, once you reach processEvents(), the event queue will mostly be empty. Only rarely will be able to get a keyPressed event in, before you reach the other while(window.pollEvent(e)) part within processEvents().
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

FacuRot

  • Newbie
  • *
  • Posts: 3
    • View Profile
    • Email
Thank for your explanation. I fixed the problem passing the event to the proccesEvent function and removing the "while(window.pollEvent(event))" loop within it.