Как переключаться между двумя различными разделами на листе спрайта, пока пользователь все еще держит клавишу, используя SFML - PullRequest
0 голосов
/ 31 августа 2018

Таким образом, моя единственная цель здесь - перемещать спрайт влево и вправо, и пока спрайт движется, я хочу переключаться между двумя различными частями моего листа спрайта каждые полсекунды.

Я перепробовал все, что мог придумать, поэтому я оставил его работающим без единой реализации необходимой функции. (РЕДАКТИРОВАТЬ: я изменил его, пытаясь следовать советам, данным другим пользователем) Я посмотрел в Интернете, но ничего, что я не смог найти, ответил на мой вопрос, насколько я мог судить. Я уверен, что есть что-то, что я упускаю из виду, и что это довольно просто, но поэтому мне нужен ваш вклад.

Третья часть листа спрайта, которую я хочу использовать, находится при x = 800, анимации, направленные влево, находятся сверху при y = 0, а анимации, направленные вправо, находятся внизу при y = 600

Вот лист спрайтов, который я использую

Первые предназначены для того, чтобы стоять на месте, а вторые два в каждом ряду - это те, между которыми я хочу переключаться во время «ходьбы»

В любом случае, вот мой код:

#include "pch.h"
#include <iostream>
#include "SFML/Graphics.hpp"
#include <random>
#include <unordered_map>

enum State 
{
    Walking,
    Standing
};
enum Direction
{
    Left,
    Right
};

