在我正在开发的基本游戏代码中,“ map ”的每个单独区域都有一个单独的 Area 类,用于处理战斗和各种其他基本功能。 Area 中包含的每个实体都有一个指向该 Area 的指针,因此它可以访问 Area 函数等,但是该指针显然已被删除或发生了一些奇怪的事情,因为当它尝试取消引用它时,我会得到各种运行时信息错误。
发生这种情况是因为我在每个 NPC 的构造函数中给了一个指向 Area 的指针吗?
区域构造器
Area::Area(Game& game, std::string name, std::string id)
: GameState(game), game(game), player(game.getPlayer()), log(game, "log", 0.0f, 90.0f, 32, game.getFont("Times"), sf::Color::White)
{
game.clearStrings();
this->id = id;
this->name = name;
game.timer.restart();
player.setArea(this);
game.addString(DisplayString(&game, name, name + "title", game.getFont("Celt"), 10.0f, 10.0f, 64, sf::Color::White));
//
this->addEnemy(NPC(game, this, "Skeleton", "skel", 30, 0, 7, 10, 5, 5));
this->addEnemy(NPC(game, this, "Skeleton", "skel", 30, 0, 7, 10, 5, 5));
int offsetY = 0;
for (std::map<std::string, NPC>::iterator it = enemies.begin(); it != enemies.end(); ++it)
{
game.addString(DisplayString(&game, it->second.getName(), it->first, game.getFont("Times"), WINDOW_WIDTH, 0, 64, sf::Color::White));
DisplayString& name = game.getString(it->second.getID());
game.addString(DisplayString(&game, std::to_string(it->second.hp) + " / " + std::to_string(it->second.maxhp), it->second.getID() + "hp", game.getFont("Times"), WINDOW_WIDTH, name.Text.getGlobalBounds().height, 64, sf::Color::White));
name.setPos(WINDOW_WIDTH - name.Text.getGlobalBounds().width, offsetY);
offsetY += name.Text.getGlobalBounds().height;
DisplayString& hp = game.getString(it->second.getID() + "hp");
hp.setPos(WINDOW_WIDTH - hp.Text.getGlobalBounds().width, offsetY+name.Text.getGlobalBounds().height);
offsetY += hp.Text.getGlobalBounds().height;
}
}
NPC 构造者
NPC::NPC(Game& game, Area* area, std::string name, std::string id, int hp, int ap, int agil, int str, int dmg, int speed)
: game(game)
{
this->name = name;
this->hp = hp;
this->maxhp = hp;
this->ap = ap;
this->dmg = dmg;
this->agil = agil;
this->str = str;
this->speed = speed;
this->area = area;
this->id = id + std::to_string(game.enemyID++);
}
这就是我在取消引用 NPC 类的区域指针时遇到麻烦的地方
void NPC::attack(Player& player)
{
if (rand() % 100 + 1 < 5)
{
int damage = 2 * (this->dmg + (rand() % 6 - 3));
player.hp -= damage;
//any of these area pointers in the debugger show up with garbage data
area->log.addLine(this->name + " critically strikes " + player.getName() + " for " + std::to_string(damage) + "!");
}
else
{
if (rand() % 100 + 1 > 15)
{
int damage = this->dmg + (rand() % 6 - 3);
player.hp -= damage;
area->log.addLine(this->name + " hits " + player.getName() + " for " + std::to_string(damage) + "!");
}
else
{
area->log.addLine(player.getName() + " dodges!");
}
}
}
请记住,从 Area 构造函数到 NPC 构造函数,再到 Attack 函数,没有发生任何恶作剧。 Area 构造函数完成,然后游戏调用 Area 的更新函数,该函数立即调用 Attack,并且区域指针不会被删除或以任何其他方式修改。
我为这个令人难以置信的冗长答案和向你倾倒一堆代码表示歉意,但我对所有这些东西都是新手,真的不知道要剪掉什么来压缩它。如果您需要更多代码来更好地了解正在发生的事情,我很乐意提供它,我已经为此绞尽脑汁好几天了,试图解决它,但没有取得任何进展。
编辑:添加一些导致区域构造的代码(删除无关代码)
void InitState::update()
{
if(main.isOpen())
{
sf::Event event;
while (main.pollEvent(event))
{
switch (event.type)
{
case sf::Event::Closed:
main.close();
game.Stop();
break;
case sf::Event::KeyReleased:
switch (event.key.code)
{
break;
case sf::Keyboard::Key::Return:
switch (var)
{
case NAME:
if (writing)
{
game.delIcon("inputbox");
player.setName(game.getString("input").Text.getString());
game.addArea(Area(game, "The Cave", "cave"));
game.setState(&game.getArea("cave"));
}
default:
break;
}
break;
}
break;
}
}
}
InitState 是一个 GameState,Area 也是一个 GameState。当游戏循环时,它会调用 state->update() 和 render(),因此当游戏设置状态时,它会切换到该类的 update 和 render 函数。
区域更新功能
void Area::update()
{
if (game.getWindow().isOpen())
{
sf::Event event;
while (game.getWindow().pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
game.getWindow().close();
game.Stop();
}
if (event.type == sf::Event::KeyReleased)
{
if (event.key.code == sf::Keyboard::Key::Return)
{
doCombat(); // calls attack functions for NPC and player
}
}
}
}
}
编辑编辑:更多代码! 区域是一个 std::map
void Game::addArea(Area area)
{
areas.emplace(area.getID(), area);
}
Area& Game::getArea(std::string id)
{
return areas.find(id)->second;
}
最佳答案
您在堆栈上创建 Area 类的实例:
在void InitState::update()
中:
//...
game.addArea(Area(game, "The Cave", "cave"));
//...
然后您的 Game::addArea() 创建它的拷贝。
但是您可能还没有为类 Area
定义一个复制构造函数,它处理所有的细节。因此,区域对象的(自动创建的)拷贝可能包含指向原始区域实例管理的对象的指针,该实例在上一行之后被删除。
有一些不同的策略可以解决您的问题:一个简单的策略:使用堆分配(new Area(..)
而不仅仅是 Area(..)
)无处不在,并在适用的情况下使用智能指针。
您应该阅读有关 C++ 堆和堆栈分配、自动内存、引用(尤其是 const 引用)的内容。
也许这个链接是给你的介绍:http://www.learncpp.com/cpp-tutorial/79-the-stack-and-the-heap/
编辑:顺便说一句,每当您不想或无法提供复制构造函数时,将对象标记为“不可复制”是一种很好的风格。或者如果您只是想禁止它们的拷贝。 Non-copyable Mixin
关于c++ - 在构造函数 C++ 中将指针传递给 self,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23749209/