2Dゲーム制作㉛(2025/10/29)

引き続き爆発処理を実装していく。
(Explosion.cpp)

bool Explosion::Update(void)
{
	if (enemyFlag == true) {
		enemyCounter++;
		if (enemyCounter >= ENEMY_EXPLOSION_TIME) EnemyExplosionEnd();
	}
	if(playerFlag == true) {
		playerCounter++;
		if (playerCounter >= PLAYER_EXPLOSION_TIME) PlayerExplosionEnd();
	}
	return true;
	}

bool Explosion::Draw(void)
{
		if (enemyFlag == true) {
			DrawGraph(enemyPos.x, enemyPos.y, image, true);
		}
		if(playerFlag == true) {
			if ((playerCounter / 4) % 2 == 0){
				// 点滅処理
				DrawGraph(playerPos.x, playerPos.y, image, true);
				return true;
			}
		}
		return true;
	}
  1. playerCounter / 4
    → カウンタを4で割って「4フレームごとに1増える値」に変換してる。
    つまり「4フレームを1単位」として周期を作ってる。
  2. ( ... ) % 2 == 0
    → その単位が偶数のとき(=ON)、奇数のとき(=OFF)で切り替える。

🧠 結果的な動作

  • 4フレーム分は true(表示)
  • 次の4フレーム分は false(非表示)
  • これを繰り返す

つまり、**「8フレーム周期で点滅」**してます。
(4フレーム表示 → 4フレーム消える → また表示 → …)

💡 まとめ


内容
意味
/4「4フレームごとに切り替える」スピード調整
%2「ON/OFFの交互制御」
結果8フレーム周期で1回点滅(4フレーム表示・4フレーム非表示)

(by ChatGPT)


プレイヤー撃破時の爆発表示を実装。
(GameScene.cpp)

bool GameScene::CollisionCheckEnemyBullet(void)
{
	if (pl->GetAlive() == false) return false;
	{
		for (int yy = Enemy::Enemy_DISP_YNUM -1; yy >= 0; yy--) {
			for (int xx = 0; xx < Enemy::ENEMY_DISP_XNUM; xx++) {
				if (eBullet->GetAlive(xx.yy) == true) {
					//敵弾が存在している
					POSITION ebPos = eBullet->GetPos(xx,yy);
					if ((pl->GetPos().y + Player::PLAYER_HIG > ebPos.y)					//プレイヤーの下端>敵弾の上端
						&& (pl->GetPos().y < ebPos.y + EnemyBullet::ENEMY_BULLET_HIG)	//プレイヤーの上端<敵弾の下端
						&& (pl->GetPos().x < ebPos.x + EnemyBullet::ENEMY_BULLET_WID)	//プレイヤーの左端<敵弾の右端
						&& (pl->GetPos().x + Player::PLAYER_WID > ebPos.x))				//プレイヤーの右端>敵弾の左端
					{
						//プレイヤーに命中
						eBullet->SetAliveOff(xx, yy);//敵弾を消滅させる
						pl->SetAliveOff();	//プレイヤーを撃破状態にする

			POSITION pos = pl->GetPos();
			pos.x -= (Explosion::EXPLOSION_WID - Player::PLAYER_WID) / 2;
			Application::WINDOW_HIG - Player::PLAYER_HIG;
			expl->PlayerExplosionStart(pos);//爆発エフェクトの生成

						return true;
					}
				}
			}

		}
	}
	return false;


}

※爆発の表示座標(プレイヤー撃破時)

pos.x -= (Explosion::EXPLOSION_WID - Player::PLAYER_WID) / 2;
pos.y = Application::WINDOW_HIG - Explosion::EXPLOSION_HIG;

これは:

  1. X座標 → 爆発画像がプレイヤーより横に大きいので、
    「中心を合わせる」ために左へ半分ずらす。
  2. Y座標 → 爆発画像が縦に大きいので、
    「下端がウィンドウの底ギリギリになるように」上に持ち上げている。

Player画像 は「機体の下端(足)」がウィンドウの底に接している。
pos.y = Application::WINDOW_HIG - Player::PLAYER_HIG;

Explosion画像 は「中心が膨らむ」タイプ。
→ 同じYで描くと、半分が下に隠れる
→ 爆発の中心がプレイヤー機体の中央にくる=自然な見た目。


📊 つまり:

行動意図
x を左にずらす横方向で画像の中心を合わせる
y を上にずらす爆発の下端が画面に隠れないようにする(全体を見せる)

