在我正在开发的基本游戏代码中,我有每个单独的区域" map"有一个单独的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!");
}
}
}
请记住,从区域构造函数,NPC构造函数到攻击函数,没有任何恶作剧。区域构造函数完成,然后游戏调用区域的更新函数,该函数立即调用攻击,其间没有任何区域指针被删除或以任何其他方式修改。
我为这个令人难以置信的冗长答案道歉,并为你倾倒了一堆代码,但我对所有这些东西都很陌生,并且真的不知道该怎么做才能缩小它。如果你需要更多的代码来更好地了解正在发生的事情,我很乐意提供它,我只是在这个问题上喋喋不休地试了几天,并没有取得任何进展。< / p>
编辑:添加一些导致构建区域的代码(删除多余的代码)
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。当游戏循环时,它会调用state-&gt; 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
}
}
}
}
}
编辑编辑:更多代码! areas是一个std :: map
void Game::addArea(Area area)
{
areas.emplace(area.getID(), area);
}
Area& Game::getArea(std::string id)
{
return areas.find(id)->second;
}
答案 0 :(得分:2)
您可以在堆栈上创建Area类的实例:
在void InitState::update()
:
//...
game.addArea(Area(game, "The Cave", "cave"));
//...
然后你的Game :: addArea()会创建一个副本。
但是你可能还没有为class Area
定义一个复制构造函数,它可以处理所有的血腥细节。因此,区域对象的(自动创建的)副本可能包含指向由原始区域实例管理的对象的指针,该指针在上面的行之后被删除。
有一些不同的策略可以解决您的问题:一个简单的策略:在任何地方使用堆分配(new Area(..)
而不仅仅是Area(..)
),并在适用的地方使用智能指针。
您应该阅读有关C ++堆和堆栈分配,自动内存,引用,尤其是const引用等内容。
也许此链接是您的介绍:http://www.learncpp.com/cpp-tutorial/79-the-stack-and-the-heap/
编辑:顺便说一下,只要您不想或不能提供复制构造函数,标记您的对象&#34;不可复制&#34;是一种很好的风格。或者,如果您只是想要禁止它们的副本。 Non-copyable Mixin
答案 1 :(得分:0)
这只是猜测,但在调用“ player.setArea(this);之前调用” game.timer.restart(); “可能是有可能的。 “是问题所在。也许这会导致某些事情被调用,即取消引用该变量。尝试移动“player.setArea(this);”在“ game.timer.restart(); ”行之前行。或者,如果重新启动清除该变量,请将重启操作分为停止和启动操作,如下所示。
game.timer.stop();
player.setArea(this);
game.timer.start();
我希望这会有所帮助。