SFML community forums

Help => General => Topic started by: rush905 on August 23, 2012, 07:01:17 am

Title: sf::Seconds delay?
Post by: rush905 on August 23, 2012, 07:01:17 am
I'm trying to get a delay in between events. The point of this is so that when the user tries to move the character, they can't simply hold down the arrow key and fly off into the distance. Now I looked into the documentation for handling time, but all I could find was how to measure it. Now how to delay the program.

So is there any way to do this? I'm sure it's really simple, and I'm just not seeing the obvious here.

I don't think showing source here is necessary, but if anyone needs it, let me know.
Title: Re: sf::Seconds delay?
Post by: Hiura on August 23, 2012, 09:06:10 am
I think the sf::Clock class can help you there.
Title: Re: sf::Seconds delay?
Post by: eXpl0it3r on August 23, 2012, 09:24:47 am
As Hirua said using a sf::Clock you can messure the delay time and as long as it hasn't stepped over the delay time you simply do not process the event. If you want to process the events afterwards you'll have to store them, although this might generate strange behaviour. :D
Title: Re: sf::Seconds delay?
Post by: Groogy on August 23, 2012, 01:29:28 pm
For the purpose of a moving character I think that using the delta time between the frames can be used for that.

if(sf::Keyboard::isKeyPressed(sf::Keyboard::W)==true)
  movement.y -= 1 * delta_time );

Now you'll have to change it depending on how your implementation works but this is the most common thing to do. Though the other ways proposed have it's benefits as well. But this one works with least amount of code and least amount of trouble.

If I am unclear I can give you more hints on how to do this ;)
Title: Re: sf::Seconds delay?
Post by: rush905 on August 23, 2012, 05:38:00 pm
For the purpose of a moving character I think that using the delta time between the frames can be used for that.

if(sf::Keyboard::isKeyPressed(sf::Keyboard::W)==true)
  movement.y -= 1 * delta_time );

Now you'll have to change it depending on how your implementation works but this is the most common thing to do. Though the other ways proposed have it's benefits as well. But this one works with least amount of code and least amount of trouble.

If I am unclear I can give you more hints on how to do this ;)

I'm having a bit of trouble thinking of how that actually works. I was thinking that I would start a clock, then I would have an if statement like so:

if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up) && clock.getElapsedTime > sf::Seconds(.25))
{
    sprite.move(0, -14);
}
 

But when I do that, and run the program, the sprite doesn't even move. What's wrong with that?
Title: Re: sf::Seconds delay?
Post by: eXpl0it3r on August 23, 2012, 06:08:55 pm
Well if you want framerate depended movement then you'll have to do what Groogy proposed.

Something like:
sf::Sprite sprite;
sf::Vector2i direction(0, -1);
sf::Vector2f speed(0, 14);
sf::Clock clock;
while(window.isOpen())
{
    sf::Time dt = clock.restart();

    sf::Event event;
    while(window.pollEvent(event))
    {
        if(even.type == sf::Event::Closed)
            window.close();
    }
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
    {
        sprite.move(0, direction.y * speed.y * dt.asSeconds());
    }
}

The sf::Clock will get restarted every frame thus, it will capture the time between two frames aka delta time or dt.
If you now take the velocity (speed) and multiply it by dt then you get the speed for that short time period and you don't apply the fully velocity for every frame. The direction variable is just a help to easily swap directions without having to change the actual velocity value.
It's adviced to use window.setFramerateLimit and use a fixed timestep (dt) to match the framerate (i.e. dt = 1/FPS).
Title: Re: sf::Seconds delay?
Post by: rush905 on August 23, 2012, 06:36:46 pm
Well if you want framerate depended movement then you'll have to do what Groogy proposed.

Something like:
sf::Sprite sprite;
sf::Vector2i direction(0, -1);
sf::Vector2f speed(0, 14);
sf::Clock clock;
while(window.isOpen())
{
    sf::Time dt = clock.restart();

    sf::Event event;
    while(window.pollEvent(event))
    {
        if(even.type == sf::Event::Closed)
            window.close();
    }
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
    {
        sprite.move(0, direction.y * speed.y * dt.asSeconds());
    }
}

The sf::Clock will get restarted every frame thus, it will capture the time between two frames aka delta time or dt.
If you now take the velocity (speed) and multiply it by dt then you get the speed for that short time period and you don't apply the fully velocity for every frame. The direction variable is just a help to easily swap directions without having to change the actual velocity value.
It's adviced to use window.setFramerateLimit and use a fixed timestep (dt) to match the framerate (i.e. dt = 1/FPS).

I'm not quite understanding what exactly this code is doing. For example, why are you multiplying the direction by the speed, and the time? What does that accomplish? Also, why do you have a vector "speed" , and multiplying that by -1. Why not just get rid of the vector and just have the sprite move -14 pixles. It would kill two birds with one stone.

