SFML渲染顺序不符合预期问题求助
为何SFML的渲染顺序与预期不符?
我写了这段代码:
window.draw(cell); window.draw(player);
按预期,player应该渲染在所有cell之上,但实际结果却是标记线下方的cell渲染在了player之上(如图所示),请问这是为什么?


以下是最小复现代码:
#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(); } }
问题原因
你的代码存在两个核心问题:
- 坐标偏移不一致:
cell的x坐标添加了居中偏移量float(1280 - 19 * cell_size)/2,但player的x坐标没有这个偏移,导致两者的网格位置不对应,视觉上可能出现重叠区域。 - 渲染顺序逻辑错误:你在遍历地图时,遇到
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
相关产品推荐
相关产品推荐

