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

Author Topic: Event Handling Deadzones? [SOLVED]  (Read 5537 times)

0 Members and 2 Guests are viewing this topic.

Ausche

  • Newbie
  • *
  • Posts: 19
    • View Profile
Event Handling Deadzones? [SOLVED]
« on: December 24, 2015, 08:33:53 pm »
Hey all,
So I'm working on the basics of a 2D zelda-style game (as a hobby) and I've got a question about the event system.

The problem is that when I hold any movement key (WASD), my sprite animation will pause for a short period of time and then act as it should, updating the spriteRect every .1 second.

I took the problem to the console, making it print every time an event was detected, every time the animation function was called, and so on, to figure out what was causing it to pause.
I found that this happens for all events detected including ones I don't handle (like the mouse) and it's the event loop that's skipped whenever an event is held.

When I just press a movement key, it acts as it should and moves the spriteRect for a split second, then resets. The problem is only when an event is held down.

Here's the segments of code that matter-
level1.cpp:
gameWindow.setFramerateLimit(30);

    while (gameWindow.isOpen())
    {
               
                sf::Event event;

        while (gameWindow.pollEvent(event))
        {
                       
            if (event.type == sf::Event::Closed)
                gameWindow.close();

                        player->handle_input(event, clock);
                        std::cout << "event detected" << std::endl;

                        enemy->path(*player, clock);
        }

                enemy->move();
                player->move();
 

player.cpp handle_input function:
void Player::handle_input(sf::Event event, sf::Clock& clock)
{
        switch(event.type)
        {
        case sf::Event::KeyPressed:
                {
                        switch(event.key.code)
                        {
                        case sf::Keyboard::W:
                                {
                                        velocity.y = -1;
                                        direction(2);
                                        if(clock.getElapsedTime().asSeconds() > 0.1f)
                                        {
                                                walking();
                                                clock.restart();
                                        }
                                        break;
                                }
                        case sf::Keyboard::A:
                                {
                                        velocity.x = -1;
                                        direction(3);
                                        if(clock.getElapsedTime().asSeconds() > 0.1f)
                                        {
                                                walking();
                                                clock.restart();
                                        }
                                        break;
                                }
                        case sf::Keyboard::S:
                                {
                                        velocity.y = 1;
                                        direction(1);
                                        if(clock.getElapsedTime().asSeconds() > 0.1f)
                                        {
                                        walking();
                                        clock.restart();
                                        }
                                        break;
                                }
                        case sf::Keyboard::D:
                                {
                                        velocity.x = 1;
                                        direction(4);
                                        if(clock.getElapsedTime().asSeconds() > 0.1f)
                                        {
                                                walking();
                                                clock.restart();
                                        }
                                        break;
                                }
                        }
                        break;
                }
        case sf::Event::KeyReleased:
                {
                        switch(event.key.code)
                        {
                        case sf::Keyboard::W: velocity.y = 0; break;
                        case sf::Keyboard::S: velocity.y = 0; break;
                        case sf::Keyboard::A: velocity.x = 0; break;
                        case sf::Keyboard::D: velocity.x = 0; break;
                        }
                        break;
                }
               
        }
       
        if(velocity.x == 0 && velocity.y == 0)
        {
                spriteRect.left = 0;
                msprite.setTextureRect(spriteRect);
        }
}
 

player.cpp move():
void Player::move()
{
        position.x +=velocity.x;
        if(position.x < 0 || position.x > (wSize.x-19))
                position.x -= velocity.x;

        position.y += velocity.y;
        if(position.y < 0 || position.y > (wSize.y-25))
                position.y -= velocity.y;

        msprite.setPosition(position);
        box = msprite.getGlobalBounds();
}
 

animate.cpp walking()
void Animate::walking()
{
        if (spriteRect.left == (mdimensions.x * 3))
                spriteRect.left = 0;
       
        else
                spriteRect.left +=mdimensions.x;

        msprite.setTextureRect(spriteRect);
}
 

animate.cpp direction function:
void Animate::direction(int direction)
{
        switch(direction)
        {
                case 1: spriteRect.top = 0;     break;
                case 2: spriteRect.top = mdimensions.y;break;
                case 3: spriteRect.top = (mdimensions.y*2);break;
                case 4: spriteRect.top = (mdimensions.y*3);break;
        }

        msprite.setTextureRect(spriteRect);
}
 

The sprite DOES move smoothly, with no pause, it's just the animation that pauses for a little bit.
All I'm looking for here is to get rid of that weird intial pause when events are held down and have smooth animation.
I'm about to head out to go to work, but when I get back I'll be able to respond.
« Last Edit: December 26, 2015, 08:45:07 pm by Ausche »
Struggling to make a game happen!

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Event Handling Deadzones?
« Reply #1 on: December 24, 2015, 10:49:55 pm »
If you want to move smoothly and continuously, you should find real-time input to be more appropriate than events.
See the tutorial on input.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Ausche

  • Newbie
  • *
  • Posts: 19
    • View Profile
Re: Event Handling Deadzones?
« Reply #2 on: December 25, 2015, 02:59:34 am »
If you want to move smoothly and continuously, you should find real-time input to be more appropriate than events.
See the tutorial on input.

So this isn't exactly my problem because the sprite does move smoothly. Meaning it moves exactly when I tell it to with no problem, it's just the animation that doesn't trigger until a few seconds after the initial key press.
Struggling to make a game happen!

Ungod

  • Newbie
  • *
  • Posts: 44
    • View Profile
Re: Event Handling Deadzones?
« Reply #3 on: December 25, 2015, 05:52:53 pm »
What was mentioned should be exactly your problem.

What you can try is setting up a boolean flag for each move direction and change them during event handling, instead of directly calculating velocity. Evaluate the flags in your update method then.

Alternatively do what the tutorial describes. Use real time input (in your update).

Jesper Juhl

  • Hero Member
  • *****
  • Posts: 1405
    • View Profile
    • Email
Re: Event Handling Deadzones?
« Reply #4 on: December 25, 2015, 06:39:31 pm »
the animation that doesn't trigger until a few seconds after the initial key press.
A few seconds is a long time and pretty extreme. I don't see such a huge delay being explained by using events vs real-time input. Something else must be wrong.
How are you handling your animations? What triggers them to start? How do they pick the frame to display/how do they know how much time has passed, etc?
Are you running an optimized build or a debug build?
Could you show a SSCCE?

Also, maybe not relevant (but maybe it is, so I'll leave the links anyway) - check out these links:
http://gafferongames.com/game-physics/fix-your-timestep/
http://www.bromeon.ch/libraries/thor/v2.0/tutorial-animations.html
« Last Edit: December 25, 2015, 06:55:08 pm by Jesper Juhl »

Ausche

  • Newbie
  • *
  • Posts: 19
    • View Profile
Re: Event Handling Deadzones?
« Reply #5 on: December 25, 2015, 10:17:30 pm »
What you can try is setting up a boolean flag for each move direction and change them during event handling, instead of directly calculating velocity. Evaluate the flags in your update method then.

This isn't my problem, it's not the movement. It's the animation. The sprite will move, the animation will not trigger until about a second give or take a few milliseconds.
If you read how I implement the animation, at every movement key keydown event i adjust the velocity and call the animation function to show the next sprite in the spritesheet texture. This keeps happening until the key is released. So it should be a smooth continuous thing, however there is a weird delay as described and then it animates completely fine.

A few seconds is a long time and pretty extreme.

I was wrong to say it's a few seconds, more like one second give or take a few milliseconds.
It iterates fine after that short pause though, but every movement key down event has that initial delay. I'll try to post a barebones example of what's going on.
Struggling to make a game happen!

G.

  • Hero Member
  • *****
  • Posts: 1593
    • View Profile
Re: Event Handling Deadzones?
« Reply #6 on: December 25, 2015, 10:25:39 pm »
It works exactly like when you hold down a key in a text box here.
The event triggers once, then there is a slight delay (defined in your OS) until it triggers faster.

And yeah, if you want something continuous the answer is in the first reply, use sf::Keyboard. ;)

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Event Handling Deadzones?
« Reply #7 on: December 26, 2015, 01:23:38 am »
If I had to guess, I'd say that walking() is your "start the animation" call?
If this is so, the testing of the clock to not allow it to start on the first event means that it will not start until the second event, which will be be after the initial keyboard repeat delay. Either start it immediately when you set the movement or consider using real-time input.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Ausche

  • Newbie
  • *
  • Posts: 19
    • View Profile
Re: Event Handling Deadzones?
« Reply #8 on: December 26, 2015, 07:57:37 pm »
It works exactly like when you hold down a key in a text box here.
The event triggers once, then there is a slight delay (defined in your OS) until it triggers faster.

And yeah, if you want something continuous the answer is in the first reply, use sf::Keyboard. ;)

