SFML 渲染(绘制)顺序

3
为什么渲染顺序与我的预期不同?
window.draw(cell);
window.draw(player);

这样做,player应该渲染在任何cell的上方。但是我得到的结果是(标记线下方的cell被渲染在player的上方)- 为什么呢?


最小可重现的示例: {{link1:问题 - 简化}}
#include <SFML/Graphics.hpp>

int main() {
    sf::RenderWindow window(sf::VideoMode(1280, 960), "Sample");

    sf::Texture texture; texture.loadFromFile("assets/images/player.png");
    sf::Sprite sprite(texture);

    int **map = new int *[3]{new int[3]{0, 0, 0}, new int[3]{0, 0, 0}, new int[3]{0, 0, 7}};
    struct Entity { int x, y; } entity{};

    while (window.isOpen()) {
        for (auto event = sf::Event(); window.pollEvent(event);) {
            std::swap(map[entity.y][entity.x],map[entity.y - (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Up ? 1 : 0)][entity.x - (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Left ? 1 : 0)]);
        }

        window.clear(sf::Color::Black);

        float cell_size = 960.f / 19;
        for (int y = 0; y < 19; ++y) {
            for (int x = 0; x < 19; ++x) {
                sf::RectangleShape cell(sf::Vector2f(cell_size, cell_size));

                if (x >= 3 || y >= 3) {
                    continue;
                }

                switch (map[y][x]) {
                    case 0:
                        cell.setPosition(float(x) * cell_size + float(1280 - 19 * cell_size) / 2,float(y) * cell_size);
                        window.draw(cell);
                        break;

                    case 7:
                        sprite.setPosition(float(x) * cell_size, float(y) * cell_size);
                        entity = {x, y};
                        window.draw(sprite);
                        break;
                }

            }
        }

        window.display();
    }
}

1
能否提供一个最小可复现的示例? - Dnafiqvss
@Dnafiqvss 当然。我已经编辑了描述。 - Robert Dziubek
1个回答

3

SFML(简单快速的多媒体库)应该尊重你绘制对象到窗口的顺序。也就是说,最后绘制的对象将出现在其他所有对象的上方。

但是我在你的代码中并没有看到这样的情况,特别是在所有绘制窗口的部分:

for (int y = 0; y < 19; ++y) {
    for (int x = 0; x < 19; ++x) {
        //...

        switch (map[y][x]) {
            case 0:
                //...
                window.draw(cell);
                break;

            case 7:
                //...
                window.draw(sprite);
                break;
        }

    }
}

在你的情况下,当遇到一个7时,精灵会被绘制,但循环不会停止。如果在绘制精灵之后当前行中还有任何值为0的单元格,它们将在精灵之后被绘制,使它们显示在精灵的上方。
这就是为什么在你的游戏中,一些单元格会出现在玩家精灵的上方,即使你可能期望玩家始终处于最上层。
所以问题在于你在同一个嵌套循环中同时绘制了单元格和玩家。
解决这个问题的一种方法是将玩家的绘制与单元格分开。当遇到一个7时,你可以将玩家的位置存储在playerPosition中,然后在绘制完所有单元格之后再绘制玩家。
类似这样:
//...

sf::Vector2f playerPosition;

window.clear(sf::Color::Black);

float cell_size = 960.f / 19;
for (int y = 0; y < 19; ++y) {
    for (int x = 0; x < 19; ++x) {
        sf::RectangleShape cell(sf::Vector2f(cell_size, cell_size));

        if (x >= 3 || y >= 3) {
            continue;
        }

        switch (map[y][x]) {
            case 0:
                cell.setPosition(float(x) * cell_size + float(1280 - 19 * cell_size) / 2,float(y) * cell_size);
                window.draw(cell);
                break;

            case 7:
                playerPosition = sf::Vector2f(float(x) * cell_size, float(y) * cell_size);
                entity = {x, y};
                break;
        }

    }
}

// Draw the player after all cells have been drawn
sprite.setPosition(playerPosition);
window.draw(sprite);

window.display();

//...

这样,玩家将始终最后被绘制,因此会出现在所有单元格的顶部。

谢谢!我怎么没想到使用位置缓存和不在原地绘制呢? - Robert Dziubek
谢谢!我怎么没想到使用位置缓存和不在原地绘制呢? - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接