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

Author Topic: Issues with game speed  (Read 5983 times)

0 Members and 1 Guest are viewing this topic.

awsumpwner27

  • Newbie
  • *
  • Posts: 27
    • View Profile
Issues with game speed
« on: January 17, 2013, 05:36:34 am »
After a bit of effort, I think I managed to compress my code into the basics to represent my problem. Unfortunately, my problem depends on a few complicated systems. Too long? The original was over 220 lines long on three files. This is 120 lines in one document. You're welcome.  ;)

Anyway, the problem I present to you is one I don't quite understand. When I usually get problems like these, the solution seems evident enough, but I don't think things quite add up in this case. You see, there is an object in the middle of the screen that can move around and follow your cursor when you press the Up key. When your mouse is still, it goes at a constant pace. However, whenever the mouse moves, the object speeds up. That's not the end of it. If I'm outputting text to the console window in the game loop, the game moves at the same pace as if the mouse were moving in the previous explanation. HOWEVER, the game slows to the calm pace when the object in the middle faces directly right. (Why right? It has to do with some math, but it used to be directly up before I subtracted 90 from an angle.) I think this has to do with me trying to control the speed of the game based on the frame rate of the game. (e.g. Game has half the expected frame rate? Make everything move twice as fast per frame.)

I've been looking at this for a long time, and I've gotten lost in a sea of possibilities. Any help is appreciated. Thanks.
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <math.h>
#include <iostream> //For bug fixing

#define PI 3.1415926535

class playerCharacter {
public:
        sf::Vector2f                            Position;
        short int                                       Rotation;
        sf::Vector2f                            Velocity;
        sf::CircleShape                         Visual;
        char                                            Direction;
        friend void                                     Update(playerCharacter *plyr, sf::Int32 passedTime);
};

void Update(playerCharacter *plyr, sf::Int32 passedTime){ //If I use Int64 here, it doesn't build. Probably because this computer doesn't use 64 of them thingamabobs.
        float timeFactor = 60.0/(1.0/((float)passedTime / 1000000.0)); //I suspect all troubles come from this line, where I try to make sure that the speed of the game is independant of the frame rate.

        //std::cout<<timeFactor<<","<<passedTime<<std::endl;

        plyr->Position.x = plyr->Position.x + plyr->Velocity.x * timeFactor;
        plyr->Position.y = plyr->Position.y + plyr->Velocity.y * timeFactor;
}

