我一直在尝试使用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(¤tID));
backgroundItem wall_2("Images/Wall-l.png", 1, 64, 428, 350, 2, 128, newID(¤tID));
backgroundItem wall_3("Images/Wall-h.png", 64, 1, 500, 422, 128, 2, newID(¤tID));
backgroundItem wall_4("Images/Wall-l.png", 1, 64, 572, 350, 2, 128, newID(¤tID));
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
我不想发布所有内容的主要原因是长度,这是我可以得到它的最短时间,但仍然包含所需的一切。
另外,感谢大家的帮助!
答案 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)为该理论提供了更多证据。