int main(int argc, char ** argv)
{
    /* Gregory */

    sf::Texture GregorySpriteSheet_T;
    GregorySpriteSheet_T.loadFromFile("Images/GregorySpriteSheet.png");
    sf::IntRect GregorySpriteRect(0, 600, 400, 600);
    sf::Sprite Gregory(GregorySpriteSheet_T, GregorySpriteRect);

    sf::RenderWindow renderWindow(sf::VideoMode(1600,800), "SFML 2 Demo");

    sf::Event event;



    sf::Time timePerFrame = sf::seconds(1.0f / 60.0f);
    sf::Clock deltaClock;
    sf::Time timeSinceLastUpdate = sf::Time::Zero;


    State isWalking{ Standing };
    sf::Clock walkClock;
    Direction direction = Right;




    /* RENDER WINDOW LOOP */


    while (renderWindow.isOpen())
    {

        sf::Time deltaTime = deltaClock.restart();
        timeSinceLastUpdate += deltaTime;

        while (timeSinceLastUpdate >= timePerFrame)
        {
            timeSinceLastUpdate -= timePerFrame;



            while (renderWindow.pollEvent(event))
            {
                if (event.type == sf::Event::EventType::Closed || sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
                {
                    renderWindow.close();
                }


                if (event.type == sf::Event::EventType::KeyPressed)
                {
                    if (event.key.code == sf::Keyboard::Right)
                    {
                        isWalking = Walking;
                        direction = Right;
                    }

                }
                if (event.type == sf::Event::EventType::KeyReleased)
                {
                    if (event.key.code == sf::Keyboard::Right)
                    {
                        isWalking = Standing;
                    }

                }


                if (event.type == sf::Event::EventType::KeyPressed)
                {
                    if (event.key.code == sf::Keyboard::Left)
                    {
                        isWalking = Walking;
                        direction = Left;

                    }
                }
                if (event.type == sf::Event::EventType::KeyReleased)
                {
                    if (event.key.code == sf::Keyboard::Left)
                    {
                        isWalking = Standing;

                    }
                }
            }



            if (isWalking == Walking)
            {
                if (direction == Right)
                    GregorySpriteRect.top = 600;
                if (direction == Left)
                    GregorySpriteRect.top = 0;

                if (GregorySpriteRect.left == 0)
                    GregorySpriteRect.left = 400;

                if ((int(walkClock.getElapsedTime().asSeconds() / 1.5f) % 2) == 1)
                {
                    if (GregorySpriteRect.left == 400)
                        GregorySpriteRect.left == 800;
                    if (GregorySpriteRect.left == 800)
                        GregorySpriteRect.left == 400;
                    walkClock.restart();
                }
            }

            {
                using kb = sf::Keyboard;

                    if (kb::isKeyPressed(kb::Right))
                    {
                        Gregory.move(400 * timePerFrame.asSeconds(), 0.0f);
                        direction = Right;
                        isWalking = Walking;
                    }


                    if (kb::isKeyPressed(kb::Left))
                    {
                        Gregory.move(-400 * timePerFrame.asSeconds(), 0.0f);
                        direction = Left;
                        isWalking = Walking;
                    }

                    if (kb::isKeyPressed(kb::Right) && kb::isKeyPressed(kb::Left))
                    {
                        isWalking = Standing;
                    }

            }


            if (isWalking == Standing)
            {
                GregorySpriteRect.left = 0;

                if (direction == Right)
                    GregorySpriteRect.top = 600;
                if (direction == Left)
                    GregorySpriteRect.top = 0;
            }

        }




        Gregory.setTextureRect(GregorySpriteRect);

        renderWindow.clear();
        renderWindow.draw(Gregory);
        renderWindow.display();

    }
                /* END RENDER WINDOW LOOP */



}

Ответы [ 2 ]

0 голосов
/ 12 сентября 2018

Так что для любого, кто попадет сюда в будущем, мне не хватало жизненной линии:

Gregory.setTextureRect(GregorySpriteRect);

Либо в моем заявлении «если» для часов под «if (isWalking == Walking)», либо под ним (как я это сделал здесь). Вставил полный код ниже. Работает в обоих направлениях сейчас. Не уверен, насколько это оптимально, но если вы любитель, как я, это должно помочь.

Также учтите, что я вернул некоторые изменения, предложенные в ответе Ботье. Хотя я должен отдать ему должное за то, что он очень помог мне с рекомендацией использовать enum для ходьбы и стояния, а также для направления. Я также использовал оператор «>» вместо оператора «==», как предложил мой профессор, из-за ошибок округления переменных с плавающей запятой.

Ура!

#include "pch.h"
#include <iostream>
#include "SFML/Graphics.hpp"
#include <random>
#include <unordered_map>

enum State 
{
    Walking,
    Standing
};
enum Direction
{
    Left,
    Right
};

int main(int argc, char ** argv)
{
    /* Gregory */

    sf::Texture GregorySpriteSheet_T;
    GregorySpriteSheet_T.loadFromFile("Images/GregorySpriteSheet.png");
    sf::IntRect GregorySpriteRect(0, 600, 400, 600);
    sf::Sprite Gregory(GregorySpriteSheet_T, GregorySpriteRect);

    sf::RenderWindow renderWindow(sf::VideoMode(1600,800), "SFML 2 Demo");

    sf::Event event;



    sf::Time timePerFrame = sf::seconds(1.0f / 60.0f);
    sf::Clock deltaClock;
    sf::Time timeSinceLastUpdate = sf::Time::Zero;


    State isWalking{ Standing };
    sf::Clock walkClock;
    Direction direction = Right;




    /* RENDER WINDOW LOOP */


    while (renderWindow.isOpen())
    {

        sf::Time deltaTime = deltaClock.restart();
        timeSinceLastUpdate += deltaTime;

        while (timeSinceLastUpdate >= timePerFrame)
        {
            timeSinceLastUpdate -= timePerFrame;



            while (renderWindow.pollEvent(event))
            {
                if (event.type == sf::Event::EventType::Closed || sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
                {
                    renderWindow.close();
                }


                if (event.type == sf::Event::EventType::KeyPressed)
                {
                    if (event.key.code == sf::Keyboard::Right)
                    {
                        isWalking = Walking;
                        direction = Right;
                        GregorySpriteRect.top = 600;
                    }

                }
                if (event.type == sf::Event::EventType::KeyReleased)
                {
                    if (event.key.code == sf::Keyboard::Right)
                    {
                        isWalking = Standing;
                    }

                }


                if (event.type == sf::Event::EventType::KeyPressed)
                {
                    if (event.key.code == sf::Keyboard::Left)
                    {
                        isWalking = Walking;
                        direction = Left;
                        GregorySpriteRect.top = 0;

                    }
                }
                if (event.type == sf::Event::EventType::KeyReleased)
                {
                    if (event.key.code == sf::Keyboard::Left)
                    {
                        isWalking = Standing;
                    }
                }
            }



            if (isWalking == Walking)
            {
                if (direction == Right)
                    GregorySpriteRect.top = 600;
                else if (direction == Left)
                    GregorySpriteRect.top = 0;
                else 
                    GregorySpriteRect.top = 600;

                if (GregorySpriteRect.left == 0)
                    GregorySpriteRect.left = 400;

                if (walkClock.getElapsedTime().asSeconds() > 0.5f)
                {
                    if (GregorySpriteRect.left == 400)
                        GregorySpriteRect.left = 800;
                    else if (GregorySpriteRect.left == 800)
                        GregorySpriteRect.left = 400;
                    else
                        GregorySpriteRect.left += 0;

                    walkClock.restart();
                }

                Gregory.setTextureRect(GregorySpriteRect);

            }

            {
                using kb = sf::Keyboard;

                    if (kb::isKeyPressed(kb::Right))
                    {
                        Gregory.move(400 * timePerFrame.asSeconds(), 0.0f);
                        direction = Right;
                    }


                    if (kb::isKeyPressed(kb::Left))
                    {
                        Gregory.move(-400 * timePerFrame.asSeconds(), 0.0f);
                        direction = Left;
                    }

                    if (kb::isKeyPressed(kb::Right) && kb::isKeyPressed(kb::Left))
                    {
                        isWalking = Standing;
                        direction = Right;
                    }

            }


            if (isWalking == Standing)
            {
                GregorySpriteRect.left = 0;

                if (direction == Right)
                    GregorySpriteRect.top = 600;
                if (direction == Left)
                    GregorySpriteRect.top = 0;
            }

        }




        Gregory.setTextureRect(GregorySpriteRect);

        renderWindow.clear();
        renderWindow.draw(Gregory);
        renderWindow.display();

    }
                /* END RENDER WINDOW LOOP */



}
0 голосов
/ 31 августа 2018

Вот одно предложение, но есть множество альтернатив:

Во-первых, немного переписайте вашу обработку событий, чтобы вы могли различать первый раз, когда удерживается клавиша, и последующие. Простой способ - получить enum State { Standing, Walking } и установить для него соответствующее значение в вашем обработчике ключей (например, «не гуляете и ключ удерживается? Установить состояние на ходьбу»)

Затем, когда игрок начинает ходить, (пере) запускает часы "прогулки".

Наконец, когда вы фактически рендерите своего игрока, проверьте эти часы и разделите истекшее время с момента ходьбы на период ходьбы (это определяет, как долго должна удерживаться одна из рамок для ходьбы). Если таких периодов ходьбы было четное количество, используйте левого шагающего спрайта, в противном случае правого шагающего спрайта.

Эта техника, конечно, легко обобщается для больших наборов ходячих рамок.

...