int main(){

        //System-related
        sf::Clock gameClock;

        sf::Clock rClock;

        sf::VideoMode vm(400,300);

        sf::RenderWindow window(vm, "Placeholder", 7);

        sf::Vector2f mousePosition;

        playerCharacter teabot;
        teabot.Position = sf::Vector2f((float)window.getSize().x/2, (float)window.getSize().y/2);
        //System-related END

        //Graphics-related
        sf::View view(sf::FloatRect(teabot.Position.x-(float)80, teabot.Position.y-((float)vm.height/(float)vm.width) * (float)80, (float)160, ((float)vm.height/(float)vm.width) * (float)160));

        teabot.Visual.setRadius(128);
        teabot.Visual.setPointCount(4);
        teabot.Visual.setFillColor(sf::Color::Blue);
        teabot.Visual.setOrigin(128, 128);
        teabot.Visual.setScale(1.f/32.f, 1.f/32.f);

        sf::CircleShape mReference(0.4, 5.0);
        mReference.setFillColor(sf::Color::White);
        //Graphics-related END

        //Window options
        window.setVerticalSyncEnabled(true);
        window.setFramerateLimit(60);
        window.setView(view);

        //Game loop
        while(window.isOpen()){
                gameClock.restart();
                sf::Event event;
                while(window.pollEvent(event)){
                        switch(event.type){
                                case sf::Event::Closed :
                                        window.close();
                                break;
                                case sf::Event::KeyPressed :
                                        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)){
                                                window.close();
                                        }
                                        //Key presses
                                        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
                                                teabot.Direction = 'F';
                                        //Key presses END
                                break;
                                case sf::Event::MouseMoved :
                                        mousePosition = (sf::Vector2f) sf::Mouse::getPosition(window); //Whenever I move the mouse, the game's speed increases
                                break;
                        }
                }

                view.setCenter(teabot.Position);
                window.setView(view);

                teabot.Visual.setPosition((sf::Vector2f)teabot.Position);
                teabot.Rotation =  90 + atan2( (float)(mousePosition.y + (view.getCenter().y - window.getSize().y/2)) - teabot.Position.y, (float)(mousePosition.x + (view.getCenter().x - window.getSize().x/2)) - teabot.Position.x) / (float)PI * 180;
                teabot.Visual.setRotation(teabot.Rotation);

                //Work on stuff below. Note: Character slows down when facing directly right, investigate.
                //When I get rid of output to cout, the entire game seems to slow to a constant rate, and it speeds up when the mouse moves.
                //Curiouser and curiouser. Because the slow down caused by facing the object to the right is relatively unnoticeable due to the new slowing by lack of output.
                //Theory: The output does cause the game to speed up, but something about all the values outputted being so simple when the object faces the right makes the console window update in a different way. Perhaps, not update at all?
                //Then why does the mouse speed up the game when there's no output? Should the game be as slow as it is when the mouse isn't moving? Does the update of a mouse cause the window to update at the rate at which the mouse position updates?

                if(teabot.Direction == 'F'){
                        teabot.Velocity.x = cos(((float)teabot.Rotation - 90.0) / 180.0 * (float)PI)*50.0;
                        teabot.Velocity.y = sin(((float)teabot.Rotation - 90.0) / 180.0 * (float)PI)*50.0;
                }

                if(rClock.getElapsedTime().asSeconds() >= 1.0){
                        mReference.setPosition(teabot.Position);
                        rClock.restart();
                }

                //std::cout<<teabot.Direction<<teabot.Velocity.x<<", "<<teabot.Velocity.y<<std::endl; //Whenever the console window updates, the game window updates. This seems to make the game go faster somehow.
                Update(&teabot, gameClock.getElapsedTime().asMicroseconds());

                window.clear(sf::Color::Black);
                window.draw(teabot.Visual);
                window.draw(mReference);
                window.display();

        }

        return 0;
}

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: Issues with game speed
« Reply #1 on: January 17, 2013, 05:44:03 am »
I didn't go through all the code and I'm not sure what you're doing/trying to achieve with the rotation, but for the speed-ups and slow downs, you should take again a close look at the tutorials about Events and Real-Time Input Classes. sf::Event and sf::Mouse/sf::Keyboard should only get mixed under special circumstances. If you want to work with events, then use the correct events respond, otherwise don't put your input code into the event loop! ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

awsumpwner27

  • Newbie
  • *
  • Posts: 27
    • View Profile
Re: Issues with game speed
« Reply #2 on: January 20, 2013, 04:20:41 am »
I'm not sure what you're doing/trying to achieve with the rotation,

Well, I kept that in because it's important to the source of the issue.

If you want to work with events, then use the correct events respond, otherwise don't put your input code into the event loop! ;)

Well, okay.

That's what you told me.

