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

Author Topic: sf::View.setPosition on draw routine causing stuttering?  (Read 5092 times)

0 Members and 1 Guest are viewing this topic.

Chumble

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
sf::View.setPosition on draw routine causing stuttering?
« on: June 26, 2015, 04:06:22 pm »
OS: Windows 7x64
Graphics Card: Radeon 7950
SFML: 2.3, static

I'm having an issue which may just stem from my lack of understanding of how this should be set up. Due to the amount of classes I have, it would be a pain to put all my code here but I'll do my best to simplify it so it's post friendly.

Edit: Created a new project with just a main.cpp to isolate the issue. Attached the images I used.
#include <SFML/Graphics.hpp>

int main()
{
        sf::RenderWindow window(sf::VideoMode(1024, 768), "Game");
        sf::View gameView;
        sf::Texture texture, texture2;
       
        gameView.setSize(sf::Vector2f(1024, 768));

        texture.loadFromFile("image.png");
        texture2.loadFromFile("image2.png");

        int playerX = 5;
        int playerY = 5;

        while (window.isOpen())
        {
                sf::Event event;
                while (window.pollEvent(event))
                {
                        if (event.type == sf::Event::Closed)
                                window.close();
                        if (event.type == sf::Event::KeyPressed)
                        {
                                if (event.key.code == sf::Keyboard::Up)
                                {
                                        playerY--;
                                }
                                else if (event.key.code == sf::Keyboard::Down)
                                {
                                        playerY++;
                                }
                                else if (event.key.code == sf::Keyboard::Left)
                                {
                                        playerX--;
                                }
                                else if (event.key.code == sf::Keyboard::Right)
                                {
                                        playerX++;
                                }
                        }
                }

                window.clear();

                window.setView(gameView);

                for (int x = 0; x < 10; ++x)
                {
                        for (int y = 0; y < 10; ++y)
                        {
                                // Note: This is not actually how I handle sprites, it's done in another class but in order to simplify it I'm just putting it here.
                                sf::Sprite sprite;
                                sprite.setTexture(texture);
                                sprite.setPosition((x - y) * 64, (x + y) * 32);
                                window.draw(sprite);

                                if ((x == playerX) & (y == playerY))
                                {
                                        sf::Sprite player;
                                        player.setTexture(texture2);
                                        player.setPosition((x - y) * 64, (x + y) * 32 - 64);
                                        window.draw(player);
                                        gameView.setCenter(player.getPosition());
                                }
                        }
                }
                window.display();
        }

        return 0;
}
 

So, it's a 10x10 isometric 2D map of "texture" sprites. When it gets to the coordinates the player is on, it draws the player then sets the view to be centered on the player. I have no idea if this is the normal way to go about handling this, I'm kinda just figuring it out as I go (I prefer this method to following full tutorials as I enjoy encountering problems and going through the steps to fix them. Helps me learn better).

The problem is when I move around, the player sprite stutters a bit. Maybe every 5-10 moves, it will draw the player one step ahead of where they should be then correct it immediately. I tried to capture this on video but the screen corrects itself so quickly that the FPS wasn't high enough on the video to catch it.

Instead, I made a series of screenshots to show this

1) Start position
(click to show/hide)

2) I move once, everything normal. The player moves, the view follows
(click to show/hide)

3) I move again, and for a split second, I see this:
(click to show/hide)
Somehow, the player sprite is drawn in the new position but the view did not get updated.

4) Immediately after 3, the view is corrected and it looks normal again
(click to show/hide)

Also, yes, I am no artist and these images are placeholders. Don't laugh.


Any idea what might be causing this?

Thanks



Edit: I can see the images are a bit bigger than the space allows here, might be easier if they're viewed somewhere else. Here's the link to the album: http://imgur.com/156ASOz,ULuVyvH,aPTNJaT,9HiJv4S#0
« Last Edit: June 26, 2015, 06:07:58 pm by Chumble »

kitteh-warrior

  • Guest
Re: sf::View.setPosition on draw routine causing stuttering?
« Reply #1 on: June 26, 2015, 05:10:18 pm »
this.gameView.setCenter(player.gerPosition());