👁️‍🗨️ 実際に表示される見た目

“爆発の重心=機体の中心” という演出バランス。
・プレイヤーの位置を基準に爆発が「ちょっと上に」出る。
・そのため、爆発が機体を包み込むように見えて、自然。
(by ChatGPT)


Updateにプレイヤー撃破時の条件も追加する
(GameScene.cpp)

void GameScene::Update(void)
{
	bool eExpFlg = expl->GetEnemyExplosionFlag();	//敵爆発中フラグ取得
	bool pExpFlg = expl->GetPlayerExplosionFlag();	//自機爆発中フラグ取得
	if(eExpFlg||pExpFlg) {
		//爆発処理中は他の更新処理を行わない
		expl->Update();
		return;
	}

StageExitConditionsCheck()関数内プレイヤーが撃破時の処理を、プレイヤーの爆発表示が終わるまで待つ様に変更(プレイヤーの存在フラグが偽の場合、爆発表示フラグが偽ならステージ終了条件を設定するという方式に変更する)
(GameScene.cpp)

eStageExitConditionsKind GameScene::StageExitConditionCheck(void)
{
	eStageExitConditionsKind exitCondition = ESTAGE_EXIT_NON;

	//敵の残機数を取得する
	int enemyNum = en->GetEnemyRestNum();

	if (enemyNum == 0) {
		//敵の残機数が0なので、プレイヤーがステージをクリアした
		exitCondition = ESTAGE_EXIT_CLEAR;
	}
	else if (pl->GetAlive() == false) {
		//プレイヤーがやられた
		if (expl->GetPlayerExplosionFlag() == false) {
			//爆発処理が終了している場合のみ
			exitCondition = ESTAGE_EXIT_ENEMY_SHOT;
		}
	}
	else if (en->CheckHitEdgeProc() == ENEMY_HIT_EDGE_DOWN) {
		//敵が最下段に到達した
		exitCondition = ESTAGE_EXIT_ENEMY_OCCUPATION;
	}
	return exitCondition;
}

スコアを実装していく。まずは変数の準備から(privateで)。
(GameScene.h)

#pragma once

#include"StDefine.h"

class SceneManager;
class Player;
class PlayerBullet;
class Enemy;
class EnemyBullet;
class Explosion;

class GameScene
{
public:
	static constexpr int STAGE_NUM_MAX = 5;	//最大ステージ数

	GameScene(SceneManager* scenem);
	~GameScene(void);

	bool SystemInit(void);		//ゲーム起動時の初期化処理
	void GameInit(void);		//ゲームシーンの初期化処理
	void SceneGameNextStageInit(void);//ステージクリア時の初期化処理
	void Update(void);			//ゲームシーンの更新処理
	void Draw(void);			//ゲームシーンの描画処理
	bool Release(void);			//ゲームシーンの解放処理

	void ExitConditionProc(void);

	eSceneKind getNextSceneID(void) { return nextScene_ID; }

private:
	SceneManager* sceneM;	//SceneManagerClassのインスタンスのポインタ
	Player* pl;				//PlayerClassのインスタンスのポインタ
	PlayerBullet* pBullet;	//PlayerBulletClassのインスタンスのポインタ
	Enemy* en;				//EnemyClassのインスタンスのポインタ
	EnemyBullet* eBullet;	//EnemyBulletのインスタンスのポインタ
	Explosion* expl;		//ExplosionClassのインスタンスのポインタ

	int nowStageNo;			//現在のステージ番号
	int nowScore;			//現在のスコア
	int highScore;			//ハイスコア

	int scoreTbl[ENEMY_KIND_MAX]; //敵キャラの種類ごとのスコアテーブル

	eStageExitConditionsKind StageExitConditionsCheck(void);
	
	bool CollisionCheckPlayerBullet(void);//衝突判定
	bool CollisionCheckEnemyBullet(void); //敵弾との衝突判定

	eSceneKind nextScene_ID;	//次に遷移するシーンのID番号

	int nowBKeyPress;
	int prevBKeyPress;

	// テスト用のキーの状態
#ifdef _DEBUG

	int nowWKeyPress;	//デバッグ用(W)
	int prevWKeyPress;
	int nowLKeyPress;	//デバッグ用(L)
	int prevLKeyPress;
	int nowOKeyPress;	//デバッグ用(O)
	int prevOKeyPress;

#endif //_DEBUG

};

スコアの初期化処理。
(GameScene.cpp)

void GameScene::GameInit(void)
{
	pl->GameInit();
	pBullet->GameInit();
	en->GameInit();
	eBullet->GameInit();
	expl->GameInit();

	nowStageNo = 0;
	nextScene_ID = SCENE_KIND_GAME;

	for(int ii = 0;ii<ENEMY_KIND_MAX;ii++){
		scoreTbl[ii] = 10 + (5 * ii);

	}
	nowscore = 0;
	highScore = 0;
	nowBKeyPress = prevBKeyPress = 0;

	// テスト用のキーの状態
#ifdef DEBUG

	nowWKeyPress = prevWKeyPress = 0;	//デバッグ用(W)
	nowLKeyPress = prevLKeyPress = 0;	//デバッグ用(L)
	nowOKeyPress = prevOKeyPress = 0;	//デバッグ用(O)

#endif // DEBUG

}

敵種別判別用のテーブル定義。
(Enemy.h)

#pragma once
#include "StDefine.h"

class Enemy
{
public:
	Enemy(void);
	~Enemy(void);

	bool SystemInit(void);
	void GameInit(void);
	void OccupationInit(void);
	void Update(void);
	void Draw(void);
	bool Release(void);

	eEnemyHitEdgeDir CheckHitEdgeProc(void);
	int GetEnemyRestNum(void);				//敵の残機数を取得

	bool GetAlive(int x, int y){ return eArray[y][x].flag; }
	void SetAliveOff(int x, int y) { eArray[y][x].flag = false; }
	POSITION GetPos(int x, int y) { return eArray[y][x].pos; }
	void SetPos(int x, int y, POSITION pos) { eArray[y][x].pos = pos; }
	eEnemyMoveDirection GetMoveDir(void) { return eMoveDirection; }
	eEnemyMoveDirection GetNextMoveDir(void) { return eNextMoveDirection; }
	void SetMoveDir(eEnemyMoveDirection dir) { eMoveDirection = dir; }
	void SetNextMoveDir(eEnemyMoveDirection dir) {eNextMoveDirection = dir;	}

	int GetKind(int x, int y) { return eArray[y][x].kind; }

	// 敵キャラ
	static constexpr int ENEMY_WID = 32;				// 敵の画像の横サイズ
	static constexpr int ENEMY_HIG = 23;				// 敵の画像の縦サイズ
	static constexpr int ENEMY_PATTERNS = 2;			//敵のアニメーション配列数
	static constexpr int ENEMY_DISP_X_DISTANCE = 8;	//敵キャラ同士の横の間隔
	static constexpr int ENEMY_DISP_Y_DISTANCE = 4;	//敵キャラ同士の縦の間隔

	// 敵キャラの画面表示関連
	static constexpr int ENEMY_DISP_XNUM = 8;				// 敵キャラの横の表示個数
	static constexpr int ENEMY_DISP_YNUM = 7;				// 敵キャラの縦の表示個数
	
	// 敵キャラの移動関連
	static constexpr int ENEMY_MOVE_X_SPEED = 4;			//敵の横方向の移動量
	static constexpr int ENEMY_MOVE_Y_SPEED = (ENEMY_HIG + ENEMY_DISP_Y_DISTANCE);//敵の縦方向移動量

	static constexpr int ENEMY_MOVE_CUT_INTERVAL = 2;	//短縮する移動間隔
	static constexpr int ENEMY_REST_PER_MINIMUM = 10;	//敵キャラ残機数の最小割合(%)
	static constexpr int ENEMY_REST_PER_MINI_2 = 20;	//敵キャラ残機数の最小割合(%)
	static constexpr int ENEMY_REST_PER_MINI_3 = 40;	//敵キャラ残機数の最小割合(%)
	static constexpr int ENEMY_REST_PER_MINI_4 = 60;	//敵キャラ残機数の最小割合(%)
	static constexpr int ENEMY_REST_PER_MINI_5 = 80;	//敵キャラ残機数の最小割合(%)


private:
	//敵キャラの表示関連
	static constexpr int ENEMY_DISP_ALL_NUM = ENEMY_DISP_XNUM * ENEMY_DISP_YNUM;

	static constexpr int ENEMY_MOVE_INTERVAL_COUNT = 32;	//敵移動のインターバル

	// 敵キャラ
	int imageArray[ENEMY_KIND_MAX][ENEMY_PATTERNS];		// 敵の画像ハンドル番号
	charData eArray[ENEMY_DISP_YNUM][ENEMY_DISP_XNUM];	// 敵のX座標表示位置と生存フラグと種類のテーブル
	bool flgArray[ENEMY_DISP_YNUM][ENEMY_DISP_XNUM];	// 敵の存在フラグテーブル

	eEnemyMoveDirection eMoveDirection;		//敵キャラの現在の移動方向
	eEnemyMoveDirection eNextMoveDirection;	//敵キャラの下移動後の移動方向
	int eMoveIntervalCounter;				//敵キャラ移動の間隔調整用カウンタ
	int eAnimCounter;						//敵キャラのアニメーションカウンタ
};

スコア加算とハイスコア更新処理。
スコア更新用の関数をヘッダーに定義
(GameScene.h)

#pragma once

#include"StDefine.h"

class SceneManager;
class Player;
class PlayerBullet;
class Enemy;
class EnemyBullet;
class Explosion;

class GameScene
{
public:
	static constexpr int STAGE_NUM_MAX = 5;	//最大ステージ数

	GameScene(SceneManager* scenem);
	~GameScene(void);

	bool SystemInit(void);		//ゲーム起動時の初期化処理
	void GameInit(void);		//ゲームシーンの初期化処理
	void SceneGameNextStageInit(void);//ステージクリア時の初期化処理
	void Update(void);			//ゲームシーンの更新処理
	void Draw(void);			//ゲームシーンの描画処理
	bool Release(void);			//ゲームシーンの解放処理

	void ExitConditionProc(void);

	eSceneKind getNextSceneID(void) { return nextScene_ID; }

private:
	SceneManager* sceneM;	//SceneManagerClassのインスタンスのポインタ
	Player* pl;				//PlayerClassのインスタンスのポインタ
	PlayerBullet* pBullet;	//PlayerBulletClassのインスタンスのポインタ
	Enemy* en;				//EnemyClassのインスタンスのポインタ
	EnemyBullet* eBullet;	//EnemyBulletのインスタンスのポインタ
	Explosion* expl;		//ExplosionClassのインスタンスのポインタ

	int nowStageNo;			//現在のステージ番号
	int nowScore;			//現在のスコア
	int highScore;			//ハイスコア
	
	int scoreTbl[ENEMY_KIND_MAX]; //敵キャラの種類ごとのスコアテーブル

	eStageExitConditionsKind StageExitConditionCheck(void);//ステージ終了条件の確認

	bool CollisionCheckPlayerBullet(void);	//衝突判定
	bool CollisionCheckEnemyBullet(void);	//敵弾との衝突判定
	void AddScore(int add, int kind);	//スコア加算処理

	eSceneKind nextScene_ID;	//次に遷移するシーンのID番号

	int nowBKeyPress;
	int prevBKeyPress;

	// テスト用のキーの状態
#ifdef _DEBUG

	int nowWKeyPress;	//デバッグ用(W)
	int prevWKeyPress;
	int nowLKeyPress;	//デバッグ用(L)
	int prevLKeyPress;
	int nowOKeyPress;	//デバッグ用(O)
	int prevOKeyPress;

#endif //_DEBUG

};


(GameScene.cpp)

bool GameScene::CollisionCheckPlayerBullet(void)
{
	if (pBullet->GetAlive() == true) {
		for (int yy = 0; yy < Enemy::ENEMY_DISP_YNUM; yy++) {
			for (int xx = 0; xx < Enemy::ENEMY_DISP_XNUM; xx++) {
				if (en->GetAlive(xx,yy) == false)continue;
				POSITION epos = en->GetPos(xx, yy);
				if (
					(epos.y + Enemy::ENEMY_HIG > pBullet->GetPos().y &&				//判定1:敵の下端のY座標 > 弾の上端のY座標
					(epos.y < pBullet->GetPos().y + Player::PLAYER_BULLET_HIG) &&	//判定2:敵の上端のY座標 < 弾の下端のY座標
					(epos.x < pBullet->GetPos().x + Player::PLAYER_BULLET_WID) &&	//判定3:敵の左端のX座標 < 弾の右端のX座標 
					(epos.x + Enemy::ENEMY_WID > pBullet->GetPos().x				//判定4: 敵の右端のX座標 > 弾の左端のX座標
					)
				{
					// プレイヤー弾は消滅
					pBullet->SetAliveOff();
					// 敵キャラも消滅
					en->SetAliveOff(xx,yy);

					// 爆発エフェクトの生成
					POSITION pos = en->GetPos(xx, yy);
					pos.x -= (Explosion::EXPLOSION_WID - Enemy::ENEMY_WID) / 2;
					expl->ExplosionStart(pos);

					// スコア加算
			AddScore(scoreTbl[en->GetKind(xx, yy)], en->GetKind(xx, yy));
					return true;
				}
			}

		}
	}
	return false;
}

Draw()内にスコア表示を追加。
(GameScene.cpp)

void GameScene::Draw(void)
{

	// プレイヤーの描画
	pl->Draw();

	// プレイヤー弾の描画
	pBullet->Draw();

	// 敵の描画
	en->Draw();

	// 敵弾の描画
	eBullet->Draw();

	// 爆発エフェクトの描画
	expl->Draw();

	//文字列表示
	DrawFormatString(10, 10, 0xffffff, "PlayerStock:%d", pl->GetPlayerStock());
	DrawFormatString(10, 28, 0xffffff, "BombStock:%d", pBullet->GetBombStock());
	DrawFormatString(10, 46, 0xffffff, "NowStage:%d", nowStageNo);
	DrawFormatString(600, 10, 0xffffff, "NowScore:%d", nowscore);
	DrawFormatString(600, 28, 0xffffff, "HighScore:%d", highScore);

	ScreenFlip();							// 裏の画面を表の画面に瞬間コピー

}

UFOを出現させるためのスペース確保。まずは敵のY座標を3行分下げる。
(Enemy.h)

#pragma once
#include "StDefine.h"

class Enemy
{
public:
	Enemy(void);
	~Enemy(void);

	bool SystemInit(void);
	void GameInit(void);
	void OccupationInit(void);
	void Update(void);
	void Draw(void);
	bool Release(void);

	eEnemyHitEdgeDir CheckHitEdgeProc(void);
	int GetEnemyRestNum(void);				//敵の残機数を取得

	bool GetAlive(int x, int y){ return eArray[y][x].flag; }
	void SetAliveOff(int x, int y) { eArray[y][x].flag = false; }
	POSITION GetPos(int x, int y) { return eArray[y][x].pos; }
	void SetPos(int x, int y, POSITION pos) { eArray[y][x].pos = pos; }
	eEnemyMoveDirection GetMoveDir(void) { return eMoveDirection; }
	eEnemyMoveDirection GetNextMoveDir(void) { return eNextMoveDirection; }
	void SetMoveDir(eEnemyMoveDirection dir) { eMoveDirection = dir; }
	void SetNextMoveDir(eEnemyMoveDirection dir) {eNextMoveDirection = dir;	}

	int GetKind(int x, int y) { return eArray[y][x].kind; }

	// 敵キャラ
	static constexpr int ENEMY_WID = 32;				// 敵の画像の横サイズ
	static constexpr int ENEMY_HIG = 23;				// 敵の画像の縦サイズ
	static constexpr int ENEMY_PATTERNS = 2;			//敵のアニメーション配列数
	static constexpr int ENEMY_DISP_X_DISTANCE = 8;	//敵キャラ同士の横の間隔
	static constexpr int ENEMY_DISP_Y_DISTANCE = 4;	//敵キャラ同士の縦の間隔
	static constexpr int ENEMY_DISP_START_Y = (ENEMY_HIG + ENEMY_DISP_Y_INTERVAL) * 3;//敵キャラの表示開始Y座標

	// 敵キャラの画面表示関連
	static constexpr int ENEMY_DISP_XNUM = 8;				// 敵キャラの横の表示個数
	static constexpr int ENEMY_DISP_YNUM = 7;				// 敵キャラの縦の表示個数
	
	// 敵キャラの移動関連
	static constexpr int ENEMY_MOVE_X_SPEED = 4;			//敵の横方向の移動量
	static constexpr int ENEMY_MOVE_Y_SPEED = (ENEMY_HIG + ENEMY_DISP_Y_DISTANCE);//敵の縦方向移動量

	static constexpr int ENEMY_MOVE_CUT_INTERVAL = 2;	//短縮する移動間隔
	static constexpr int ENEMY_REST_PER_MINIMUM = 10;	//敵キャラ残機数の最小割合(%)
	static constexpr int ENEMY_REST_PER_MINI_2 = 20;	//敵キャラ残機数の最小割合(%)
	static constexpr int ENEMY_REST_PER_MINI_3 = 40;	//敵キャラ残機数の最小割合(%)
	static constexpr int ENEMY_REST_PER_MINI_4 = 60;	//敵キャラ残機数の最小割合(%)
	static constexpr int ENEMY_REST_PER_MINI_5 = 80;	//敵キャラ残機数の最小割合(%)


private:
	//敵キャラの表示関連
	static constexpr int ENEMY_DISP_ALL_NUM = ENEMY_DISP_XNUM * ENEMY_DISP_YNUM;

	static constexpr int ENEMY_MOVE_INTERVAL_COUNT = 32;	//敵移動のインターバル

	// 敵キャラ
	int imageArray[ENEMY_KIND_MAX][ENEMY_PATTERNS];		// 敵の画像ハンドル番号
	charData eArray[ENEMY_DISP_YNUM][ENEMY_DISP_XNUM];	// 敵のX座標表示位置と生存フラグと種類のテーブル
	bool flgArray[ENEMY_DISP_YNUM][ENEMY_DISP_XNUM];	// 敵の存在フラグテーブル

	eEnemyMoveDirection eMoveDirection;		//敵キャラの現在の移動方向
	eEnemyMoveDirection eNextMoveDirection;	//敵キャラの下移動後の移動方向
	int eMoveIntervalCounter;				//敵キャラ移動の間隔調整用カウンタ
	int eAnimCounter;						//敵キャラのアニメーションカウンタ
};

敵の初期配置をずらす。
(Enemy.cpp)

#include<DxLib.h>
#include"Application.h"
#include"Player.h"
#include"Enemy.h"

//-----------------
// 変数の宣言
//-----------------

Enemy::Enemy()
	: imageArray{}               // 2次元配列を 0 クリア
	, eArray{}                   // 構造体配列を 0 クリア
	, flgArray{}                 // 0 クリア(全部 false)
	, eMoveDirection(ENEMY_DIR_RIGHT)
	, eNextMoveDirection(ENEMY_DIR_NON)
	, eMoveIntervalCounter(-1)
	, eAnimCounter(0)
{
}


Enemy::~Enemy()
{

}
bool Enemy::SystemInit(void)
{
	const char* fileName[] = {
		{"image/Enemy_1.png"},
		{"image/Enemy_2.png"},
		{"image/Enemy_3.png"},
	};
	
	//敵の画像の読込み
	for (int ii = 0; ii < ENEMY_KIND_MAX; ii++) {
		int err = LoadDivGraph(fileName[ii], ENEMY_PATTERNS, ENEMY_PATTERNS, 1, ENEMY_WID, ENEMY_HIG, imageArray[ii]);
		if (err == -1)return false;
	}

	return true;

}
void Enemy::GameInit(void)
{
	//-----------------
	// 変数の初期化
	//-----------------

	// 敵キャラの変数テーブルの初期化
	for (int yy = 0; yy < ENEMY_DISP_YNUM; yy++) {
		for (int xx = 0; xx < ENEMY_DISP_XNUM; xx++) {
			eArray[yy][xx].pos.x = (ENEMY_WID + ENEMY_DISP_X_DISTANCE) * xx;
			eArray[yy][xx].pos.y = ENEMY_DISP_START_Y + (ENEMY_HIG + ENEMY_DISP_Y_DISTANCE) * yy;
			eArray[yy][xx].flag = true;
			if (yy < 2)
			{
				eArray[yy][xx].kind = ENEMY_KIND_3;
			}
			if (yy < 4)
			{
				eArray[yy][xx].kind = ENEMY_KIND_2;
			}
			else
			{
				eArray[yy][xx].kind = ENEMY_KIND_1;
			}
		}
	}

	eMoveDirection = ENEMY_DIR_RIGHT;
	eNextMoveDirection = ENEMY_DIR_NON;

	eMoveIntervalCounter = -1;	//カウンタ初期化(00:15~)
	eAnimCounter = -1;			//アニメーションカウンタ初期化
}
void Enemy::OccupationInit(void)
{

}
void Enemy::Update(void)
{
	int rnum = GetEnemyRestNum();
	int per = (rnum * 100) / ENEMY_DISP_ALL_NUM;
	if (per > ENEMY_REST_PER_MINIMUM) {
		eMoveIntervalCounter++;
		if (eMoveIntervalCounter > 0) {
			int cutCount = 0;
			if (per < ENEMY_REST_PER_MINI_5) {
				if (per < ENEMY_REST_PER_MINI_2) {
					cutCount = 16;
				}
				else if (per < ENEMY_REST_PER_MINI_3) {
					cutCount = 14;
				}
				else if (per < ENEMY_REST_PER_MINI_4) {
					cutCount = 10;
				}
				else {
					cutCount = 8;
				}
			}
			if (eMoveIntervalCounter >= (ENEMY_MOVE_INTERVAL_COUNT-ENEMY_MOVE_CUT_INTERVAL*cutCount)) {
				eMoveIntervalCounter = -1;
			}
			return;
		}
	}

	eAnimCounter++;
	if (eAnimCounter >= ENEMY_PATTERNS)eAnimCounter = 0;

	for (int yy = 0; yy < ENEMY_DISP_YNUM; yy++) {
		for (int xx = 0; xx < ENEMY_DISP_XNUM; xx++) {
			if (eArray[yy][xx].flag) {
				switch (eMoveDirection) {
				case ENEMY_DIR_RIGHT:
					eArray[yy][xx].pos.x += ENEMY_MOVE_X_SPEED;
					break;
				case ENEMY_DIR_LEFT:
					eArray[yy][xx].pos.x -= ENEMY_MOVE_X_SPEED;
					break;
				case ENEMY_DIR_DOWN:
					eArray[yy][xx].pos.y += ENEMY_MOVE_Y_SPEED;
					break;

				}
			}
		}
	}
	// エリアの端にぶつかっていないかのチェック
	eEnemyHitEdgeDir hitdir = CheckHitEdgeProc();
	switch (hitdir) {
	case ENEMY_HIT_EDGE_NON:
		// 通常移動:次の方向に移る
		if (eNextMoveDirection != ENEMY_DIR_NON) {
			eMoveDirection = eNextMoveDirection;
			eNextMoveDirection = ENEMY_DIR_NON;
		}
		break;

	case ENEMY_HIT_EDGE_RIGHT:
		eMoveDirection = ENEMY_DIR_DOWN;
		eNextMoveDirection = ENEMY_DIR_LEFT;
		break;

	case ENEMY_HIT_EDGE_LEFT:
		eMoveDirection = ENEMY_DIR_DOWN;
		eNextMoveDirection = ENEMY_DIR_RIGHT;
		break;

	case ENEMY_HIT_EDGE_DOWN:
		// 敵が最下段に到達 → 負け処理へ
		break;
	}


}
void Enemy::Draw(void)
{
	// 敵の描画
	for (int yy = 0; yy < ENEMY_DISP_YNUM; yy++) {
		for (int xx = 0; xx < ENEMY_DISP_XNUM; xx++) {
			if (eArray[yy][xx].flag) {
				DrawGraph(eArray[yy][xx].pos.x, eArray[yy][xx].pos.y, imageArray[eArray[yy][xx].kind][eAnimCounter], true);
			}
		}
	}
}


bool Enemy::Release(void)
{
	bool err = true;
	for (int ii = 0; ii < ENEMY_KIND_MAX; ii++) {
		for (int jj = 0; jj < ENEMY_PATTERNS; jj++) {
			if (DeleteGraph(imageArray[ii][jj]) == -1)err = false;
		}
	}
	return err;
}

//エリアの端にぶつかっていないかのチェック処理
eEnemyHitEdgeDir Enemy::CheckHitEdgeProc(void)
{
	eEnemyHitEdgeDir hitdir = ENEMY_HIT_EDGE_NON;
	int restnum;//その列に生き残っている敵の数を格納する変数(ローカル)
	switch (eMoveDirection) {
		//右方向に移動中なので、右端に接触していないかをチェックする
	case ENEMY_DIR_RIGHT:
		for (int xx = ENEMY_DISP_XNUM - 1; xx >= 0; xx--) {
			restnum = 0;//敵が残っていなかった場合、チェックする列を移行するたびにチェックを初期化する
			for (int yy = 0; yy < ENEMY_DISP_YNUM; yy++) {
				if (eArray[yy][xx].flag == true) {
					restnum++;
					if (eArray[yy][xx].pos.x >= (Application::WINDOW_WID - ENEMY_WID)) {
						hitdir = ENEMY_HIT_EDGE_RIGHT;
						break;
					}
				}
			}
			if (hitdir != ENEMY_HIT_EDGE_NON || restnum > 0)break;	//端に接触しているか、端に接触していなくても残っている敵がいる場合にbreak
		}
		break;

		//左方向に移動中なので、左端に接触していないかをチェックする
	case ENEMY_DIR_LEFT:
		for (int xx = 0; xx < ENEMY_DISP_XNUM; xx++) {
			restnum = 0;//敵が残っていなかった場合、チェックする列を移行するたびにチェックを初期化する
			for (int yy = 0; yy < ENEMY_DISP_YNUM; yy++) {
				if (eArray[yy][xx].flag == true) {
					restnum++;
					if (eArray[yy][xx].pos.x <= 0) {
						hitdir = ENEMY_HIT_EDGE_LEFT;
						break;
					}
				}
			}
			if (hitdir != ENEMY_HIT_EDGE_NON || restnum > 0)break;	//端に接触しているか、端に接触していなくても残っている敵がいる場合にbreak

		}
		break;

		//下方向に移動中なので、下端に接触していないかをチェックする
	case ENEMY_DIR_DOWN:
		for (int yy = ENEMY_DISP_YNUM - 1; yy > 0; yy--) {
			restnum = 0;
			for (int xx = 0; xx < ENEMY_DISP_XNUM; xx++) {
				if (eArray[yy][xx].flag == true) {
					restnum++;
					if (eArray[yy][xx].pos.y >= (Application::WINDOW_HIG - ENEMY_HIG)) {
						hitdir = ENEMY_HIT_EDGE_DOWN;
						break;
					}
				}
			}
			if (hitdir != ENEMY_HIT_EDGE_NON || restnum > 0)break;	//端に接触しているか、端に接触していなくても残っている敵がいる場合にbreak
		}
		break;

	default:
		break;
	}
	return hitdir;
}

	int Enemy::GetEnemyRestNum(void)
	{
		int num = 0;

		for (int yy = 0; yy < ENEMY_DISP_YNUM; yy++) {
			for (int xx = 0; xx < ENEMY_DISP_XNUM; xx++) {
				if (eArray[yy][xx].flag == true)num++;
			}
		}
		return num;
	}

UfoProcClassを追加。メンバを記載。
(UfoProc.h)

#pragma once

#include"StDefine.h"

class UfoProc
{
public:
	static constexpr int UFO_WID = 48;		//UFOの画像の横サイズ
	static constexpr int UFO_HIG = 24;		//UFOの画像の縦サイズ
	
	static constexpr int UFO_DSP_SY = 28;	//UFOの表示Y座標
	static constexpr int UFO_SPEED = 4;		//UFOの移動速度

	static constexpr int UFO_EMERGE_INTERVAL = (60 * 30);	//UFO出現間隔(60FPS×30秒)
	static constexpr int UFO_RAND_TIME = (60 * 5);	//UFO出現のランダム時間(60FPS×5秒)
	static constexpr int UFO_EMARGE_CUT_TIME = (60 * 5);	//UFO出現間隔短縮時間(60FPS×5秒)
	
	UfoProc(void);
	~UfoProc(void);
	bool SystemInit(void);
	void GameInit(void);
	void Update(void);
	void Draw(void);
	bool Release(void);

private:
	int image;			//UFO画像ハンドル番号
	charData ufoInfo;		//UFO情報
	int emergeIntervalCounter;	//UFO出現間隔カウンタ
	eEnemyHitEdgeDir emergeDir;    //UFOの出現位置(左右)
			               //ENEMY_HIT_DIR_RIGHT:右から出現
				       //ENEMY_HIT_DIR_LEFT:左から出現
	int emergeRandTime;	       //UFO出現のランダム時間
};

関数を実装してゆく。
(UfoProc.cpp)

//-----------------------------------------------------------------------------
// インベーダーゲーム
// 氏 名:ゆき
//-----------------------------------------------------------------------------
// UfoProcClass
#include <DxLib.h>
#include"Application.h"
#include "StDefine.h"
#include "UfoProc.h"
#include "Enemy.h"

UfoProc::UfoProc(void)
{
	image = -1;
}

UfoProc::~UfoProc(void)
{
}

bool UfoProc::SystemInit(void)
{
	image = LoadGraph("image/UFO.png");
	if (image == -1)return false;
	return true;
}

void UfoProc::GameInit(void)
{
	ufoInfo.pos.x = 0;
	ufoInfo.pos.y = UFO_DSP_SY;
	ufoInfo.flag = false;
	emergeIntervalCounter = 0;
	emergeDir = ENEMY_HIT_EDGE_NON;
	emergeRandTime = 0;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

続きは次回。

コメント

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