C++でのゲーム開発勉強(4)

c++
GitHub - kowara-gan/ProjectCpp: c++勉強用
c++勉強用. Contribute to kowara-gan/ProjectCpp development by creating an account on GitHub.

参考書の4章で作るゲームを作ります。

準備を前回と同じように行います。

ステートマシン

ステートマシンを設計します。状態の遷移を管理するのですが、クラスとしてオブジェクト指向を利用したステートマシンを使うことで拡張性があります。

class AIState
{
public:
	AIState(class AIComponent* owner)
		:mOwner(owner)
		,mTower(nullptr)
		,mEnemy(nullptr)
	{ }
	// 状態ごとの振る舞い
	virtual void Update(float deltaTime) = 0;
	virtual void OnEnter() = 0;
	virtual void OnExit() = 0;
	// 状態名の取得
	virtual const char* GetName() const = 0;
protected:
	class Enemy* mEnemy;
	class Tower* mTower;
	class AIComponent* mOwner;
};

AIStateは基底クラスであり、その派生クラスの実装ではオーバーライドして拡張します。

class AIPatrol : public AIState
{
public:
	AIPatrol(class AIComponent* owner)
		:EnemyState(owner, enemy)
	{
	}

	// 振る舞いをオーバーライドする
	void Update(float deltaTime) override;
	void OnEnter() override;
	void OnExit() override;

	const char* GetName() const override
	{
		return "Patrol";
	}
};

ステートマシンを利用するコンポーネントはステートマシンのポインタを配列で持ち、アップデート関数では現在のステートに動作を委譲するような設計となります。先ほどのステートクラスを使うには登録が必要です。

class AIComponent : public Component
{
public:
	AIComponent(class Actor* owner);

	void Update(float deltaTime) override;
	void ChangeState(const std::string& name);

	// 新しい状態を登録
	void RegisterState(class AIState* state);
private:
	// 状態の名前とインスタンスを対応づけるマップ
	std::unordered_map<std::string, class AIState*> mStateMap;
	// 現在の状態
	class AIState* mCurrentState;
};

経路探索

ここに関しては迷路のゲーム情報学で解説したいので、その記事を参照してください。(まだない)

参考書ではグラフ、幅優先探索、ヒューリスティック(マンハッタン・ユークリッド距離)、欲張り法、A*探索、ダイクストラ法が紹介されます。

ゲーム木

この内容は以下の記事を参照してください。

練習問題

ステートマシンを実装します。判定のためにキャストしており、適切なステート名をつけるかもっと良い方法があるかもしれません。下記のプログラムも参考ですが、A*探索のgifがわかりやすいです。

重力付き4目並べを実装します。ほとんど用意されているので、αβ法を実装するだけです。

float AlphaBetaMax(const BoardState* node, int depth, float alpha, float beta)
{
	if (node->IsTerminal() || depth == 0)
	{
		return node->GetScore();
	}

	float maxValue = -std::numeric_limits<float>::infinity();

	for (const BoardState* child : node->GetPossibleMoves(BoardState::Red))
	{
		maxValue = std::max(maxValue, AlphaBetaMin(child, depth - 1, alpha, beta));
		if (maxValue >= beta)
		{
			return maxValue;
		}
		alpha = std::max(maxValue, alpha);
	}
	return maxValue;
}

float AlphaBetaMin(const BoardState* node, int depth, float alpha, float beta)
{
	if (node->IsTerminal()||depth==0)
	{
		return node->GetScore();
	}

	float minValue = std::numeric_limits<float>::infinity();

	for (const BoardState* child : node->GetPossibleMoves(BoardState::Yellow))
	{
		minValue = std::min(minValue, AlphaBetaMax(child, depth-1, alpha, beta));
		if (minValue <= alpha)
		{
			return minValue;
		}
		beta = std::min(minValue, beta);
	}
	return minValue;
}

const BoardState* AlphaBetaDecide(const BoardState* root ,int maxDepth)
{
	const BoardState* choice = nullptr;
	float maxValue = -std::numeric_limits<float>::infinity();
	float beta = std::numeric_limits<float>::infinity();

	for (const BoardState* child : root->GetPossibleMoves(BoardState::Red))
	{
		float v = AlphaBetaMin(child,maxDepth-1,maxValue, beta);
		if (v > maxValue)
		{
			maxValue = v;
			choice = child;
		}
	}
	return choice;
}

ライセンス元

GitHub - gameprogcpp/code: Game Programming in C++ Code
Game Programming in C++ Code. Contribute to gameprogcpp/code development by creating an account on GitHub.

コメント

タイトルとURLをコピーしました