为什么只有当我向上移动(以及如何修复)时才会出现这种错误?

时间:2016-08-07 19:27:22

标签: c++ segmentation-fault sfml

我一直在尝试使用SFML和C ++制作基本游戏,但是当我向上走时,我的游戏会出现段错误和崩溃。

段错误发生在我的角色类中此函数的第5行:

let anotherName = text

fatal error: unexpectedly found nil while unwrapping an Optional value

由我的播放器类中的walk函数多次调用:

bool character::collision_check(character *player, backgroundItem *obj, char direction, bool isRunning)
{
    sf::Vector2f player_pos = player->_sprite.getPosition();
    sf::Vector2f obj_pos = obj->_sprite.getPosition();
    int height = obj->height;
    int width = obj->width;

    if (direction == 'u')
    {
        if (isRunning)
        {
            if ((player_pos.y - 8) == (obj_pos.y + (height/2)))
            {
                return 0;
            }
            else if ((player_pos.y - 9) == (obj_pos.y + (height/2)))
            {
                return 0;
            }
            else if ((player_pos.y - 10) == (obj_pos.y + (height/2)))
            {
                return 1;
            }
        }
        else if ((player_pos.y - 8) == (obj_pos.y + (height/2)))
        {
            return 0;
        }
    }
    else if (direction == 'd')
    {
        if (isRunning)
        {
            if ((player_pos.y + 8) == (obj_pos.y - (height/2)))
            {
                return 0;
            }
            else if ((player_pos.y + 9) == (obj_pos.y - (height/2)))
            {
                return 0;
            }
            else if ((player_pos.y + 10) == (obj_pos.y - (height/2)))
            {
                return 1;
            }
        }
        else if ((player_pos.y + 8) == (obj_pos.y - (height/2)))
        {
            return 0;
        }
    }
    else if (direction == 'l')
    {
        if (isRunning)
        {
            if ((player_pos.x - 8) == (obj_pos.x + (width/2)))
            {
                return 0;
            }
            else if ((player_pos.x - 9) == (obj_pos.x + (width/2)))
            {
                return 0;
            }
            else if ((player_pos.x - 10) == (obj_pos.x + (width/2)))
            {
                return 1;
            }
        }
        else if ((player_pos.x - 8) == (obj_pos.x + (width/2)))
        {
            return 0;
        }
    }
    else if (direction == 'r')
    {
        if (isRunning)
        {
            if ((player_pos.x + 8) == (obj_pos.x - (width/2)))
            {
                return 0;
            }
            else if ((player_pos.x + 9) == (obj_pos.x - (width/2)))
            {
                return 0;
            }
            else if ((player_pos.x + 10) == (obj_pos.x - (width/2)))
            {
                return 1;
            }
        }
        else if ((player_pos.x + 8) == (obj_pos.x - (width/2)))
        {
            return 0;
        }
    }

    return 1;
}

我不明白的部分是为什么当我向上移动时(通过按'w')这只是段错误。当我向任何其他方向移动时,它工作正常,即使每次调用collision_check函数都会通过第5行。

使用gdb进行调试时,它告诉我:

