敵キャラクターの思考パターン


敵キャラクターは次の簡単な思考パターンを実装しています

・前に移動できれば、そのまま前に移動
・前に移動できずに、左右両方に移動できる場合は1/2の確立で左右どちらかに移動
・前と右に移動できずに、左に移動できる場合は左に移動
・前と左に移動できずに、右に移動できる場合は右に移動
・前と左右両方に移動できない場合は後ろに移動

これだけのパターンの思考を持っていれば、停止することなく、
ひたすら移動することができます
敵キャラクターの向きによって前方向、左右方向、後方向は変わってきます
プレイヤーから見て敵キャラクターが上を向いている場合
前は(±0, -1 )
左は( -1,±0 )
右は( +1,±0 )
後は(±0, +1 )
という風にあらわすことが出来ます

敵キャラクターの向きは

Enemy.cppより
int Direction;  // 向き( 0:下 1:左 2:上 3:右 )

としているので、前後左右は次のように設定できます

Enemy.cppより
				// 方向ごとの前方向
				int FrontPos[4][2] =
				{
					{  0,  1 },{ -1,  0 },{  0, -1 },{  1,  0 }
				};
				// 方向ごとの左方向
				int LeftPos[4][2] =
				{
					{  1,  0 },{  0,  1 },{ -1,  0 },{  0, -1 }
				};
				// 方向ごとの前方向
				int RightPos[4][2] =
				{
					{ -1,  0 },{  0, -1 },{  1,  0 },{  0,  1 }
				};
				// 方向ごとの後方向
				int BackPos[4][2] =
				{
					{  0, -1 },{  1,  0 },{  0,  1 },{ -1,  0 }
				};

また敵キャラクタの移動に関する変数は次のように宣言しています

Enemy.cppより
// 敵キャラクターデータ構造体
struct ENEMY_DATA
{
						:
	int NowBlockX;  // 現在のブロック単位での位置( X座標 )
	int NowBlockY;  // 現在のブロック単位での位置( Y座標 )
	int NextBlockX; // 次に移動するブロック単位での位置( X座標 )
	int NextBlockY; // 次に移動するブロック単位での位置( Y座標 )
	int Direction;  // 向き( 0:下 1:左 2:上 3:右 )
						:
};

static ENEMY_DATA EnemyData[ENEMY_NUM];// 敵キャラクターデータ

また、先ほどの思考パターンに一つパターンを追加します

・自分のいるブロックが 2 の場合は無条件で上方向に移動
・前に移動できれば、そのまま前に移動
・前に移動できずに、左右両方に移動できる場合は1/2の確立で左右どちらかに移動
・前と右に移動できずに、左に移動できる場合は左に移動
・前と左に移動できずに、右に移動できる場合は右に移動
・前と左右両方に移動できない場合は後ろに移動

ブロックが 2 の場合、そこは発生地点なので無条件で上に移動させます
これらを元に思考パターンを次のように実装しています
ソースコードはすこし長めですが、一つ一つ整理して、順を追って見ていってください

Enemy.cppより
			int block = CheckMapState( EnemyData[i].NowBlockX, EnemyData[i].NowBlockY );
			if( block == 2 ){
				// 強制移動地点だったら無条件で上に移動
				EnemyData[i].Direction = 2;
				EnemyData[i].NextBlockY--;
			}else{
				// 方向ごとの前方向
				int FrontPos[4][2] =
				{
					{  0,  1 },{ -1,  0 },{  0, -1 },{  1,  0 }
				};
				// 方向ごとの左方向
				int LeftPos[4][2] =
				{
					{  1,  0 },{  0,  1 },{ -1,  0 },{  0, -1 }
				};
				// 方向ごとの前方向
				int RightPos[4][2] =
				{
					{ -1,  0 },{  0, -1 },{  1,  0 },{  0,  1 }
				};
				// 方向ごとの後方向
				int BackPos[4][2] =
				{
					{  0, -1 },{  1,  0 },{  0,  1 },{ -1,  0 }
				};
				int Direction = EnemyData[i].Direction;
				int NextBlockX = EnemyData[i].NextBlockX + FrontPos[Direction][0];
				int NextBlockY = EnemyData[i].NextBlockY + FrontPos[Direction][1];
				if( CheckMapState( NextBlockX, NextBlockY ) == 0 ){
					// 前方向が進入可能ならそのまま前進
					EnemyData[i].NextBlockX = NextBlockX;
					EnemyData[i].NextBlockY = NextBlockY;
				}else{
					int LeftX = EnemyData[i].NextBlockX + LeftPos[Direction][0];
					int LeftY = EnemyData[i].NextBlockY + LeftPos[Direction][1];
					int RightX = EnemyData[i].NextBlockX + RightPos[Direction][0];
					int RightY = EnemyData[i].NextBlockY + RightPos[Direction][1];

					int BlockLeft = CheckMapState( LeftX, LeftY );
					int BlockRight = CheckMapState( RightX, RightY );
					if( (BlockLeft == 0) && (BlockRight == 0) ){
						// 左右両方とも進入可なら1/2の確立で左右どちらかを選択
						int Next = rand() % 2;
						if( Next == 0 ){
							// 左方向に決定
							EnemyData[i].NextBlockX = LeftX;
							EnemyData[i].NextBlockY = LeftY;
							EnemyData[i].Direction += 3;
							EnemyData[i].Direction %= 4;
						}else{
							// 右方向に決定
							EnemyData[i].NextBlockX = RightX;
							EnemyData[i].NextBlockY = RightY;
							EnemyData[i].Direction++;
							EnemyData[i].Direction %= 4;
						}
					}else if( (BlockLeft == 0) && (BlockRight != 0) ){
						// 左方向が進入可で左方向が進入不可の場合は左方向に決定
						EnemyData[i].NextBlockX = LeftX;
						EnemyData[i].NextBlockY = LeftY;
						EnemyData[i].Direction += 3;
						EnemyData[i].Direction %= 4;
					}else if( (BlockLeft != 0) && (BlockRight == 0) ){
						// 右方向が進入可で左方向が進入不可の場合は右方向に決定
						EnemyData[i].NextBlockX = RightX;
						EnemyData[i].NextBlockY = RightY;
						EnemyData[i].Direction++;
						EnemyData[i].Direction %= 4;
					}else if( (BlockLeft != 0) && (BlockRight != 0) ){
						// 左右どちらも進入不可の場合は後ろに移動
						EnemyData[i].NextBlockX += BackPos[Direction][0];
						EnemyData[i].NextBlockY += BackPos[Direction][1];
						EnemyData[i].Direction += 2;
						EnemyData[i].Direction %= 4;
					}
				}
			}




ゲームの構成
アニメーション処理
マップデータ
コインデータ
キャラクターの移動
敵キャラクターの思考パターン
敵キャラクターとのあたり判定
最後に

ゲーム「GetAndRun」

戻る