Yes! This helped, I didn't understand the part about my OS so I tried the real-time input method but put it inside my event loop, which was dumb.

If I had to guess, I'd say that walking() is your "start the animation" call?
If this is so, the testing of the clock to not allow it to start on the first event means that it will not start until the second event, which will be be after the initial keyboard repeat delay. Either start it immediately when you set the movement or consider using real-time input.

I tried real-time input but did it wrong, now it works as I want.

-------------------------------------------------------------------------------------------------------------------

However I've encountered another problem. Now the movement isn't working correctly but the animation is very smooth.

The animation rolls continuously and smoothly but the sprite doesn't move continuously. It moves for roughly a second then stops and will move a pixel or so randomly.

My code right now, I changed some stuff up:
 while (gameWindow.isOpen())
    {

                if(sf::Keyboard::isKeyPressed(sf::Keyboard::W))
                        player->moveUp(clock);
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::S))
                        player->moveDown(clock);
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::A))
                        player->moveLeft(clock);
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::D))
                        player->moveRight(clock);
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Q))
                        gameWindow.close();

                sf::Event event;

        while (gameWindow.pollEvent(event))
        {
                        if(event.type == sf::Event::Closed)
                                gameWindow.close();
                        if(sf::Event::KeyReleased)
                                player->keyReleased(event);
                }

                enemy->path(*player, *clock);

                enemy->move(*player);
               
                if(!player->getBox().intersects(enemy->getBox()))
                        player->move();
 


