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

Author Topic: [SOLVED] Why do my inputs get multiplied when my mouse moves over my window ?  (Read 3752 times)

0 Members and 1 Guest are viewing this topic.

PaulDubois

  • Newbie
  • *
  • Posts: 3
    • View Profile
Hello, could someone explain to me why that happens please ?

My problem is as follow : If I press a key while my program is running then the input is only received once, which is what I want. However, if I press a key while I move my mouse over my SFML window then the input is repetead ~5-7 times in an instant.

Here is my main loop :

sf::RenderWindow window(sf::VideoMode(WIN_HEI, WIN_WID), "fenĂȘtre");
    if (!heroTexture.loadFromFile("res/hero_sheet.png"))
    {
        cout << "erreur de chargement";
    }

    heroSprite.setTexture(heroTexture);
    heroSprite.setTextureRect(IntRect(spriteSize * heroAnim.x, heroAnim.y * spriteSize, spriteSize, spriteSize));
    while (window.isOpen())
    {
       
       
        Event event;
       
        while (window.pollEvent(event))
        {
           
            CheckBtn();
            animPlayer();
        }
       
        input.InputHandler(event, window);
       
       
        window.clear();
        window.draw(heroSprite);
        window.display();
    }

    return 0;
}


Here is my class Input.h :


#ifndef INPUT_H
#define INPUT_H

#include <SFML/Graphics.hpp>
#include <iostream>


using namespace sf;

class Input
{
        struct Button { bool left, right, up, down, attack, escape; };
        Button button;
public:
        Input();
        Button GetButton(void) const;
        void InputHandler(Event event, RenderWindow& window);

       
};

#endif


Input.cpp :
#include "input.h"

Input::Input()
{
    button.left = button.right = button.down = button.up = button.escape = button.attack = false;
}

void Input::InputHandler(Event event, RenderWindow& window)
{
    if (event.type == sf::Event::Closed)
    {
        window.close();
    }
    if (event.type == Event::KeyPressed)
    {
        switch (event.key.code)
        {
        case Keyboard::Escape:
            button.escape = true;
            break;
        case Keyboard::Up:
            button.up = true;
            break;
        case Keyboard::Down:
            button.down = true;
            break;
        case Keyboard::Left:
            button.left = true;
            break;
        case Keyboard::Right:
            button.right = true;
            break;
        default:
            break;
        }
    }
    if (event.type == Event::KeyReleased)
    {
        switch (event.key.code)
        {
        case Keyboard::Escape:
            button.escape = false;
            break;
        case Keyboard::Up:
            button.up = false;
            break;
        case Keyboard::Down:
            button.down = false;
            break;
        case Keyboard::Left:
            button.left = false;
            break;
        case Keyboard::Right:
            button.right = false;
            break;
        default:
            break;
        }

    }
    if (event.type == Event::MouseButtonPressed)
    {
        if (event.mouseButton.button == Mouse::Left)
        {
            button.attack = true;
        }
    }
    if (event.type == Event::MouseButtonReleased)
    {
        if (event.mouseButton.button == Mouse::Left)
        {
            button.attack = false;
        }
    }
   
   

}

Input::Button Input::GetButton(void) const
{
    return button;
}


And in my main is a fuction CheckBtn that simply assosciates an enumeration (the 4 directions) to corresponding sprites.


« Last Edit: June 17, 2022, 05:29:44 am by PaulDubois »

Arcade

  • Full Member
  • ***
  • Posts: 230
    • View Profile
How are you determining your inputs are being repeated? Did you put a print statement in your InputHandler class? Or is there something in CheckBtn() or animPlayer() happening more than once?

Also, is there a reason that this line
input.InputHandler(event, window);
isn't inside of the while loop above it? Looks like it probably should be.

PaulDubois

  • Newbie
  • *
  • Posts: 3
    • View Profile
How are you determining your inputs are being repeated? Did you put a print statement in your InputHandler class? Or is there something in CheckBtn() or animPlayer() happening more than once?

Also, is there a reason that this line
input.InputHandler(event, window);
isn't inside of the while loop above it? Looks like it probably should be.


Hello, yes I did use a print statement to determine that. Also I have a constant for the "walk speed" of my character and the sprite moves way faster when I hover my cursor over my window.
However if my mouse is on my window but I don't move it then the input is not repeated x times and the program works as expected.

As for why I did not put
input.InputHandler(event, window);
right above it's because if I do that then the same exact bug happens except I don't even need to move my cursor for it to happen.
So I opted to put it out of the loop so that this bug only happens when I hover my cursor.

I know it's a bit confusing and I'm sorry about it but I hope I made my problem understandable.

kojack

  • Sr. Member
  • ****
  • Posts: 343
  • C++/C# game dev teacher.
    • View Profile
It sounds like CheckBtn() is actually performing the movement based on the values set by InputHandler. Is that right?

The reason there is a while loop around pollEvent is because there can be multiple events waiting in the event queue. Every key press or release, every window event, and every small mouse movement or button press will add an event. The while loop goes through them all one at a time.
This has two effects on the code shown that you might not want:
- CheckBtn and animPlayer() are called every time the mouse moves, which might be multiple times per frame.
- InputHandler() is outside of the loop, so it will miss events, it only sees the last event in the queue. If events are coming in slow that would work, but many events coming in will make it miss some.

I'd say try swapping the inside and outside parts:
Event event;
       
while (window.pollEvent(event))
{
    input.InputHandler(event, window);            
}

CheckBtn();
animPlayer();
 

That way the input system receives every event and CheckBtn and animPlayer only happen once per frame.

PaulDubois

  • Newbie
  • *
  • Posts: 3
    • View Profile
It sounds like CheckBtn() is actually performing the movement based on the values set by InputHandler. Is that right?

The reason there is a while loop around pollEvent is because there can be multiple events waiting in the event queue. Every key press or release, every window event, and every small mouse movement or button press will add an event. The while loop goes through them all one at a time.
This has two effects on the code shown that you might not want:
- CheckBtn and animPlayer() are called every time the mouse moves, which might be multiple times per frame.
- InputHandler() is outside of the loop, so it will miss events, it only sees the last event in the queue. If events are coming in slow that would work, but many events coming in will make it miss some.

I'd say try swapping the inside and outside parts:
Event event;
       
while (window.pollEvent(event))
{
    input.InputHandler(event, window);            
}

CheckBtn();
animPlayer();
 

That way the input system receives every event and CheckBtn and animPlayer only happen once per frame.


You are correct about CheckBtn(), animPlayer() simply cuts rectangles around the sprites of a sprite sheet.
I swapped the two blocks and I tweaked animPlayer() a bit and it worked ! Thank you very much for taking the time to help me with my problem.