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

Author Topic: [SOLVED]Having issues with animation speed.  (Read 3520 times)

0 Members and 1 Guest are viewing this topic.

supdawg

  • Newbie
  • *
  • Posts: 33
    • View Profile
[SOLVED]Having issues with animation speed.
« on: December 11, 2012, 04:59:34 am »
I have a fade animation and some shape movement on the screen. the enter key causes the screen to fade out and in. i noticed that if i press the enter key while moving my mouse in the window, the fade animation happens faster.

here is my main loop:

while(Window.isOpen()){
    while(Window.pollEvent(ScreenManager::getInstance().event)){
      if(ScreenManager::getInstance().event.type == sf::Event::Closed)
        Window.close();
      if(ScreenManager::getInstance().event.key.code == sf::Keyboard::Escape)
        Window.close();
      else
        ScreenManager::getInstance().update(ScreenManager::getInstance().event, Window);
    }//end of while Poll event
   
    Window.clear(sf::Color(0, 0, 0));
    ScreenManager::getInstance().update(ScreenManager::getInstance().event, Window);
    ScreenManager::getInstance().draw(Window);
    Window.display();
    ScreenManager::getInstance().timeBetwFrame = clock.restart(); //records time between frame
  }//end of while isOpen

as you probably saw, i call my update function twice, once in the event loop and again in the while(Window is open) loop. the reason for this is this: if the user presses enter and then does nothing after that, i want the window to do the fade animation. however if i have update only in the event loop, then it wont call update since after pressing enter, there are no more events to pop so it wont even be in the event loop. and if update is only outside the event loop, then if an event happens, i wont call update until all events are popped and im outside the event loop. so i have a call to update twice. now you may say that in my event loop, i should say
if(sf::Event::isKeyPressed) //call update function
however this still isnt that great of a solution.

my update function does everything for me: input handling, window switching, animation, etc etc. but after one event (say pressing enter) to actually completely do the whole animation, update has to be called a few times since every frame, i change the alpha value by a bit (for fade animation). so i think the two calls to the update function makes the fade animation speed up if i move my mouse when pressing enter since many events are happening so its calling udpate once in the event loop and once in the while(isOpen) loop.

i cant think of any solution to this problem that works with the way i have set up my program. can anyone help me out with this issue please? thanks :D
« Last Edit: December 16, 2012, 02:13:06 pm by supdawg »

Plaid Phantom

  • Newbie
  • *
  • Posts: 10
    • View Profile
Re: Having issues with animation speed.
« Reply #1 on: December 11, 2012, 06:29:46 am »
I'm still not clear on why you need the update call in your event polling loop.  You are entirely correct that the Mouse events are causing the loop call to be called multiple times.  Just do the update outside of the event loop.

My guess is that you are concerned about events slowing down the frame time?  If so, two things: one, events probably won't slow your loop all that much (especially if they aren't handled), and two, you are already using a sf::Clock to measure the amount of time elapsed from the last frame: pass that time to your update function, and have your update function calculate the change in alpha per second instead of per frame (changePerSecond * timeElapsedInSeconds).

supdawg

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: Having issues with animation speed.
« Reply #2 on: December 12, 2012, 01:33:51 am »
yes i am using the time elapsed per frame to change my alpha so thats fine. but if i only update outside my event loop, then say when a bunch of keys are pressed, my program will enter the
while(Window.pollEvent)
loop and it will keep looping until all those events are popped from the event stack. so if i dont have update inside my event loop, (and my update takes an event and sees whether anything needs to be done), then wont the events that are popped be lost? or am i misunderstanding? and ofcourse the reason i need my update outside is obvious. if its only inside the event loop then if no events are happening it will never update.

Plaid Phantom

  • Newbie
  • *
  • Posts: 10
    • View Profile
Re: Having issues with animation speed.
« Reply #3 on: December 14, 2012, 08:10:59 am »
I see what you're doing now.  what you basically need to do is separate your event-handling code from your update code.  There are two ways you could do this:

The first (and probably best) way to do this is to have separate Update() and HandleEvent() functions.  The Update() function is what is called outside the event loop and would take the time and advance the game objects' states by the appropriate time.  The HandleEvent() function would be what is called within the event loop, and instead of advancing object state it sets flags (i.e. isFading) based on what the events signal.

Alternately, you could keep the single update() method and create some way to signal to it that you are advancing time instead of handling a received event.  There are a couple of ways to do this; for example, you could pass a pointer to the event object and have the pointer be NULL on non-event updates or you could have a separate isEvent parameter to the function.

In both cases, you are distinguishing the logic of advancing time versus handling an event.  That way, you aren't advancing the time more than once per frame, and all events only get handled once (if you look, you'll see that your code will handle the last event received in a frame twice: in the event loop and then immediately afterward, and even more if the next frame has no events.)

The way this works is that when in the "handling events" stage of your frame, you modify the state of your object.  For example, when the event means for you to start fading, all it would do is set an isFading flag to true.  This is all the event handling needs to do.  Then, in the Update stage, your object checks the isFading flag and if it is true fades the screen by the appropriate amount.

Here's a bit of pseudocode to explain:

Code: [Select]

//object

class Object : public sf::Sprite {
public:
    void HandleEvent(sf::Event e) {
        if(e.type == [whatever triggers your fade])
            isFading = true;
    };

    void Update(float time) {
        fadeBy(fadePerSec * time);  // or however you fade
    };
private:
    bool isFading;
};

// run loop
Object obj;
sf::Event event;
while (win.isRunning()) {
    while(win.pollEvent(event)) {
        obj.handleEvent(event);
    }
   
    obj.Update(clock.restart());  // I pass the time in my update function; you set it as an attribute of your ScreenManager, which works too.

    win.draw(obj);
}





« Last Edit: December 14, 2012, 08:12:49 am by Plaid Phantom »

supdawg

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: Having issues with animation speed.
« Reply #4 on: December 16, 2012, 07:11:17 am »
ok that makes a lot more sense and its much clearer now. the handleEvent function seems like a great idea. and one thing i was wondering. the handleEvent sets the flag to true (e.g. setting isFading to true) so would it be appropriate to say that the FadeAnimation class sets isFading to false? or should handleEvent do that? what i have right now is my FadeAnimation class will fade in and out and then set the "active" boolean to false. is that alrite? and now ill just create a handleEvent that just handles flags.

also in your second recommendation where i keep the single update function. i didnt quite understand what you meant. if i keep my one update function and pass it something like an isEvent parameter, should i keep the update function located in the while(pollEvent) loop? and should i change my loop to while(pollEvent || advancing time)? i didnt quite understand the 2nd approach but for now i will try the handleEvent function.

Plaid Phantom

  • Newbie
  • *
  • Posts: 10
    • View Profile
Re: Having issues with animation speed.
« Reply #5 on: December 16, 2012, 07:42:43 am »
Don't worry too much about the second method; basically it is just the same thing as the first, except instead of two methods you would have one method with a big if/else inside it. The first method is the better way to do it and I probably shouldn't have mentioned the other way to make things simpler. Here is my example above rewritten this way for completeness, though:

Code: [Select]
//object

class Object : public sf::Sprite {
public:
    void Update(bool isEvent, sf::Event* e, float time) {
        if(isEvent) { // or e != NULL
            if(e->type == [whatever triggers your fade])
                isFading = true;
        }
        else
           fadeBy(fadePerSec * time);  // or however you fade
    };
private:
    bool isFading;
};

// run loop
Object obj;
sf::Event event;
while (win.isRunning()) {
    while(win.pollEvent(event)) {
        obj.Update(true, &event, 0.0f);
    }
   
    obj.Update(false, NULL, clock.restart());


As to the rest of your question, it sounds lke you are on the right track. The exact flags and how they are set would depend on the exact behavior desired; probably you would set the isFading flag to true in your handleEvent method, and once the fade is complete your class might set the flag to false to signal that it is complete.

supdawg

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: Having issues with animation speed.
« Reply #6 on: December 16, 2012, 02:12:48 pm »
ok yes. then i will use your first mentioned method for sure. this makes a lot more sense now.

thanks so much :P