Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I slow down my sprite animations?

Currently I have this player.cpp class that I'm using for my sprite animations. I'm using a counter to update every frame. It animates, but it flies through the animations.

I want to slow this down. I found code that can be used to slow down sprite animations but I'm unsure how to implement it into my current program.

Below are my player.cpp file and following it is the code I found that can slow down sprite animations. When I've tried to add a clock to the counterWalking++ it didn't animate at all, and I've tried implementing this code to the same effect.

player::player()
{
    rect.setSize(sf::Vector2f(32, 32));
    rect.setFillColor(sf::Color::White);
    rect.setPosition(300, 300);
    sprite.setTextureRect(sf::IntRect(0, 0, 32, 32));
}

void player::update()
{
    sprite.setPosition(rect.getPosition());
}

void player::updateMovement()
{
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {

        if (canMoveRight == true) {

            rect.move(movementSpeed, 0);
            sprite.setTextureRect(sf::IntRect(counterWalking * 32, 64, 32, 32));
            direction = 4;
            canMoveUp = true;
            canMoveDown = true;
            canMoveLeft = true;
            canMoveRight = true;
        }
    }
    else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {

        if (canMoveLeft == true) {

            rect.move(-movementSpeed, 0);
            sprite.setTextureRect(sf::IntRect(counterWalking * 32, 32, 32, 32));
            direction = 3;
            canMoveUp = true;
            canMoveDown = true;
            canMoveLeft = true;
            canMoveRight = true;
        }
    }
    else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {

        if (canMoveUp == true) {

            rect.move(0, -movementSpeed);
            sprite.setTextureRect(sf::IntRect(counterWalking * 32, 96, 32, 32));
            direction = 1;
            canMoveUp = true;
            canMoveDown = true;
            canMoveLeft = true;
            canMoveRight = true;
        }
    }
    else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) {

        if (canMoveDown == true) {

            rect.move(0, movementSpeed);
            sprite.setTextureRect(sf::IntRect(counterWalking * 32, 0, 32, 32));
            direction = 2;
            canMoveUp = true;
            canMoveDown = true;
            canMoveLeft = true;
            canMoveRight = true;
        }
    }
    else {
        //Player not moving
    }
    counterWalking++;

    if (counterWalking == 3)
        counterWalking = 0;
}

Here is the code I found that displays a slow animation:

int main()
{
    sf::RenderWindow renderWindow(sf::VideoMode(640, 480), "Demo Game");
    sf::Event event;
    sf::Texture texture;
    texture.loadFromFile("images/player.png");
    sf::IntRect rectSourceSprite(0, 0, 32, 32);
    sf::Sprite sprite(texture, rectSourceSprite);
    sf::Clock clock;

    while (renderWindow.isOpen()) {

        while (renderWindow.pollEvent(event)) {

            if (event.type == sf::Event::EventType::Closed)
                renderWindow.close();
        }

        if (clock.getElapsedTime().asSeconds() > 1.0f) {

            if (rectSourceSprite.left == 96)
                rectSourceSprite.left = 0;
            else
                rectSourceSprite.left += 32;

            sprite.setTextureRect(rectSourceSprite);
            clock.restart();
        }

        renderWindow.clear();
        renderWindow.draw(sprite);
        renderWindow.display();
    }
}
like image 798
agtv Avatar asked Nov 09 '22 21:11

agtv


1 Answers

Since a solution has been given in comment but not implemented in an answer, here's some kind of "code review"

Key Binding

This code is actually using the sf::Keyboard::isKeyPressed and sf::Keyboard::isKeyReleased wich needs to be called every loop while a simple boolean switched when the key is pressed/released could to the work using events.

while (renderWindow.pollEvent(event)) {

            if (event.type == sf::Event::EventType::Closed)
                renderWindow.close();
        }

The Event used in the main loop does also contain information about KeyEvents but isn't used that way. I'll suggest sending the evet to the player eac time a key Event happens:

    while (renderWindow.pollEvent(event)) {
        switch(event.type){
        case sf::Event::EventType::Closed:
            renderWindow.close();
            break;

        case sf::Event::KeyPressed: case sf::Event::KeyReleased:
            myPlayer.keyEvent(event);
            break;
        }
    }

The keyEvent function in player should then look like this:

void player::keyEvent(sf::Event event){
    //Keycode of your keyboard's arrows goes from 71 to 74
    if (event.key.code >= 71 && event.key.code <= 74){
        //Gets the array ID from the enumeration value
        int ID = event.key.code - 71;
        //Stores false if the key is release, and true if it's pressed
        keys[ID] = (event.type == sf::Event::KeyPressed);
    }
}

Wich changes each values of the array in Player.h:

private:
    bool keys[4];

Movement

Now all you have to do is call the player update() function in your game loop each second:

if (clock.getElapsedTime().asSeconds() > 1.0f) {

        if (rectSourceSprite.left == 96)
            rectSourceSprite.left = 0;
        else
            rectSourceSprite.left += 32;

        sprite.setTextureRect(rectSourceSprite);
        myPlayer.update();
        clock.restart();
    }

In the update() function, ou will then build you movement vector based on wich key is pressed:

void player::update()
{
    sf::Vector2f movementVector(0,0);
    //Left
    if (keys[0]){
        movementVector.x -= movementSpeed;
        //Sends the sprite Rectangle position based on the movement type
        move(32);
    }
    //Right
    if (keys[1]){
        movementVector.x += movementSpeed;
        move(64);
    }
    //Up
    if (keys[2]){
        movementVector.y -= movementSpeed;
        move(96);
    }
    //Down
    if (keys[3]){
        movementVector.y += movementSpeed;
        move(0);
    }
}

The move function will then move your sprite Position depending on the movement vector and the counter, the sprite will then be set.
Your movement counter will be incremented up to 30 and your player may only move when this counter is equal to 0, 10 or 20:

void move(int spritePos){
    //Here, the check() function should tell if the player isn't going outside of the screen / in a wall
    if (check(sprite.getPosition() + movementVector)){
        sprite.move(movementVector);
        ++counterWalking %= 30;

        if(!counterWalking % 10)
            sprite.setTextureRect(sf::IntRect(counterWalking / 10 * 32, spritePos, 32, 32));
    }
}

There are multiple ways of doing this, that's only the way I would do it

like image 114
Treycos Avatar answered Nov 15 '22 12:11

Treycos