Again, sorry if these are stupid questions, I simply want a better understanding of this.
Title: Re: sf::Seconds delay?
Post by: eXpl0it3r on August 23, 2012, 06:57:55 pm
Well I'm not sure if you have read my explenation underneath the code, it actually explains most of what you've ask.

If you want to move your sprite by -14px the you have to ask yourself in what time period do I want to move that? Do you want it to move just once -14px? Do you want to smoothly move it from point A to point B with a speed of -14px per second?
If you do not take care of timing (i.e. sprite.move(0, -14)) then your sprite will move with a speed of -14px*FPS and with a simple application drawing one sprite you can get around 500-5000fps thus your sprite would move with a speed of -7'000px/s-70'000px/s which well isn't really usefull. Thus you have to make your movement depended of the framerate (/ fixed timestamp with fixed fps). That's where the velocity*dt comes in.

Like I already said the direction is just an easy way to change direction without having to influence the actual velocity value, but you can of course merge them together and just use positive/negative velocities to describe the direction.

The use of vectors comes from math/physics itself. An object can have a diffrent x and y velocity, e.g. you can jump with -14px/s but you don't have to move forward thus your x speed would be 0px/s. Now instead of having two variables speedx and speedy you simply merge them into one class 'vector'. ;)
Title: Re: sf::Seconds delay?
Post by: rush905 on August 23, 2012, 07:10:04 pm
Ok, I'm starting to understand now. But when I use your code, the sprite is only moving 1 pixle per 1 second. Why is that?

Source:

http://pastebin.com/YgMCYtYs (http://pastebin.com/YgMCYtYs)

EDIT: When I change the value of how much it moves to a much larger number, there's no delay at all. It moves whenever I press the key. And if I hold it down, the sprite freezes, but when I release it move really far.
Title: Re: sf::Seconds delay?
Post by: eXpl0it3r on August 23, 2012, 07:25:40 pm
Well you're doing a few things wrong. ;)

First if you hardcode your speed you obviously don't need that 1/-1 for direction...
Second take again a closer look at my example, I've put the movement function outside of the while(window.pollEvent()) loop. That's what you have to do too. If your code does not depend on an event then it should never be in the event loop.
Third you're loading a new image whenever you press a key, this leads to the freezing, when keeping the key pressed, since SFML then is working very hard loading constantly a new image => very inefficient.
At best you should put all the diffrent images of your character in one image and then load this onces. You then can use sprite.setTextureRect to change the visible rectangle on the texture (i.e. you can 'cut' out the image you need). That way you'd load the texture once and then only move the rectangle on the loaded image.

I would suggest to use setFramerateLimit since one can force VSync to be off or on from the system and SFML's setVerticalSync won't be able to change anything.
Title: Re: sf::Seconds delay?
Post by: rush905 on August 23, 2012, 11:19:53 pm
Alright, well I did what you said, but now the Sprite isn't showing up.

Source:

http://pastebin.com/SePTHHNh (http://pastebin.com/SePTHHNh)
Title: Re: sf::Seconds delay?
Post by: eXpl0it3r on August 23, 2012, 11:29:05 pm
Well are all the rects correctly configured?
Otherwise it wouldn't make any sense that it doesn't show up.

Btw: You can also post the code here to the forum with the code=cpp tag and if you ever post code to pastebin, make sure to choose the right syntax highlighting (e.g. C++) so we don't have to stare at black text which makes it hard to understand... ;)
Title: Re: sf::Seconds delay?
Post by: rush905 on August 23, 2012, 11:30:57 pm
Sorry, I just didn't want to have it take up so much room here, so I decided to put it else where. And sorry about the not choosing C++, silly mistake. I'll take a look at it again, and see if I can fix it.