void player::walk(character *player, sf::View *main, backgroundItem* obj)
{
    bool canMove = true;
    bool isRunning = false;
    bool move_amount[4];
    short speed = 1;

    if(sf::Keyboard::isKeyPressed(sf::Keyboard::LShift) || sf::Keyboard::isKeyPressed(sf::Keyboard::RShift))
    {
        isRunning = true;
    }


    if(sf::Keyboard::isKeyPressed(sf::Keyboard::S))
    {
        if(player->player_texture_state == 0)
        {
            player->_sprite.setTexture(player->_textures[1]);
            player->player_texture_state = 1;

            for(int i=0;i<5;i++)
            {
                move_amount[i] = player->collision_check(player, obj, 'd', isRunning);
                obj++;

                if (move_amount[i] == 0)
                {
                    canMove = false;
                }
                else
                {
                    speed = move_amount[i];
                }
            }
            if (canMove)
            {
                if (isRunning)
                {
                    speed *= 2;
                }
                player->_sprite.move(0, speed);
                main->move(0, speed);
            }
        }
        else if(player->player_texture_state == 1)
        {
            player->_sprite.setTexture(player->_textures[0]);
            player->player_texture_state = 2;
        }
        else if(player->player_texture_state == 2)
        {
            player->_sprite.setTexture(player->_textures[2]);
            player->player_texture_state = 3;

            for(int i=0;i<5;i++)
            {
                move_amount[i] = player->collision_check(player, obj, 'd', isRunning);
                obj++;

                if (move_amount[i] == 0)
                {
                    canMove = false;
                }
                else
                {
                    speed = move_amount[i];
                }
            }
            if (canMove)
            {
                if (isRunning)
                {
                    speed *= 2;
                }
                player->_sprite.move(0, speed);
                main->move(0, speed);
            }
        }
        else if(player->player_texture_state == 3)
        {
            player->_sprite.setTexture(player->_textures[0]);
            player->player_texture_state = 0;
        }
    }

    else if(sf::Keyboard::isKeyPressed(sf::Keyboard::A))
    {
        if(player->player_texture_state == 0)
        {
            player->_sprite.setTexture(player->_textures[4]);
            player->player_texture_state = 1;

            for(int i=0;i<5;i++)
            {
                move_amount[i] = player->collision_check(player, obj, 'l', isRunning);
                obj++;

                if (move_amount[i] == 0)
                {
                    canMove = false;
                }
                else
                {
                    speed = move_amount[i];
                }
            }
            if (canMove)
            {
                if (isRunning)
                {
                    speed *= 2;
                }   
                player->_sprite.move(-speed, 0);
                main->move(-speed, 0);
            }
        }
        else if(player->player_texture_state == 1)
        {
            player->_sprite.setTexture(player->_textures[3]);
            player->player_texture_state = 2;
        }
        else if(player->player_texture_state == 2)
        {
            player->_sprite.setTexture(player->_textures[5]);
            player->player_texture_state = 3;

            for(int i=0;i<5;i++)
            {
                move_amount[i] = player->collision_check(player, obj, 'l', isRunning);
                obj++;

                if (move_amount[i] == 0)
                {
                    canMove = false;
                }
                else
                {
                    speed = move_amount[i];
                }
            }
            if (canMove)
            {
                if (isRunning)
                {
                    speed *= 2;
                }
                player->_sprite.move(-speed, 0);
                main->move(-speed, 0);
            }
        }
        else if(player->player_texture_state == 3)
        {
            player->_sprite.setTexture(player->_textures[3]);
            player->player_texture_state = 0;
        }
    }

    else if(sf::Keyboard::isKeyPressed(sf::Keyboard::D))
    {
        if(player->player_texture_state == 0)
        {
            player->_sprite.setTexture(player->_textures[7]);
            player->player_texture_state = 1;

            for(int i=0;i<5;i++)
            {
                move_amount[i] = player->collision_check(player, obj, 'r', isRunning);
                obj++;

                if (move_amount[i] == 0)
                {
                    canMove = false;
                }
                else
                {
                    speed = move_amount[i];
                }
            }
            if (canMove)
            {
                if (isRunning)
                {
                    speed *= 2;
                }           
                player->_sprite.move(speed, 0);
                main->move(speed, 0);
            }
        }
        else if(player->player_texture_state == 1)
        {
            player->_sprite.setTexture(player->_textures[6]);
            player->player_texture_state = 2;
        }
        else if(player->player_texture_state == 2)
        {
            player->_sprite.setTexture(player->_textures[8]);
            player->player_texture_state = 3;

            for(int i=0;i<5;i++)
            {
                move_amount[i] = player->collision_check(player, obj, 'r', isRunning);
                obj++;

                if (move_amount[i] == 0)
                {
                    canMove = false;
                }
                else
                {
                    speed = move_amount[i];
                }
            }
            if (canMove)
            {
                if (isRunning)
                {
                    speed *= 2;
                }
                player->_sprite.move(speed, 0);
                main->move(speed, 0);
            }
        }
        else if(player->player_texture_state == 3)
        {
            player->_sprite.setTexture(player->_textures[6]);
            player->player_texture_state = 0;
        }
    }

    else if(sf::Keyboard::isKeyPressed(sf::Keyboard::W))
    {
        if(player->player_texture_state == 0)
        {
            player->_sprite.setTexture(player->_textures[10]);
            player->player_texture_state = 1;

            for(int i=0;i<5;i++)
            {
                move_amount[i] = player->collision_check(player, obj, 'u', isRunning);
                obj++;

                if (move_amount[i] == 0)
                {
                    canMove = false;
                }
                else
                {
                    speed = move_amount[i];
                }
            }
            if (canMove)
            {
                if (isRunning)
                {
                    speed *= 2;
                }
                player->_sprite.move(0, -speed);
                main->move(0, -speed);
            }
        }
        else if(player->player_texture_state == 1)
        {
            player->_sprite.setTexture(player->_textures[9]);
            player->player_texture_state = 2;
        }
        else if(player->player_texture_state == 2)
        {
            player->_sprite.setTexture(player->_textures[10]);
            player->player_texture_state = 1;

            for(int i=0;i<5;i++)
            {
                move_amount[i] = player->collision_check(player, obj, 'u', isRunning);
                obj++;

                if (move_amount[i] == 0)
                {
                    canMove = false;
                }
                else
                {
                    speed = move_amount[i];
                }
            }
            if (canMove)
            {
                if (isRunning)
                {
                    speed *= 2;
                }
                player->_sprite.move(0, -speed);
                main->move(0, -speed);
            }
        }
        else if(player->player_texture_state == 3)
        {
            player->_sprite.setTexture(player->_textures[9]);
            player->player_texture_state = 0;
        }
    }
}

