SFML渲染(绘制)顺序

huangapple go评论63阅读模式
英文:

SFML render (draw) order

问题

为什么渲染顺序与我期望的不同?

window.draw(cell);
window.draw(player);

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

最小可复现示例:
SFML渲染(绘制)顺序

#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();
    }
}
英文:

Why is the rendering order different from what I expect it to be?

<!-- language: c++ -->

window.draw(cell);
window.draw(player);

Doing this, player should be rendered on top of any cell. This is what I get though (cells below the line marked are rendered on top of player) – why?:

<img src="https://i.stack.imgur.com/jMNWS.png" width="250" />
<img src="https://i.stack.imgur.com/i640u.png" width="250" />

<p>
</p>


Minimal reproducible example:
SFML渲染(绘制)顺序
<!-- language: c++ -->

#include &lt;SFML/Graphics.hpp&gt;
int main() {
sf::RenderWindow window(sf::VideoMode(1280, 960), &quot;Sample&quot;);
sf::Texture texture; texture.loadFromFile(&quot;assets/images/player.png&quot;);
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 &amp;&amp; event.key.code == sf::Keyboard::Up ? 1 : 0)][entity.x - (event.type == sf::Event::KeyPressed &amp;&amp; event.key.code == sf::Keyboard::Left ? 1 : 0)]);
}
window.clear(sf::Color::Black);
float cell_size = 960.f / 19;
for (int y = 0; y &lt; 19; ++y) {
for (int x = 0; x &lt; 19; ++x) {
sf::RectangleShape cell(sf::Vector2f(cell_size, cell_size));
if (x &gt;= 3 || y &gt;= 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

得分: 3

SFML (Simple and Fast Multimedia Library) 应该遵守绘制对象到窗口的顺序。这意味着最后绘制的对象将显示在其他所有对象的顶部。

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

for (int y = 0; y &lt; 19; ++y) {
    for (int x = 0; x &lt; 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 &lt; 19; ++y) {
    for (int x = 0; x &lt; 19; ++x) {
        sf::RectangleShape cell(sf::Vector2f(cell_size, cell_size));

        if (x &gt;= 3 || y &gt;= 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;
        }

    }
}

// 在绘制所有单元格后绘制玩家
sprite.setPosition(playerPosition);
window.draw(sprite);

window.display();

//...

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

英文:

SFML (Simple and Fast Multimedia Library) should respect the order in which you draw your objects to the window. Meaning, the object that is drawn last will appear on top of all others.

But that is not what I see in your code, specifically the part where all the drawing to the window happens:

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

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

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

    }
}

In your case, when a 7 is encountered, the sprite is drawn, but the loops do not stop there. If there are any cells (with value 0) left in the current row after the sprite has been drawn, they will be drawn after the sprite, making them appear on top of the sprite.

This is why some cells appear on top of the player sprite in your game, even though you might expect the player to always be on top.

So the issue is that you are drawing both the cells and the player in the same nested loops.

One way to fix this issue is to separate the drawing of the player from the cells. You can store the player's position when you encounter a 7 (in playerPosition), and then draw the player after all the cells have been drawn.

Something like:

//...

sf::Vector2f playerPosition;

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

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

        if (x &gt;= 3 || y &gt;= 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();

//...

This way, the player will always be drawn last and therefore will appear on top of all cells.

huangapple
  • 本文由 发表于 2023年6月8日 07:47:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/76427748.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定