Oh, quick question. With "sprite.setTextureRect(), the first two arguments are for the cords of the top left corner of the selection, correct? Or, you could just link me to the documentation, because I have a hard time finding the write page   :-[
Title: Re: sf::Seconds delay?
Post by: eXpl0it3r on August 23, 2012, 11:37:34 pm
Oh, quick question. With "sprite.setTextureRect(), the first two arguments are for the cords of the top left corner of the selection, correct? Or, you could just link me to the documentation, because I have a hard time finding the write page   :-[
Yes as described in the documentation (http://www.sfml-dev.org/documentation/2.0/classsf_1_1Rect.php#details). :D
Well you click on 'Classes' and then choose the one you want to inspect further and there you'll also find links to related classes etc. ;)
Title: Re: sf::Seconds delay?
Post by: rush905 on August 23, 2012, 11:52:55 pm
   
sf::Rect< T >::Rect     (       T       rectLeft,
                T       rectTop,
                T       rectWidth,
                T       rectHeight
        )              

That's from the documentation. How do I pass in 4 cords with only 4 integers? Should I be passing in 4 vectors instead, because they store an x and a y cord? Also, I'm not understanding the first two params.
Title: Re: sf::Seconds delay?
Post by: Laurent on August 23, 2012, 11:55:21 pm
sf::Rect is an axis-aligned rectangle, so you only need 4 coordinates to describe it.
Title: Re: sf::Seconds delay?
Post by: eXpl0it3r on August 24, 2012, 12:00:12 am
Does who can read have a clear advantage... ;D

It's all written in the documentation and even the variable names tell what to pass in.
The first argument is for the (top) left coordinate of the sub-image, the second for the (left) top coordinate, the third is for the width of the sub-image (going from the specified left coordinate into the direction right) and the forth is for the height of the sub-image (going from the specified top coordinate into the direction down).
Title: Re: sf::Seconds delay?
Post by: rush905 on August 24, 2012, 12:20:07 am
I'm sorry, what? The first agrument is for the top-left corner, and the 2nd is for the left-top corner?
Title: Re: sf::Seconds delay?
Post by: Laurent on August 24, 2012, 12:21:36 am
Yeah, this was not the clearest explanation :P

The first is the  X coordinate of the left edge, the second is the Y coordinate of the top edge.
Title: Re: sf::Seconds delay?
Post by: rush905 on August 24, 2012, 12:24:28 am
Yeah, this was not the clearest explanation :P

The first is the  X coordinate of the left edge, the second is the Y coordinate of the top edge.

Ah, thank you. That makes a lot more sense. I'll try it out in a sec.
Title: Re: sf::Seconds delay?
Post by: eXpl0it3r on August 24, 2012, 12:25:22 am
Yeah, this was not the clearest explanation :P
True my over pronouncing was kind of missleading, but seriously read the documentation, I mean what's so hard to understand with the description "left", "top", "width" and "height"? ;)
Title: Re: sf::Seconds delay?
Post by: rush905 on August 24, 2012, 12:30:22 am
I guess because I would have done it with the cords of each corner, and I thought that was the approach they were trying to do as well.

Okay, I'm literally pulling my hair out right now, trying to figure out why this isn't working. If you guys could tell me what's wrong I would be so happy.

The image I'm using (zoomed):
http://i.imgur.com/jAc3D.png

Not zoomed:
http://i.imgur.com/JNRGT.png

The source:

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

int main()
{
        //Create window, and limit frame rate
        sf::RenderWindow window (sf::VideoMode(800, 600, 32), "Game", sf::Style::Default);
        window.setFramerateLimit(30);

        //Declare image
        sf::Texture texture;
        //Load image
        if(!texture.loadFromFile("Sprites/main.png"))
        {
                return 1;
        }

        //Creates and places the main sprite
        sf::Sprite sprite;
        sprite.setPosition(400, 300);

        //Defines the rects that will be used to switch character view
        sf::IntRect front(2, 2, 17, -22);
        sf::IntRect back (22, 2, 16, 21);
        sf::IntRect left (2, 27, 16, 23);
        sf::IntRect right (23, 27, 16, 23);

        //Starts clock
        sf::Clock clock;

        //Main window loop
        while(window.isOpen())
        {
                sf::Event event;

                sf::Time time = clock.restart();

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

                        if(event.key.code == sf::Keyboard::Insert)
                        {
                                sf::Image screenshot = window.capture();
                                screenshot.saveToFile("Screenshot.png");
                        }
                }

                //Movement
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
                {
                        sprite.setTextureRect(front);
                        sprite.move(0, -14 * time.asSeconds());
                }

                else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
                {
                        sprite.setTextureRect(back);
                        sprite.move(0, 14 * time.asSeconds());
                }

                else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
                {
                        sprite.setTextureRect(right);
                        sprite.move(16 * time.asSeconds(), 0);
                }

                else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
                {
                        sprite.setTextureRect(left);
                        sprite.move(-16 * time.asSeconds(), 0);
                }
               
                //Draw sequence
                window.clear(sf::Color(255, 0, 0)); //(Red, Green, Blue, (optional) Alpha) Alpha is transperency

                //Draw....

                window.draw(sprite);

                window.display();
        }
        return 0;
}
 
Title: Re: sf::Seconds delay?
Post by: FRex on August 24, 2012, 02:52:37 am
Your rects are all wrong.
Your spirte has no texture assigned to it so it quits it's drawing call without drawing anything.
Title: Re: sf::Seconds delay?
Post by: rush905 on August 24, 2012, 03:09:34 am
Oh my god, I must have deleted it by mistake! I've been up all night, and haven't slept at all, so I can't think straight right now. Thank you so much, you saved me.

Now I have to get the original problem I was having solved. I need to delay the movement of the character. The earlier solution didn't help.