当我要求它打印Program received signal SIGSEGV, Segmentation fault. 0x0804bef3 in character::collision_check (this=0xbfffe840, player=0xbfffe840, obj=0xbfffffa0, direction=117 'u', isRunning=false) at character_class.cpp:53 53 int height = obj->height; 的值时,它会说:

obj->height

任何有关此问题的帮助都会非常感激,这让我很生气!

修改

问题是在user2421739的答案中所述,但是这里要求的是使其最小化,完整和可验证的代码:

Main.cpp的:

Cannot access memory at address 0xc00000d4

backgroundItem_class.hpp:

#include "header.hpp"
#include "backgroundItem_class.hpp"
#include "character_class.hpp"
#include "player_class.hpp"

int newID(int* currentID)
{
    return *currentID++;
}

int main()
{
    int currentID = 0;

    sf::RenderWindow window(sf::VideoMode(1024, 768), "Game", sf::Style::Fullscreen);
    window.setVerticalSyncEnabled(true);

    sf::View main(sf::Vector2f(500, 350), sf::Vector2f(300, 200));

    player player("Images/Player-0.png", "Images/Player-1.png", "Images/Player-2.png", "Images/Player-3.png",
                "Images/Player-4.png", "Images/Player-5.png", "Images/Player-6.png", "Images/Player-7.png",
                "Images/Player-8.png", "Images/Player-9.png", "Images/Player-10.png", "Images/Player-11.png");


    backgroundItem wall_1("Images/Wall-h.png", 64, 1, 500, 278, 128, 2, newID(&currentID));
    backgroundItem wall_2("Images/Wall-l.png", 1, 64, 428, 350, 2, 128, newID(&currentID));
    backgroundItem wall_3("Images/Wall-h.png", 64, 1, 500, 422, 128, 2, newID(&currentID));
    backgroundItem wall_4("Images/Wall-l.png", 1, 64, 572, 350, 2, 128, newID(&currentID));

    backgroundItem item_array[4] = {wall_1, wall_2, wall_3, wall_4};

    while(window.isOpen())
    {
        player.walk(&player, &main, item_array);

        sf::Event event;
        while(window.pollEvent(event))
        {
            if((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))
            {
                window.close();
            }
        }
        window.setView(main);
        window.clear(sf::Color::White);

        window.draw(player._sprite);
        window.draw(wall_1._sprite);
        window.draw(wall_2._sprite);
        window.draw(wall_3._sprite);
        window.draw(wall_4._sprite);

        window.display();
        sf::sleep(sf::milliseconds(125));
    }
    return 0;
}

backgroundItem_class.cpp:

#ifndef BACKGROUNDITEM_CLASS
#define BACKGROUNDITEM_CLASS

#include "header.hpp"
using namespace std;

class backgroundItem
{
public:
    backgroundItem(string, int, int, int, int, int, int, int);
    backgroundItem();

    sf::Sprite _sprite;
    sf::Texture _texture;
    int width;
    int height;
    int id;
};

#endif

