I asked this question about a half hour ago, but the code had typos and I wasn't being very clear, so I've deleted and I'm trying again with a better format.
I'm getting a Segmentation Fault in my code, the problem seems to be at the function call if( (*trans).test((*this), *(*itr)) )
inside World::update()
:
void World::update(sf::Time dt)
{
mPlayer->setVelocity(0.f, 0.f);
while (!mCommandQueue.isEmpty()){
Command cmd = mCommandQueue.pop();
cmd.action(cmd.node, dt);
}
mSceneGraph.update(dt);
adaptPlayerPosition();
//Enemy Spawn engine
if (mSpawnTimer.getElapsedTime().asSeconds() >= SPAWN_INTERVAL && mEnemies.size() < MAX_NUM_ENEMIES){
float winX = mWindow.getDefaultView().getSize().x;
float winY = mWindow.getDefaultView().getSize().y;
float x = rand() % (int)winX;
float y = rand() % (int)winY;
spawnEnemy(x, y, EnemyType::Loner, IState::ILWander);
mSpawnTimer.restart();
}
// FSM update
IState::ID curEnemyStateID;
FState curEnemyState;
bool trigger = false;
ICondition triggeredtrans;
FState triggeredState;
for(auto itr = mEnemies.begin(); itr != mEnemies.end(); ++itr){
curEnemyStateID = (*itr)->getState();
// set curState to whatever the enemy's curState is
switch(curEnemyStateID){
case 0:
curEnemyState = LWander;
break;
default:
break;
}
auto tState = curEnemyState.getTransitionStates().begin();
for(auto trans = curEnemyState.getConditions().begin(); trans != curEnemyState.getConditions().end(); ++trans){
if( (*trans).test((*this), *(*itr)) ){
trigger = true;
triggeredState = (*tState);
break;
}
++tState;
}
if(trigger){
(*itr)->setState(IState::ILRushPlayer);
curEnemyState = LRushPlayer;
}
curEnemyState.getAction()->doAction((*this), *(*itr));
}
}
Context:
trans
is an iterator for a std::vector<ICondition> conditions
where each ICondition
has a test(World& world, Enemy& enemy)
. itr
is an iterator through a std::vector<Enemy*>
that is held by World
.
The conditions
vector is filled in this function:
void World::initializeStates()
{
Wander LWanderAction;
LWander.setAction(LWanderAction);
DistFromPlayer LWanderCond1(30);
LWander.pushCondition(LWanderCond1);
LWander.pushTransitionState(LRushPlayer);
}
LWander is a state (FState
) in my Finite State Machine. Wander
is a class that inherits IAction
, and setAction
accepts an IAction
parameter: FState::setAction(IAction iact)
DistFromPlayer
is a class that inherits ICondition
.
FState::pushCondition(ICondition icond)
and FState::pushTransitionState(Fstate state)
should take their arguments and push them to Fstate
's conditions
and states
vectors. (A transition's condition and matching target state should be at the same indices in both)
LWander
and LRushPlayer
are both members of World
.
And that should cover everything. I don't know why I'm getting a SegFault, but I'm assuming that the problem is with how things are pushed into LWander
in World::initializeStates()
. I should also note that the SegFault occurs right after the first enemy is spawned in my game, which is also the same update frame that runs (*trans).test(*this, **itr)
for the first time. All Enemy
s start in the LWander
state.
ICondition's virtual bool test(World& world, Enemy& enemy);
is defined as:
bool ICondition::test(World& world, Enemy& enemy){
return false;
//returns false by default, overwritten later
}
and DistFromPlayer's bool test(World& world, Enemy& enemy);
is defined as:
bool DistFromPlayer::test(World& world, Enemy& enemy)
{
std::cout << "DistFromPlayer (LWander's Transition) was reached
";
return false;
}
and only contains a print statement for debugging purposes.
GDB's backtrace
#0 World::update (this=0x6464408, dt=...) at C:...World.cpp:97
#1 0x0040416b in GameState::update (this=0x64643f0, dt=...) at C:...GameState.cpp:22
#2 0x00402435 in StateStack::update (this=0x28fde0, dt=...) at C:...StateStack.cpp:19
#3 0x00403782 in Game::update (this=0x28fbc0, elapsedTime=...) at C:...Game.cpp:58
#4 0x004036a2 in Game::run (this=0x28fbc0) at C:...Game.cpp:48
#5 0x0040888b in main () at C:...main.cpp:7
See Question&Answers more detail:
os