정답이라고 할 수는 없지만 개인적인 생각에는
class StateMachine { std::list<StatePtr> stateStack; public: StateMachine(State* baseState) { stateStack.push_back(baseState); } void Push(StatePtr newState) { stateStack.front()->Pause(); stateStack.push_front(newState); stateStack.front()->Start(); } void Change(StatePtr newState) { if (stateStack.size() <= 1) return Push(newState); stateStack.front()->Stop(); stateStack.pop_front(); stateStack.push_front(newState); stateStack.front()->Start(); } void Pop() { if (stateStack.size() <= 1) return; stateStack.front()->Stop(); stateStack.pop_front(); stateStack.front()->Resume(); } void Reset() { while (stateStack.size() > 1) { stateStack.front()->Stop(); stateStack.pop_front(); } } void SendMessage(Message& msg) { for (auto& state : stateStack) { if (state->OnMessage(msg)) return; } } };
위와 같이 스택 구조로 만들면… 이전 상태가 기록되어 좋다고 생각합니다. 뭐 이런 느낌???
// 선공, 비선공으로 NPC AI 를 시작 aiStateMachine.Push(offensive ? new OffensiveState(this) : new PeacefulState(this)); // 어떤 조건으로 인해 전투 상태로 변경 aiStateMachine.Push(new CombatState(this)); // 다른 조건으로 NPC가 스킬을 시전 aiStateMachine.Push(new UseSkillState(this)); // 스킬 사용 상태 class UseSkillState : public State { public: virtual bool OnMessage(Message& msg) override { switch (msg.GetType()) { case MessageType::GET_TARGET: // 이전 상태에서 구한다 return false; // ... } } virtual void Start() override { // 대상을 구한다 GetTargetMessage msg; owner->GetStateMachine().SendMessage(msg); if (!msg.HasTarget()) return owner->GetStateMachine().Pop(); // 대상을 못 구했으므로 종료 // 대상에게 스킬 시전 // ... } }