SFML community forums

Help => System => Topic started by: dotty on January 23, 2012, 11:23:15 pm

Title: Only want a function to get called once on a keyDown.
Post by: dotty on January 23, 2012, 11:23:15 pm
Hello, I'm using AniSprite to animate my sprites, this works well and I can play animation with ease.

When I press D on my keyboard I'm adding some velocity to move my sprite, but at the same time I'm calling AniSprite.Play(0,5); to play the animation. The obvious issue here is that Play(0,5) is called every frame, so that the animation never actually starts.

How do people get around this?
Title: Only want a function to get called once on a keyDown.
Post by: MarekkPie on January 24, 2012, 12:02:50 am
No idea about more elegant solutions, but you could do a if statement with a bool once, and the first time it gets called toggle that bool so the keyDown event only calls that particular bit of code once.
Title: Only want a function to get called once on a keyDown.
Post by: Tex Killer on January 24, 2012, 01:15:18 am
If you use input events instead of simple checks it will not happen every frame.
Title: Only want a function to get called once on a keyDown.
Post by: dotty on January 24, 2012, 09:13:40 am
I'm using this

Quote

this->LeftButton = sf::Keyboard::IsKeyPressed(sf::Keyboard::A);
if( this->LeftButton ){
      this->MoveLeft();
   }
Title: Only want a function to get called once on a keyDown.
Post by: dotty on January 24, 2012, 02:39:12 pm
Can anyone lend a hand on this? I'm struggling to get this working.
Title: Only want a function to get called once on a keyDown.
Post by: Tex Killer on January 24, 2012, 03:21:43 pm
http://sfml-dev.org/tutorials/1.6/window-events.php

If you are using SFML 2, use .PollEvent instead of .GetEvent
Title: Only want a function to get called once on a keyDown.
Post by: model76 on January 24, 2012, 03:36:58 pm
He/she is using SFML 2 and I don't think it is clear that the problem is what everyone assumes.

Dotty, do you want something to happen every time the button is pressed, or do you want something to happen every frame, as long as the button is pressed?

Events are good for the first case. Documentation for SFML 2 is here: http://www.sfml-dev.org/documentation/2.0/classsf_1_1Event.php

Real-time inputs, as you are using now, is for the latter.

Also, what is AniSprite?
Title: Only want a function to get called once on a keyDown.
Post by: MarekkPie on January 24, 2012, 04:36:22 pm
I think the issue here is that this "AniSprite" library as it's own little update loop, that iterates through the animation frames once you press play and give it a start frame. However, s/he is calling Play(0,5), the start trigger for the animation, every time that event gets called. So, it would start running its animation, get a call to start over, then run back to the beginning and start again, endlessly.
Title: Only want a function to get called once on a keyDown.
Post by: dotty on January 24, 2012, 07:55:26 pm
I want to do something every time the button is pressed.
Title: Only want a function to get called once on a keyDown.
Post by: model76 on January 24, 2012, 08:10:32 pm
Then you need to use sf::Event.

There is a really good example in the link I provided in the previous post, so that is where I think you should start.
Title: Only want a function to get called once on a keyDown.
Post by: dotty on January 24, 2012, 08:51:07 pm
sf::Event does seem the best way to do this. However, it seems that I cannot pass my window instance to my class. Any idea's how to use sf::Event within my class?
Title: Only want a function to get called once on a keyDown.
Post by: Tex Killer on January 24, 2012, 09:04:12 pm
You have to either pass the windows as parameter or have it global (if you choose this, you better have a window pointer made global, instead of the windows itself, because global variables cause trouble with SFML).
Title: Only want a function to get called once on a keyDown.
Post by: dotty on January 24, 2012, 09:13:40 pm
I've got something like this going on

Code: [Select]


Player {
public:
    sf::Window win;
    void SetWindow(sf::Window window);
}

void Player::SetWindow(sf::Window window){
    this->win = window;
}



But it's telling me it's 'Not copyable'
Title: Only want a function to get called once on a keyDown.
Post by: Tex Killer on January 24, 2012, 10:06:28 pm
Use a pointer or a reference.
Title: Only want a function to get called once on a keyDown.
Post by: model76 on January 25, 2012, 12:05:33 am
Why don't you do something like this in your main event loop:
Code: [Select]
if ( event.Type == sf::Event::KeyPressed && event.Key.Code == sf::Keyboard::Left )
    aniSprite.MoveLeft();
Title: Only want a function to get called once on a keyDown.
Post by: Mario on January 26, 2012, 01:01:42 am
I'm using a number of objects I iterate over (array of base class pointers to be specific) when I receive an input event. Each one has an "Update()" method that is called when receiving an input event, e.g. for keyboard inputs I've got this:
Code: [Select]
void KeyInput::Update(const sf::Event &event)
{
if ((event.Type == sf::Event::KeyPressed || event.Type == sf::Event::KeyReleased) && key == event.Key.Code)
{
Tapped = event.Type == sf::Event::KeyPressed && !Down;
Down = event.Type == sf::Event::KeyPressed;
}
}

For comparison, this is for gamepad/joystick buttons:
Code: [Select]
void JoyButtonInput::Update(const sf::Event &event)
{
if ((event.Type == sf::Event::JoystickButtonPressed || event.Type == sf::Event::JoystickButtonReleased) && controller == event.JoystickButton.JoystickId && button == event.JoystickButton.Button)
{
Tapped = event.Type == sf::Event::JoystickButtonPressed && !Down;
Down = event.Type == sf::Event::JoystickButtonPressed;
}
}

After this handling is done, I'm able to use the members "Tapped" and "Down" to determine whether some key has been pressed (still down) or tapped (one frame only). Once updating is done, I reset the "Tapped" member of all input objects to false, so it's no longer set while holding down the key/button.

It's probably not the most effective way to handle this, but it's very convenient to handle and sufficient for my use for now.
Title: Only want a function to get called once on a keyDown.
Post by: ingwik on February 03, 2012, 08:52:53 am
I had a similar problem with the animation from the wiki not working as intended.

Solution: http://www.sfml-dev.org/forum/viewtopic.php?t=5933

The solution was to use enumeration to check if it was already playing and only start an animation sequence if it was false. It was for SFML 1.6 though, even if I doubt it would make a difference.