1) I believe there is a typo.
2) The use of this-> in a class is redundant.
3) What does the function I quoted's implementation?
4) Have you tried debugging it?
5) Did you try moving what I quoted to outside of the for loops?
6) Use the spoiler BBC tag around the images.
7) this

Chumble

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Re: sf::View.setPosition on draw routine causing stuttering?
« Reply #2 on: June 26, 2015, 05:24:22 pm »
this.gameView.setCenter(player.gerPosition());

1) I believe there is a typo.
2) The use of this-> in a class is redundant.
3) What does the function I quoted's implementation?
4) Have you tried debugging it?
5) Did you try moving what I quoted to outside of the for loops?
6) Use the spoiler BBC tag around the images.
7) this

1) Yep, it's a typo. Two typos, actually. Fixed em.
2) That was my understanding prior to reading through some tutorials where it was plastered everywhere.
3) Not sure what you're looking for here, setCenter is a standard function of sf::View. The doc is http://www.sfml-dev.org/documentation/2.0/classsf_1_1View.php#ab0296b03793e0873e6ae9e15311f3e78
4) Guess I'm not sure how I would go about that.
5) I did. It was originally just prior to the window.display(), I was moving it to ensure it got called when it was supposed to. Did not make a difference.
6) Done
7) Yeah, got halfway there but I wanted to avoid re-writing an entirely new program to isolate this thinking it might be a more known and obvious setup issue. I will put something functional together.


Edit: I changed the original post so it's all in one runable program. The problem is very sporadic but it happens, though it seems to happen less often in this example than my actual program.
« Last Edit: June 26, 2015, 05:40:12 pm by Chumble »

kitteh-warrior

  • Guest
Re: sf::View.setPosition on draw routine causing stuttering?
« Reply #3 on: June 26, 2015, 05:40:00 pm »
3) Not sure what you're looking for here, setCenter is a standard function of sf::View. The doc is http://www.sfml-dev.org/documentation/2.0/classsf_1_1View.php#ab0296b03793e0873e6ae9e15311f3e78

I assumed that gameView was a reference to another class you implemented, because I mostly just skimmed through it.
The reason that it is having a slight "stutter", is because you are changing gameView's center, but not the RenderWindow's View's center.

Example:
sf::View testView;
renderWindow.setView( testView );
testView.setCenter( sf::Vector2f( 100, 100 ) ); //<-- does not update the renderWindow's view

The RenderWindow does not store a reference to the view, it copies it. Therefor:

sf::View testView;
testView.setCenter( sf::Vector2f( 100, 100 ) );
renderWindow.setView( testView ); //<-- sets the correct center for the renderWindow

Edit: Forgot the solution.
If you put this line:
window.setView(gameView);

To right before you update the render window, it should be solved.
« Last Edit: June 26, 2015, 05:41:40 pm by kitteh-warrior »

Chumble

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Re: sf::View.setPosition on draw routine causing stuttering?
« Reply #4 on: June 26, 2015, 05:43:42 pm »
That sounded incredibly promising and made perfect sense, but I moved my setView to be after I changed the center and it still happens.. here's the updated code

#include <SFML/Graphics.hpp>

int main()
{
        sf::RenderWindow window(sf::VideoMode(1024, 768), "Game");
        sf::View gameView;
        sf::Texture texture, texture2;
       
        gameView.setSize(sf::Vector2f(1024, 768));

        texture.loadFromFile("image.png");
        texture2.loadFromFile("image2.png");

        int playerX = 5;
        int playerY = 5;

        while (window.isOpen())
        {
                sf::Event event;
                while (window.pollEvent(event))
                {
                        if (event.type == sf::Event::Closed)
                                window.close();
                        if (event.type == sf::Event::KeyPressed)
                        {
                                if (event.key.code == sf::Keyboard::Up)
                                {
                                        playerY--;
                                }
                                else if (event.key.code == sf::Keyboard::Down)
                                {
                                        playerY++;
                                }
                                else if (event.key.code == sf::Keyboard::Left)
                                {
                                        playerX--;
                                }
                                else if (event.key.code == sf::Keyboard::Right)
                                {
                                        playerX++;
                                }
                        }
                }

                window.clear();

                sf::Sprite player;
                player.setTexture(texture2);

                for (int x = 0; x < 10; ++x)
                {
                        for (int y = 0; y < 10; ++y)
                        {
                                sf::Sprite sprite;
                                sprite.setTexture(texture);
                                sprite.setPosition((x - y) * 64, (x + y) * 32);
                                window.draw(sprite);

                                if ((x == playerX) & (y == playerY))
                                {
                                        player.setPosition((x - y) * 64, (x + y) * 32 - 64);
                                        window.draw(player);
                                }
                        }
                }
                gameView.setCenter(player.getPosition());
                window.setView(gameView);
                window.display();
        }

        return 0;
}
 
