You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SFML渲染顺序不符合预期问题求助

为何SFML的渲染顺序与预期不符?

我写了这段代码:

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

按预期,player应该渲染在所有cell之上,但实际结果却是标记线下方的cell渲染在了player之上(如图所示),请问这是为什么?

问题截图1
问题截图2

以下是最小复现代码:
简化问题演示

#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. 坐标偏移不一致:cell的x坐标添加了居中偏移量float(1280 - 19 * cell_size)/2,但player的x坐标没有这个偏移,导致两者的网格位置不对应,视觉上可能出现重叠区域。
  2. 渲染顺序逻辑错误:你在遍历地图时,遇到0就绘制cell,遇到7就绘制player。由于遍历是按从上到下、从左到右的顺序执行,player之后的所有cell(同一行右侧、下方所有行)都会在player之后绘制,若这些cell和player视觉位置重叠,就会覆盖player。

解决方法

方法1:统一坐标偏移

给player的位置添加和cell相同的x偏移量,确保两者处于同一网格位置:

case 7:
    float offset = float(1280 - 19 * cell_size) / 2;
    sprite.setPosition(float(x) * cell_size + offset, float(y) * cell_size);
    entity = {x, y};
    window.draw(sprite);
    break;

方法2:强制渲染顺序(推荐)

先绘制所有cell,再单独绘制player,这样无论player在哪个位置,都会处于所有cell之上:

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

float cell_size = 960.f / 19;
float offset = float(1280 - 19 * cell_size) / 2;

// 第一步:绘制所有cell
for (int y = 0; y < 19; ++y) {
    for (int x = 0; x < 19; ++x) {
        if (x >= 3 || y >= 3) continue;
        if (map[y][x] == 0) {
            sf::RectangleShape cell(sf::Vector2f(cell_size, cell_size));
            cell.setPosition(float(x)*cell_size + offset, float(y)*cell_size);
            window.draw(cell);
        }
    }
}

// 第二步:绘制player
for (int y = 0; y < 19; ++y) {
    for (int x = 0; x < 19; ++x) {
        if (x >= 3 || y >= 3) continue;
        if (map[y][x] == 7) {
            sprite.setPosition(float(x)*cell_size + offset, float(y)*cell_size);
            entity = {x, y};
            window.draw(sprite);
            break; // 找到player后直接退出循环,无需继续遍历
        }
    }
}

window.display();

另外,你的事件处理代码存在逻辑问题:每次pollEvent都会执行swap,即使事件不是Up或Left键按下,这会导致不必要的无效交换。建议修改为只在对应按键按下时执行交换:

for (auto event = sf::Event(); window.pollEvent(event);) {
    if (event.type == sf::Event::KeyPressed) {
        int newY = entity.y;
        int newX = entity.x;
        if (event.key.code == sf::Keyboard::Up) {
            newY = entity.y - 1;
            // 确保不会越界
            if (newY >= 0) std::swap(map[entity.y][entity.x], map[newY][entity.x]);
        } else if (event.key.code == sf::Keyboard::Left) {
            newX = entity.x - 1;
            // 确保不会越界
            if (newX >= 0) std::swap(map[entity.y][entity.x], map[entity.y][newX]);
        }
        // 更新entity位置
        entity.y = newY;
        entity.x = newX;
    }
}

内容的提问来源于stack exchange,提问作者Robert Dziubek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 21:52:00