The player moveUP/DOWN/LEFT/RIGHT. All that's really important here is to see that I set the velocity, the rest is the animation which works fine.
void Player::moveUp(sf::Clock* clock)
{
        velocity.y=-1;
        yDirection(-1);
        if(clock->getElapsedTime().asSeconds() > 0.1f)
        {
                walking();
                clock->restart();
        }
}
void Player::moveDown(sf::Clock* clock)
{
        velocity.y=1;
        yDirection(1);
        if(clock->getElapsedTime().asSeconds() > 0.1f)
        {
                walking();
                clock->restart();
        }
}
void Player::moveLeft(sf::Clock* clock)
{
        velocity.x=-1;
        xDirection(-1);
        if(clock->getElapsedTime().asSeconds() > 0.1f)
        {
                walking();
                clock->restart();
        }
}
void Player::moveRight(sf::Clock* clock)
{
        velocity.x=1;
        xDirection(1);
        if(clock->getElapsedTime().asSeconds() > 0.1f)
        {
                walking();
                clock->restart();
        }
}
 

The move function, very important. It's called every frame and adds velocity to positon. Might be part of the problem:

void Player::move()
{
        position.x +=velocity.x;
        if(position.x < 0 || position.x > (wSize.x-19))
                position.x -= velocity.x;

        position.y += velocity.y;
        if(position.y < 0 || position.y > (wSize.y-25))
                position.y -= velocity.y;

        msprite.setPosition(position);
}
 

I'm not sure what the problem is, I've been looking at it all day, might have made a careless mistake. I want to say that the event loop is still being triggered by the key presses, but I really don't understand how the loop works to begin with.
Struggling to make a game happen!

Ausche

  • Newbie
  • *
  • Posts: 19
    • View Profile
Re: Event Handling Deadzones?
« Reply #9 on: December 26, 2015, 08:09:43 pm »
Okay it's my keyRelease function inside the event loop. I made the console print my velocity at each call of the move() function and for some reason it's being set to zero.

The place that does that is inside my event loop:
if(sf::Event::KeyReleased)
     player->keyReleased(event);
 

which looks like
void Player::keyReleased(sf::Event event)
{
        switch(event.key.code)
                        {
                        case sf::Keyboard::W: velocity.y = 0; releaseDirection(velocity); break;
                        case sf::Keyboard::S: velocity.y = 0; releaseDirection(velocity); break;
                        case sf::Keyboard::A: velocity.x = 0; releaseDirection(velocity); break;
                        case sf::Keyboard::D: velocity.x = 0; releaseDirection(velocity); break;
                        }
}
 

Once again, I don't understand events very well or how the event loop works so I'm going to read around a bit.
Struggling to make a game happen!

G.

  • Hero Member
  • *****
  • Posts: 1593
    • View Profile
Re: Event Handling Deadzones?
« Reply #10 on: December 26, 2015, 08:19:36 pm »
Quote
        while (gameWindow.pollEvent(event))
        {
            if(event.type == sf::Event::Closed)
                gameWindow.close();
            if(sf::Event::KeyReleased)
                player->keyReleased(event);
        }
You're not checking correctly the type of your event.

It should be:
if(event.type == sf::Event::KeyReleased)

Ausche

  • Newbie
  • *
  • Posts: 19
    • View Profile
Re: Event Handling Deadzones?
« Reply #11 on: December 26, 2015, 08:44:54 pm »
Perfect, that worked. I'm getting careless haha.

Thanks all!
Struggling to make a game happen!