« Last Edit: June 26, 2015, 05:45:19 pm by Chumble »

shadowmouse

  • Sr. Member
  • ****
  • Posts: 302
    • View Profile
Re: sf::View.setPosition on draw routine causing stuttering?
« Reply #5 on: June 26, 2015, 05:49:28 pm »
I think you're meant to set the view before drawing to it, so put
window.draw(sprite);
and
window.draw(player);
after
window.setView(gameView);
Also, why are you making a new instance of player every loop and therefore setting the texture every loop?

Chumble

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Re: sf::View.setPosition on draw routine causing stuttering?
« Reply #6 on: June 26, 2015, 06:04:39 pm »
I'm not following you here..

I could have two calls to

window.setView(gameView);
 

one before the loop and one after I run
gameView.setCenter(player.getPosition());
 
(I tried this for a quick test and it made no difference).

But if I have just the one call to setView prior to the loop, then it kinda contradicts what kitteh-warrior posted.

Also, why are you making a new instance of player every loop and therefore setting the texture every loop?
It's not really clean code, it was just a quick example project I made to show the problem. I can move the player outside the loop but I don't think it matters, this isn't my actual project.


Updated code for readability
(click to show/hide)

Also uploaded a quick video of it using this code. It happened 3 times when recording this but it only captured one of them (at about the 14 second mark)

http://www.fastswf.com/BMyezm4
« Last Edit: June 26, 2015, 06:09:46 pm by Chumble »

kitteh-warrior

  • Guest
Re: sf::View.setPosition on draw routine causing stuttering?
« Reply #7 on: June 26, 2015, 06:22:03 pm »
As shadowmouse said, you need to set the view of the render window, prior to drawing any drawable objects.

Example:
sf::Sprite testSpr;
sf::View testView;
testView.setCenter( sf::View( 100, 100 ) );
renderWindow.setView( testView ); //<-- must be set prior to drawing objects!
renderWindow.draw(testSpr);

Chumble

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Re: sf::View.setPosition on draw routine causing stuttering?
« Reply #8 on: June 26, 2015, 06:49:03 pm »
So, I need to use setView before I use draw but after I use setCenter.

The way the view is centered, I need to call setView inside the player condition.. so I end up with this:

(click to show/hide)

Which .. appears to have fixed one problem and caused another. The player sprite no longer jumps. Instead, the column of tiles under the player will flicker, not drawing the texture so it's black for a moment. I'm assuming this is caused by the inner if statement being called, updating the center and setting the view. I think I was able to fix this by calling setCenter and setView prior to drawing the tile as well, but this seems like a really really hack-y crude way to go about doing this... doesn't seem right.


Edit: And after further testing, I see this hasn't actually fixed the new issue.

(click to show/hide)
« Last Edit: June 26, 2015, 06:51:08 pm by Chumble »

kitteh-warrior

  • Guest
Re: sf::View.setPosition on draw routine causing stuttering?
« Reply #9 on: June 26, 2015, 07:06:23 pm »
(click to show/hide)

Why don't you just update the position of the player prior to the nested for loops, and draw the player after the nested for loops? It would avoid recalculating it 100 times per frame.

(click to show/hide)

