如何在 VertexArray 中翻转纹理?

How do you flip texture in VertexArray?

我有一个使用顶点数组绘制的 spritesheet 动画。作为一个例子,假设我有一个指向右边的箭头和一个简单的动画。我希望能够在 x 轴上翻转纹理,以便箭头也可以指向左侧,而无需将我的 spritesheet 的大小加倍。

我知道这可以通过使用负比例因子来实现,但是在我必须使用 vertexarray 的情况下,我想知道这是如何实现的。我试着给 texcoords 一个负宽度,但它没有用。这是我尽可能隔离问题的示例代码:

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

int main()
{
    // CREATE THE WINDOW

    sf::RenderWindow window(sf::VideoMode(200, 200), "Arrow");
    window.setFramerateLimit(20);

    // CREATE GRAPHICS

    sf::Texture texArrow;
    texArrow.loadFromFile("Arrow.png");

    sf::VertexArray vaArrow;
    sf::RenderStates rsArrow;
    rsArrow.texture = &texArrow;

    vaArrow.setPrimitiveType(sf::Quads);
    vaArrow.resize(4);

    vaArrow[0].position = sf::Vector2f(0, 0);
    vaArrow[1].position = sf::Vector2f(100, 0);
    vaArrow[2].position = sf::Vector2f(100, 100);
    vaArrow[3].position = sf::Vector2f(0, 100);

    vaArrow[0].texCoords = sf::Vector2f(0, 0);
    vaArrow[1].texCoords = sf::Vector2f(100, 0);
    vaArrow[2].texCoords = sf::Vector2f(100, 100);
    vaArrow[3].texCoords = sf::Vector2f(0, 100);

    // ARROW DIRECTION STATES

    enum Directions { right, left};
    Directions dir = right;

    float AnimationFrame = 0;

    // GAME LOOP

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

            else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) { dir = right; }
            else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) { dir = left; }
        }

        // UPDATE

        switch (dir)
        {
            case right: // NORMAL

                std::cout << "Arrow is now pointing RIGHT" << std::endl;

                vaArrow[0].texCoords = sf::Vector2f(AnimationFrame * 100        ,   0);
                vaArrow[1].texCoords = sf::Vector2f(AnimationFrame * 100 + 100  ,   0);
                vaArrow[2].texCoords = sf::Vector2f(AnimationFrame * 100 + 100  ,   100);
                vaArrow[3].texCoords = sf::Vector2f(AnimationFrame * 100        ,   100);

                break;

            case left: // FLIPPED

                std::cout << "Arrow is now pointing LEFT" << std::endl;

                // THIS IS WHAT I HAVE TRIED BUT IT DOESN'T WORK:

                vaArrow[0].texCoords = sf::Vector2f((AnimationFrame * 100) * -1         ,   0);
                vaArrow[1].texCoords = sf::Vector2f((AnimationFrame * 100 + 100) * -1   ,   0);
                vaArrow[2].texCoords = sf::Vector2f((AnimationFrame * 100 + 100) * -1   ,   100);
                vaArrow[3].texCoords = sf::Vector2f((AnimationFrame * 100) * -1         ,   100);

                break;
        }

        AnimationFrame++;

        if (AnimationFrame == 5) { AnimationFrame = 0; } // Always loop 0 1 2 3 4

        // RENDER

        window.clear();
        window.draw(vaArrow, rsArrow);
        window.display();
    }

    return 0;
}

示例的 Spritesheet:

还有很多天可以解决这个问题,但您的实际想法并不遥远。您是否注意到您基本上是在整个四边形上拉伸箭头的一端?

解决方案非常简单:默认。纹理不重复,它们被固定(意味着边缘上的像素无限重复),这会导致您注意到的故障。

因此,要使您的方法起作用,您要做的就是设置要重复的纹理:

texArrow.setRepeated(true);