character_class.hpp:

#include "header.hpp"
#include "backgroundItem_class.hpp"

backgroundItem::backgroundItem(string filename, int originX, int originY, int positionX, int positionY, int width, int height, int id)
:width(width), height(height), id(id)
{
    if(!_texture.loadFromFile(filename))
    {
        assert(false);
    }
    _sprite.setTexture(_texture);

    _sprite.setOrigin(originX, originY);
    _sprite.setPosition(positionX, positionY);
}

backgroundItem::backgroundItem()
{}

character_class.cpp:

#ifndef CHARACTER_CLASS
#define CHARACTER_CLASS

#include "header.hpp"
#include "backgroundItem_class.hpp"

using namespace std;

class character
{
public:
    character(string, string, string, string, string, string, string, string, string, string, string, string);
    character();

    void setFilenames(string, string, string, string, string, string, string, string, string, string, string, string);
    void setTextures(string[12]);

    bool collision_check(character*, backgroundItem*, char, bool);
    virtual void walk() {};

    sf::Sprite  _sprite;
    sf::Texture _textures[12];
    short player_texture_state;

protected:
    string _filenames[12];
};

#endif

header.hpp:

#include "header.hpp"
#include "character_class.hpp"
#include "backgroundItem_class.hpp"

void character::setFilenames(std::string file_a, std::string file_b, std::string file_c, std::string file_d, std::string file_e, std::string file_f, std::string file_g, std::string file_h, std::string file_i, std::string file_j, std::string file_k, std::string file_l)
{
    _filenames[0] = file_a;
    _filenames[1] = file_b;
    _filenames[2] = file_c;
    _filenames[3] = file_d;
    _filenames[4] = file_e;
    _filenames[5] = file_f;
    _filenames[6] = file_g;
    _filenames[7] = file_h;
    _filenames[8] = file_i;
    _filenames[9] = file_j;
    _filenames[10] = file_k;
    _filenames[11] = file_l;
}


void character::setTextures(std::string _filenames[12])
{
    for(int i=0; i<12; i++)
        {
            if(!_textures[i].loadFromFile(_filenames[i]))
            {
                assert(false);
            }
        }
}


character::character(std::string file_a, std::string file_b, std::string file_c, std::string file_d, std::string file_e, std::string file_f, std::string file_g, std::string file_h, std::string file_i, std::string file_j, std::string file_k, std::string file_l)
:player_texture_state(0)
{
    setFilenames(file_a, file_b, file_c, file_d, file_e, file_f, file_g, file_h, file_i, file_j, file_k, file_l);
    setTextures(_filenames);

    _sprite.setTexture(_textures[0]);
    _sprite.setOrigin(8, 8);
    _sprite.setPosition(500, 350);
}

character::character()
:player_texture_state(0)
{}

/*And character::collision_check as up there*/

player_class.hpp:

#ifndef HEADER
#define HEADER

#include <string.h>
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <assert.h>

#endif

player_class.cpp:

#ifndef PLAYER_CLASS
#define PLAYER_CLASS

#include "header.hpp"
#include "backgroundItem_class.hpp"
#include "character_class.hpp"

using namespace std;

class player: public character
{
public:
    player(string, string, string, string, string, string, string, string, string, string, string, string);
    void walk(character*, sf::View*, backgroundItem*);

    short player_texture_state;
};

#endif

我不想发布所有内容的主要原因是长度,这是我可以得到它的最短时间,但仍然包含所需的一切。

另外,感谢大家的帮助!

2 个答案:

答案 0 :(得分:2)

您的move_amount数组只有四个元素,但您的循环正在访问五个元素。这会导致未定义的行为,这很可能是代码崩溃的原因。

答案 1 :(得分:0)

如评论中所述,如果没有更多细节,我们无法给出确切的答案。如前面的答案中所述,move_amount的长度应为5,否则堆栈将被破坏。

然而,调试器输出可能会给崩溃提供不同的线索。

    for(int i=0;i<5;i++)
        {
            move_amount[i] = player->collision_check(player, obj, 'u', isRunning);
            obj++;

可能是输入参数obj不是数组还是数组太短? obj ++将指针移动到数组中的下一个元素。与move_amount的问题类似,越过末尾可能会导致分段错误。

指针值跨越页边界(0xc000000)为该理论提供了更多证据。