Edit: Also, I never really noticed that "else if" chain in the event loop until now, I would recommend a switch statement for that.
« Last Edit: June 26, 2015, 07:12:48 pm by kitteh-warrior »

Chumble

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Re: sf::View.setPosition on draw routine causing stuttering?
« Reply #10 on: June 26, 2015, 07:13:08 pm »
The player's position is based on the x and y of the loops, so it can't be done before x and y are set.

Also, the player needs to be drawn in the correct draw order so that it will show up behind or in front of other tiles appropriately. That's the purpose of the inner if. That also ensures it only calculates the player's position once per drawScreen, not 100.

kitteh-warrior

  • Guest
Re: sf::View.setPosition on draw routine causing stuttering?
« Reply #11 on: June 26, 2015, 07:17:04 pm »
The player's position is based on the x and y of the loops, so it can't be done before x and y are set.

Also, the player needs to be drawn in the correct draw order so that it will show up behind or in front of other tiles appropriately. That's the purpose of the inner if. That also ensures it only calculates the player's position once per drawScreen, not 100.

But you added
gameView.setCenter(player.getPosition());
to outside of the if. I would still recommend the changing of position and view prior to the nested for loops. Therefor, the view will have the correct position.

EDIT: Use a debugger to go through your code, step by step and watch the position of the player.

(click to show/hide)
« Last Edit: June 26, 2015, 07:24:59 pm by kitteh-warrior »

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: sf::View.setPosition on draw routine causing stuttering?
« Reply #12 on: June 26, 2015, 08:41:25 pm »
As mentioned, change the view before the drawing which includes setting the center. It is not necessary to wait until drawing the tiles to calculate the player's position so why not do all of that before drawing?

                window.clear();

                sf::Sprite player;
                player.setTexture(texture2);

                const sf::Vector2f currentPlayerPosition((playerX - playerY) * 64, (playerX + playerY) * 32 - 64);
                player.setPosition(currentPlayerPosition);
                gameView.setCenter(currentPlayerPosition);
                window.setView(gameView);

                for (int x = 0; x < 10; ++x)
                {
                        for (int y = 0; y < 10; ++y)
                        {
                                sf::Sprite sprite;
                                sprite.setTexture(texture);
                                sprite.setPosition((x - y) * 64, (x + y) * 32);
                                window.draw(sprite);

                                if ((x == playerX) && (y == playerY))
                                {
                                        window.draw(player);
                                }
                        }
                }
                window.display();

Also, even though I didn't alter it in this code to show specifically what I'd changed, I'd highly recommend moving sf::Sprite player; and sf::Sprite sprite; to before the game loop. The setting of the texture each loop isn't really that bad but since they aren't expected to change (why would you need a different player texture each cycle and why would you need a different tile texture for each tile?), it would be better to move the two "setTexture" lines to before the main loop too (just after the sprite declarations would be ideal).

(click to show/hide)
« Last Edit: June 26, 2015, 09:09:51 pm by Hapax »
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Chumble

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Re: sf::View.setPosition on draw routine causing stuttering?
« Reply #13 on: June 26, 2015, 08:42:38 pm »
Huh... yeah, that makes sense. I have a tough time keeping all this stuff in my head at the same time and originally I wasn't even using playerX and Y for the view, I had a separate set of coordinates so that the view wasn't 100% locked to the player. That and still getting used to the two coordinate systems and the isometric drawing .. it was too much for me to see clearly, I guess.

Thanks for the help!

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: sf::View.setPosition on draw routine causing stuttering?
« Reply #14 on: June 26, 2015, 08:48:08 pm »
I added an example of what the code would look like without the excess sprite and texture setup to my previous post ;)

You could create a function that calculates the isometric position (the calculation that works out position of a tile) and re-use that for the tiles and player so avoid duplicating code, which will be great if/when you change the calculation - there wouldn't be player calculation that needed altering!

One other thing:
In your condition that tests if the player's location is the same as the current tile's location, you're using the bitwise operator & where you should be using the logical operator &&

(click to show/hide)
« Last Edit: June 26, 2015, 09:35:25 pm by Hapax »
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

 

anything