2

我有一些 SFML 2.0 代码,我在其中绘制了一个在网格中移动的机器人。网格使用 OpenGL 绘制,机器人图像使用 sf::Texture 加载。我有一些代码可以在用户左键单击时生成墙壁(无碰撞检测)。我做了一个功能,可以在右键单击时删除它们。墙存储在 sf::Sprite 中,然后放入 std::list 并循环绘制。当我调用 list.erase() 程序段错误时。调试器在 sf::transformable = 运算符中显示了一些问题。如何解决。

这是代码:

#include <SFML/Graphics.hpp>
#include <SFML/OpenGL.hpp>
#include <iostream>
#include <list>
using namespace std;
static const size_t WIN_HEIGHT=800, WIN_WIDTH=800;
void drawGrid();
void fixCoords(int & x, int & y);
static list<sf::Sprite> walls;

int main()
{
    // Create the main window
    sf::RenderWindow window(sf::VideoMode(WIN_WIDTH, WIN_HEIGHT), "SFML window");

    /*** Robot code ***/
    sf::Image robotImg;
    robotImg.loadFromFile("robot.png");
    robotImg.createMaskFromColor(sf::Color(89, 167, 45));
    sf::Texture robotTexture;
    robotTexture.loadFromImage(robotImg);
    sf::Sprite robotSpr(robotTexture);
    sf::Sprite t;
    robotSpr.setPosition(sf::Vector2f(400, 405));

    /*****  Wall code  ****/
    int x = 0, y = 0;
    sf::Image wallimg;
    wallimg.loadFromFile("wall.png");
    wallimg.createMaskFromColor(sf::Color(255, 0, 255));
    sf::Texture walltex;
    walltex.loadFromImage(wallimg);
    sf::Sprite wall;
    wall.setTexture(walltex);

    int movex = 0, movey = 0;
    gluOrtho2D(0, WIN_WIDTH, 0, WIN_HEIGHT);
    while (window.isOpen())
    {
        // Process events
        sf::Event event;
        while (window.pollEvent(event))
        {
            // Close window : exit
            if (event.type == sf::Event::Closed)
            {
                window.close();
                return 0;
            }

            if (event.type == sf::Event::MouseButtonPressed )
            {
                if(event.mouseButton.button == sf::Mouse::Left)
                {
                    x = event.mouseButton.x;
                    y = event.mouseButton.y;
                    fixCoords(x, y);
                    wall.setPosition(sf::Vector2f(x, y));
                    walls.push_back(wall);
                }
                if(event.mouseButton.button == sf::Mouse::Right)
                {
                    x = event.mouseButton.x;
                    y = event.mouseButton.y;
                    fixCoords(x, y);
                    for(list<sf::Sprite>::iterator it = walls.begin(); it != walls.end(); it++)
                    {
                        if((it->getPosition().x == x) && (it->getPosition().y == y)) // This line
                            walls.erase(it);
                    }
                }

            }

            if(event.type == sf::Event::KeyPressed)
            {
                if((movex == 0) && (movey == 0))
                {
                    if(event.key.code == sf::Keyboard::Up)
                        movey -= 37;
                    if(event.key.code == sf::Keyboard::Down)
                        movey += 37;
                    if(event.key.code == sf::Keyboard::Left)
                        movex -= 40;
                    if(event.key.code == sf::Keyboard::Right)
                        movex += 40;
                }
            }
        }
        window.pushGLStates();
        window.clear(sf::Color(90, 167, 45));
        // Insert SFML Draws here
        if(movex > 0)
        {
            robotSpr.move(1, 0);
            movex--;
        }
        if(movex < 0)
        {
            robotSpr.move(-1, 0);
            movex++;
        }
        if(movey > 0)
        {
            robotSpr.move(0, 1);
            movey--;
        }
        if(movey < 0)
        {
            robotSpr.move(0, -1);
            movey++;
        }
        window.draw(robotSpr);
        if((x != 0) && (y != 0))
        {
            for(list<sf::Sprite>::iterator it = walls.begin(); it != walls.end(); it++)
            window.draw(*it);
        }

        window.popGLStates();
        // OpenGL Here
        drawGrid();

        // Update the window
        window.display();
    }
}

void drawGrid()
{
    glColor3ub(0, 0, 0);
    glBegin(GL_LINES); // Horizontal lines
    for(int i = 0; i < WIN_HEIGHT; i += WIN_HEIGHT / 20)
    {
        glVertex2i(0, i);
        glVertex2i(WIN_WIDTH, i);
    }
    glEnd();

    glColor3ub(0, 0, 0);
    glBegin(GL_LINES); // Vertical lines
    for(int i = 0; i < WIN_WIDTH; i += WIN_WIDTH / 20)
    {
        glVertex2i(i, 0);
        glVertex2i(i, WIN_HEIGHT);
    }
    glEnd();
}

void fixCoords(int &x, int &y)
{
    /**** Find the nearest x sqare ****/
    for(int i = 1; i < WIN_WIDTH - 1; i += 40)
    {
        if((x >= i) && x <= (i + 40))
        {
            x = i - 1;
            break;
        }
    }
    for(int i = WIN_HEIGHT; i > 0; i -= 40)
    {
        if((y >= i) && y <= (i + 40))
        {
            y = i;
            break;
        }
    }
}
4

1 回答 1

3

这是list<T>容器工作方式的烦恼。

一个list<T>容器被实现为一个双向链表。因此,迭代器需要访问其当前元素才能到达下一个元素。如果你刚刚删除了它的当前元素,一切都会爆炸。

你可以让它像这样工作:

list<sf::Sprite>::iterator it=walls.begin(),next;
while(it!=walls.end()) {
    next = it; next++;
    if((it->getPosition().x == x) && (it->getPosition().y == y))
        walls.erase(it);
    it = next;
}

您也可以将remove_if与适当的谓词类一起使用,但这只会更丑陋且更令人费解。

于 2012-04-30T09:17:07.047 回答