StateMachine 状態遷移マシンを作ってみたw

# 状態遷移マシンとは？
* 簡単に言うと・・・
    * 状態を管理して、状態同士の遷移を行うことです。
* 各遷移する状態を表す状態は以下の要件があれば十分です
    * 各状態は、特定のタイミングで指定した関数を実行する
* 状態遷移マシンでは、マシンがすべての状態を登録、抹消、切り替えだけをする。
* ゲームに使える状態遷移マシンは、そこまで複雑なのは必要ではありません。

# コード
```cpp:StateMachine

//-------------------------------------------------
// 状態管理クラス
// 
// StateMachine : 状態の管理部分
// StateBase : 状態の基底クラス
// StateSwitch : 状態を切り替えるクラス
//--------------------------------------------------


#include <iostream>
#include <unordered_map>
#include <string>
#include <memory>


class StateBase
{
public:
	StateBase() :
		isNext(false)
	{

	};

	// アップデートの前に呼ばれる
	virtual void Start() = 0;

	// アップデート
	virtual void Update() = 0;

	// 状態が変わるときの処理
	virtual void OnChangeEvent() = 0;

	// 切り替える条件を取得
	bool IsNext()const{ return isNext; }

protected:
	// 次に行くための条件
	bool isNext;

};


// 状態の切り替えクラス
class StateSwitch
{
public:
	StateSwitch() = default;
	StateSwitch(const std::shared_ptr<StateBase> state, const std::string nextRegisterName) :
		state(state), nextRegisterName(nextRegisterName)
	{
	}

	// アップデートの前に呼ばれる
	void Start()
	{
		state->Start();
	}

	// アップデート
	void Update()
	{
		state->Update();
	}

	// 次の状態にいけるかどうか
	bool CanNextState()
	{
		if (state->IsNext())
		{
			state->OnChangeEvent();
			return true;
		}
		return false;
	}

	// 次に行く登録した名前
	const std::string nextRegisterName;

private:
	// 親クラス
	std::shared_ptr<StateBase> state;
};

// 状態管理
class StateMachine
{
public:
	StateMachine():
		nowState()
	{

	}

	void Update()
	{
		nowState->Update();
		if (nowState->CanNextState())
		{
			auto it = stateMap.find(nowState->nextRegisterName);
			if (it == stateMap.end()) return;

			nowState = it->second;
			nowState->Start();
		}
	}

	// 登録する
	void Register(const std::string& name, const std::shared_ptr<StateSwitch> state)
	{
		stateMap.insert(std::make_pair(name, state));
		std::cout << "StateMachine : " << name << "を登録" << std::endl;
	}

	// 最初から始める状態を設定
	void SetStartState(const std::string& registerName)
	{
		auto it = stateMap.find(registerName);
		if (it == stateMap.end()) return;

		std::cout << "StateMachine : " << it->first << "をスタート状態に設定" << std::endl;

		nowState = it->second;
		nowState->Start();

	}

	// 登録したものを削除する
	void Deregistration(const std::string& registerName)
	{
		auto it = stateMap.find(registerName);
		if (it == stateMap.end()) return;
		
		std::cout << "StateMachine : " << it->first << "を登録を削除する" << std::endl;

		stateMap.erase(it);
	}

	// すべての登録を削除する
	void AllDeregistration()
	{
		std::cout << "StateMachine : " << "すべての登録を削除する" << std::endl;

		stateMap.clear();
	}

private:
	std::unordered_map<std::string, std::shared_ptr<StateSwitch>> stateMap;
	std::shared_ptr<StateSwitch> nowState;
};

// 移動状態クラス
class PlayerMover:public StateBase
{
public:
	PlayerMover()
	{

	}

	void Start()
	{
		std::cout << "PlayerMover : " << "スタート" << std::endl;
	}

	void Update()
	{
		std::cout << "PlayerMover : " << "アップデート" << std::endl;
		isNext = true;
	}

	// 状態が変わるときの処理
	void OnChangeEvent()
	{
		isNext = false;
		std::cout << "PlayerMover : "<< "切り替わるイベントに入った" << std::endl;
	}

private:

};

// 攻撃状態クラス
class PlayerAttacker :public StateBase
{
public:
	PlayerAttacker()
	{

	}

	void Start()
	{
		std::cout << "PlayerAttacker : " << "スタート" << std::endl;
	}

	void Update()
	{
		std::cout << "PlayerAttacker : " << "アップデート" << std::endl;
		isNext = true;
	}

	void OnChangeEvent()
	{
		isNext = false;
		std::cout << "PlayerAttacker : " << "切り替わるイベントに入った" << std::endl;
	}

private:

};

// 止まる状態クラス
class PlayerStoper :public StateBase
{
public:
	PlayerStoper()
	{

	}


	void Start()
	{
		std::cout << "PlayerStoper : " << "スタート" << std::endl;
	}

	void Update()
	{
		std::cout << "PlayerStoper : " << "アップデート" << std::endl;
		//isNext = true;
	}

	void OnChangeEvent()
	{
		isNext = false;
		std::cout << "PlayerStoper : " << "切り替わるイベントに入った" << std::endl;
	}

private:

};

class Player
{
public:
	Player():
		stateMachine(std::make_unique<StateMachine>())
	{
		const std::string moveName = "PlayerMove";
		const std::string attackName = "PlayerAttack";
		const std::string stopName = "PlayerStop";

		auto moveState = std::make_shared<StateSwitch>(std::make_shared<PlayerMover>(), attackName);
		auto attackState = std::make_shared<StateSwitch>(std::make_shared<PlayerAttacker>(), stopName);
		auto stopState = std::make_shared<StateSwitch>(std::make_shared<PlayerStoper>(), moveName);

		stateMachine->Register(moveName, moveState);
		stateMachine->Register(attackName, attackState);
		stateMachine->Register(stopName, stopState);

		stateMachine->SetStartState(moveName);

	}

	void Update()
	{
		stateMachine->Update();
	}

private:
	std::unique_ptr<StateMachine> stateMachine;
};



int main()
{
	std::unique_ptr<Player> player;
	player = std::make_unique<Player>();

	player->Update();
	player->Update();
	player->Update();
	player->Update();

	return 0;
}



```

# 状態遷移マシンがあるといいこと
* 細かく状態が分けることが可能です。
* 他人とのコーディングがしやすくなると思います。
* オブジェクトに依存しなくてよくなる
    * 例) プレイヤーに状態の処理を書かないようになる