This is what I did:
(Hope you don't mind me pasting code that was hardly changed.)
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <math.h>
#include <iostream> //For bug fixing

#define PI 3.1415926535

class playerCharacter {
public:
        sf::Vector2f                            Position;
        short int                                       Rotation;
        sf::Vector2f                            Velocity;
        sf::CircleShape                         Visual;
        char                                            Direction;
        friend void                                     Update(playerCharacter *plyr, sf::Int32 passedTime);
};

void Update(playerCharacter *plyr, sf::Int32 passedTime){ //If I use Int64 here, it doesn't build. Probably because this computer doesn't use 64 of them thingamabobs.
        float timeFactor = 60.0/(1.0/((float)passedTime / 1000000.0)); //I suspect all troubles come from this line, where I try to make sure that the speed of the game is independant of the frame rate.

        //std::cout<<timeFactor<<","<<passedTime<<std::endl;

        plyr->Position.x = plyr->Position.x + plyr->Velocity.x * timeFactor;
        plyr->Position.y = plyr->Position.y + plyr->Velocity.y * timeFactor;
}

int main(){

        //System-related
        sf::Clock gameClock;

        sf::Clock rClock;

        sf::VideoMode vm(800,600);

        sf::RenderWindow window(vm, "Placeholder", 7);

        sf::Vector2f mousePosition;

        playerCharacter teabot;
        teabot.Position = sf::Vector2f((float)window.getSize().x/2, (float)window.getSize().y/2);
        //System-related END

        //Graphics-related
        sf::View view(sf::FloatRect(teabot.Position.x-(float)80, teabot.Position.y-((float)vm.height/(float)vm.width) * (float)80, (float)160, ((float)vm.height/(float)vm.width) * (float)160));

        teabot.Visual.setRadius(128);
        teabot.Visual.setPointCount(4);
        teabot.Visual.setFillColor(sf::Color::Blue);
        teabot.Visual.setOrigin(128, 128);
        teabot.Visual.setScale(1.f/32.f, 1.f/32.f);

        sf::CircleShape mReference(0.4, 5.0);
        mReference.setFillColor(sf::Color::White);
        //Graphics-related END

        //Window options
        window.setVerticalSyncEnabled(true);
        window.setFramerateLimit(60);
        window.setView(view);

        //Game loop
        while(window.isOpen()){
                gameClock.restart();
                sf::Event event;
                while(window.pollEvent(event)){
                        switch(event.type){
                                case sf::Event::Closed :
                                        window.close();
                                break;
                        }
                }
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
                        window.close();

                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
                        teabot.Direction = 'F';

                mousePosition = (sf::Vector2f) sf::Mouse::getPosition(window);

                view.setCenter(teabot.Position);
                window.setView(view);

                teabot.Visual.setPosition((sf::Vector2f)teabot.Position);
                teabot.Rotation =  90 + atan2( (float)(mousePosition.y + (view.getCenter().y - window.getSize().y/2)) - teabot.Position.y, (float)(mousePosition.x + (view.getCenter().x - window.getSize().x/2)) - teabot.Position.x) / (float)PI * 180;
                teabot.Visual.setRotation(teabot.Rotation);

                //Work on stuff below. Note: Character slows down when facing directly right, investigate.
                //When I get rid of output to cout, the entire game seems to slow to a constant rate, and it speeds up when the mouse moves.
                //Curiouser and curiouser. Because the slow down caused by facing the object to the right is relatively unnoticeable due to the new slowing by lack of output.
                //Theory: The output does cause the game to speed up, but something about all the values outputted being so simple when the object faces the right makes the console window update in a different way. Perhaps, not update at all?
                //Then why does the mouse speed up the game when there's no output? Should the game be as slow as it is when the mouse isn't moving? Does the update of a mouse cause the window to update at the rate at which the mouse position updates?

                if(teabot.Direction == 'F'){
                        teabot.Velocity.x = cos(((float)teabot.Rotation - 90.0) / 180.0 * (float)PI)*50.0;
                        teabot.Velocity.y = sin(((float)teabot.Rotation - 90.0) / 180.0 * (float)PI)*50.0;
                }

                if(rClock.getElapsedTime().asSeconds() >= 1.0){
                        mReference.setPosition(teabot.Position);
                        rClock.restart();
                }

                //std::cout<<teabot.Direction<<teabot.Velocity.x<<", "<<teabot.Velocity.y<<std::endl; //Whenever the console window updates, the game window updates. This seems to make the game go faster somehow.
                Update(&teabot, gameClock.getElapsedTime().asMicroseconds());

                window.clear(sf::Color::Black);
                window.draw(teabot.Visual);
                window.draw(mReference);
                window.display();

        }

        return 0;
}

If you look at the event loop, there is no reference to sf::Keyboard or sf::Mouse. (I didn't use the members of sf::Event because to do comparisons, I'd have to refer to sf::Keyboard. Something I was told not to do. (In case you hadn't noticed, your post was a bit confusing.))

This is what happened:

It behaved in the exact same way.

I think that at this point, I need a bit more help.

masskiller

  • Sr. Member
  • ****
  • Posts: 284
  • Pointers to Functions rock!
    • MSN Messenger - kyogre_jb@hotmail.com
    • View Profile
    • Email
Re: Issues with game speed
« Reply #3 on: January 20, 2013, 06:00:35 am »
I'm going to sleep now, but I'll try to help tomorrow in the afternoon with some more time, however a small note on some code skimming: Don't use Real-Time Input  when you don't need it, it's pretty much overkill to use it to close the window, verify whether it's necessary or not to use real time input and if not then use events instead.
Programmer, Artist, Composer and Storyline/Script Writer of "Origin of Magic". If all goes well this could turn into a commercial project!

Finally back into the programming world!

awsumpwner27

  • Newbie
  • *
  • Posts: 27
    • View Profile
Re: Issues with game speed
« Reply #4 on: January 20, 2013, 09:26:45 am »
Don't use Real-Time Input  when you don't need it, it's pretty much overkill to use it to close the window, verify whether it's necessary or not to use real time input and if not then use events instead.

Amended.
//switch(event.type)
        case sf::Event::KeyPressed :
                if(event.key.code == sf::Keyboard::Escape)
                window.close();
        break;

Also, if it wouldn't hurt, could you guys tell me if my code looks okay? I feel like I could be making a mistake here. There's pretty much only one object instantiated of the playerCharacter class. I feel like that's a mistake, because I currently only need one player, but I also think I need the organization of data that classes provide. Are there cleaner alternatives, or is what I'm doing okay?

masskiller

  • Sr. Member
  • ****
  • Posts: 284
  • Pointers to Functions rock!
    • MSN Messenger - kyogre_jb@hotmail.com
    • View Profile
    • Email
Re: Issues with game speed
« Reply #5 on: January 21, 2013, 04:47:27 am »
Quote
Also, if it wouldn't hurt, could you guys tell me if my code looks okay? I feel like I could be making a mistake here. There's pretty much only one object instantiated of the playerCharacter class. I feel like that's a mistake, because I currently only need one player, but I also think I need the organization of data that classes provide. Are there cleaner alternatives, or is what I'm doing okay?

I assume that the reason for having everything public in the class is for simplicity in testing and making the code minimal. If not then you should make all variables that are not needed as public private. The usage of references instead of pointers and usage of initialization lists in the constructor. Those are all good programming habits that are worth learning and implementing, but it's become obvious that the problem most likely doesn't lie in that.

There are surely better ways to structure it by going through what is considered to be good programming practice and other standards that make code far more readable.

However if you ask for improvements you can go for that.

The update function should be a member function, not a friend. cmath instead of math.h. #Define when you could have a math global const (in a namespace for better handling). Enums could be used for explicit state handling instead of using a char (even more with C++ 11 enum classes and changes in enums). Static_cast instead of C casts and the list can go on.

Now for the real problem, let passed time in the update function be sf::Time instead of sf::Int32 and use the FPS clock to return time to it directly. Inside the function convert time to seconds (casting microseconds to float may not be right) and check the results.

The call should look like this:

Update(teabot, gameClock.getElapsedTime());
///Using a reference to teabot, not a pointer.
///As it would receive an sf::Time variable this is valid.
///Note that you make the conversion to seconds or whatever time unit you want inside the function.
 

Take note that your char Distance 'F' doesn't change back to another value when there's no input, so that may be a possible cause. An enum (with good naming) would make what you want to do with the class a lot clearer.
And the variable is never initialized, which can be potentially bad, as it can have a random value that has the possibility of being 'F'.

I'll probably test it tomorrow (as I can't right now), but try that for now.
Programmer, Artist, Composer and Storyline/Script Writer of "Origin of Magic". If all goes well this could turn into a commercial project!

Finally back into the programming world!

awsumpwner27

  • Newbie
  • *
  • Posts: 27
    • View Profile
Re: Issues with game speed
« Reply #6 on: March 03, 2013, 11:08:36 am »
I'll probably test it tomorrow
That might be a bit overdue.

Also, I've made a discovery.

It would appear that the time passing between frames doubles when the mouse is moved. However, the game still looks like it's running at 60fps, so the object moves twice as fast as a result. Even stranger, changing the framerate limit with sf::RenderWindow::setFramerateLimit does not change the time passing between frames. (Or, at least doesn't change the value returned from sf::Time::asMicroseconds.)

Why didn't I notice this? I had already written a line of code set to output the data I needed to come to this conclusion! It took over a month of not paying attention to this project, but I figured out more in few minutes than in the hours I spent looking at it before! I'm not even well rested!

awsumpwner27

  • Newbie
  • *
  • Posts: 27
    • View Profile
Re: Issues with game speed
« Reply #7 on: March 04, 2013, 07:11:58 pm »
Here's a question probably needing an answer: Is the problem entirely related to the inaccuracy of the time measured by the sf::Clock? I think it is. Maybe now I can continue working on the project.

io

  • Jr. Member
  • **
  • Posts: 52
  • z/OS by day, SFML by night
    • View Profile
Re: Issues with game speed
« Reply #8 on: March 04, 2013, 11:23:03 pm »
I played w/ your code a little and think I got it to stay constant (though it may just be my eyes playing tricks on me :P):

#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <math.h>
#include <iostream> //For bug fixing

#define PI 3.1415926535

class playerCharacter {
public:
    sf::Vector2f                Position;
    short int                   Rotation;
    sf::Vector2f                Velocity;
    sf::CircleShape             Visual;
    char                        Direction;
    friend void                 Update(playerCharacter *plyr, sf::Int32 passedTime);
};

void Update(playerCharacter *plyr, sf::Time delta  );

int main(){

    //System-related
    sf::Clock gameClock;

    sf::Clock rClock;

    sf::VideoMode vm(800,600);

    sf::RenderWindow window(vm, "Placeholder", 7);

    sf::Vector2f mousePosition;

    playerCharacter teabot;
    teabot.Position = sf::Vector2f((float)window.getSize().x/2, (float)window.getSize().y/2);
    //System-related END

    //Graphics-related
    sf::View view(sf::FloatRect(teabot.Position.x-(float)80, teabot.Position.y-((float)vm.height/(float)vm.width) * (float)80, (float)160, ((float)vm.height/(float)vm.width) * (float)160));

    teabot.Visual.setRadius(128);
    teabot.Visual.setPointCount(4);
    teabot.Visual.setFillColor(sf::Color::Blue);
    teabot.Visual.setOrigin(128, 128);
    teabot.Visual.setScale(1.f/32.f, 1.f/32.f);

    sf::CircleShape mReference(0.4, 5.0);
    mReference.setFillColor(sf::Color::White);
    //Graphics-related END

    //Window options
    window.setVerticalSyncEnabled(true);
    window.setFramerateLimit(60);
    window.setView(view);

    //Game loop
    while(window.isOpen()){
        sf::Event event;
        while(window.pollEvent(event)){
            switch(event.type){
                case sf::Event::Closed :
                    window.close();
                break;
            }
        }
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
            window.close();

        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
            teabot.Direction = 'F';

        mousePosition = (sf::Vector2f) sf::Mouse::getPosition(window);

        view.setCenter(teabot.Position);
        window.setView(view);

        teabot.Visual.setPosition((sf::Vector2f)teabot.Position);
        teabot.Rotation =  90 + atan2( (float)(mousePosition.y + (view.getCenter().y - window.getSize().y/2)) - teabot.Position.y, (float)(mousePosition.x + (view.getCenter().x - window.getSize().x/2)) - teabot.Position.x) / (float)PI * 180;
        teabot.Visual.setRotation(teabot.Rotation);


        if(teabot.Direction == 'F'){
            teabot.Velocity.x = cos(((float)teabot.Rotation - 90.0) / 180.0 * (float)PI)*50.0;
            teabot.Velocity.y = sin(((float)teabot.Rotation - 90.0) / 180.0 * (float)PI)*50.0;
        }


        if(rClock.getElapsedTime().asSeconds() >= 1.0)
        {
            mReference.setPosition(teabot.Position);
            rClock.restart();
        }




        window.clear(sf::Color::Black);
        window.draw(teabot.Visual);
        window.draw(mReference);
        window.display();

        Update(&teabot, gameClock.restart() );

    }

    return 0;
}


void Update(playerCharacter *plyr, sf::Time delta )
{
    float timeFactor = 60.0/(1.0/(delta.asMicroseconds() / 100000000.0));

    plyr->Position.x = plyr->Position.x + plyr->Velocity.x * timeFactor;
    plyr->Position.y = plyr->Position.y + plyr->Velocity.y * timeFactor;
}

 
« Last Edit: March 04, 2013, 11:40:00 pm by io »