2Dゲーム制作㉚(2025/10/27)

VisualStudio – Project>クラスの追加
で.h、.cppのひな型を作ってくれるので、これも便利。

爆発エフェクトを処理するためにExplosionClassを作成。
クラス定義を書いていく。
(Explosion.h)

#pragma once

#include"StDefine.h"

class Explosion
{

public:

	void EnemyExplositionStart(POSITION pos);
	void GetEnemyExplosionFlag(void) { return enemyFlag; }
private:
	static const int EXPLOSION_WID = 36;        // 爆発画像の幅
	static const int EXPLOSION_HIG = 24;        // 爆発画像の高さ
	static const int ENEMY_EXPLOSION_TIME = 5;	// 敵の爆発画像を表示する時間

	Explosion(void);
	~Explosion(void);

	bool SystemInit(void);
	bool GameInit(void);
	bool Update(void);
	bool Draw(void);
	bool Release(void);
	void EnemyExplosionEnd(void) { enemyFlag = false; }

	int image;	// 爆発画像のハンドル番号を格納する変数

	int enemyCounter;	// 敵爆発表示時間カウンター
	bool enemyFlag;		// 敵爆発表示フラグ(true=表示中/false=非表示)
	POSITION enemyPos;	// 敵爆発表示位置

};

※クラススコープ
(クラス名)::(関数名)
この「(クラス名)+(::)」をクラススコープと呼び、関数がどのクラスに所属しているかを特定するためのもの。(復習)


#include<DxLib.h>
#include "Explosion.h"

Explosion::Explosion(void)
{
	image = -1;
}
Explosion::~Explosion(void)
{
}
bool Explosion::SystemInit(void)
{
	image = LoadGraph("image/Explosion.png");
	if (image == -1)return false;
	return true;
}
bool Explosion::GameInit(void)
{
	// 敵爆発関連の変数初期化
	enemyCounter = 0;
	enemyFlag = false;
	enemyPos.x = enemyPos.y = 0;//(実装をミスった場合に画面外に爆発が表示されたりすると分りづらい、という意味合いも含む)	
	return true;
}
	bool Explosion::Update(void)
{
	if (enemyFlag == true) {
		enemyCounter++;
		if (enemyCounter >= ENEMY_EXPLOSION_TIME) EnemyExplosionEnd();
	}
	return true;
	}

	bool Explosion::Draw(void)
	{
		if (enemyFlag == true) {
			DrawGraph(enemyPos.x, enemyPos.y, image, true);
		}
		return true;
	}


	bool Explosion::Release(void)
	{
		if (DeleteGraph(image) == -1)return false;
		return true;
	}

	void Explosion::EnemyExplositionStart(POSITION pos)
	{
		enemyPos = pos;
		enemyFlag = true;
		enemyCounter = 0;
	}
	

GameSceneClassからExplosionClassを呼び出せるようにする。
(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;				//現在のステージ番号

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

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

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

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

#endif // DEBUG

};

GameSceneにExplosionClassの処理を組み込む。
(GameScene.cpp)

#include <DxLib.h>
#include "GameScene.h"
#include "Player.h"
#include "PlayerBullet.h"
#include "Enemy.h"
#include "EnemyBullet.h"
#include "Application.h"
#include "SceneManager.h"
#include"Explosion.h"

//コンストラクタ
GameScene::GameScene(SceneManager* scenem)
{
	sceneM = scenem;
	pl = nullptr;
	pBullet = nullptr;
	en = nullptr;
	eBullet = nullptr;
	expl = nullptr;
}

//デストラクタ
GameScene::~GameScene(void)
{

}

bool GameScene::SystemInit(void)
{
	pl = new Player();
	if (pl == nullptr)return false;

	pBullet = new PlayerBullet(sceneM,pl);
	if (pBullet == nullptr)return false;

	en = new Enemy();
	if (en == nullptr)return false;

	eBullet = new EnemyBullet(en);
	if (eBullet == nullptr)return false;

	expl = new Explosion();
	if (expl == nullptr)return false;

	if (pl->SystemInit() == false)return false;
	if (pBullet->SystemInit() == false)return false;
	if (en->SystemInit() == false)return false;
	if (eBullet->SystemInit() == false)return false;
	if (expl->SystemInit() == false)return false;

	return true;
}

void GameScene::GameInit(void)
{
	pl->GameInit();
	pBullet->GameInit();
	en->GameInit();
	eBullet->GameInit();
        expl->GameInit();
	nowStageNo = 0;
	nextStage_ID = SCENE_KIND_GAME;

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

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

#endif // DEBUG

}

//プレイヤーが勝利した時の再初期化処理
void GameScene::SceneGameNextStageInit(void)
{
	//敵キャラ関連の初期化
	en->GameInit();
	//プレイヤー関連の初期化
	//プレイヤーY座標は常に最下段なので再設定は不要
	//プレイヤー勝利時に呼ばれるので存在フラグの再設定は不要
	pl->SetDefaultPos();
}

void GameScene::Update(void)
{
	bool eExpFlg = expl->GetEnemyExplosionFlag();
	if(eExpFlg == true) {
		//爆発処理中は他の更新処理を行わない
		expl->Update();
		return;
	}
	//プレイヤーの移動
	pl->Update();


	// プレイヤー弾の移動処理
	pBullet->UpdateMove();

	// プレイヤー弾の発射処理
	pBullet->UpdateShot();


	//敵の移動処理
	en->Update();

	//敵弾の移動処理
	eBullet->UpdateMove();

	//敵弾の発射処理
	eBullet->UpdateShot();


	// 当たり判定
	CollisionCheckPlayerBullet();
	CollisionCheckEnemyBullet();

	prevBKeyPress = nowBKeyPress;
	nowBKeyPress = CheckHitKey(KEY_INPUT_B);

	if (nowBKeyPress == 0 && prevBKeyPress == 1) {
		//敵を1段押し戻す
		pBullet->Bomb();
	}
	//--------------------------------------------
	// テスト用処理
	//--------------------------------------------
#ifdef _DEBUG
	prevWKeyPress = nowWKeyPress;
	nowWKeyPress = CheckHitKey(KEY_INPUT_W);
	prevWKeyPress = nowWKeyPress;
	nowLKeyPress = CheckHitKey(KEY_INPUT_L);
	prevLKeyPress = nowLKeyPress;
	nowKeyOPress = CheckHitKey(KEY_INPUT_O);
	
	if (nowWKeyPress == 0 && prevWKeyPress == 1) {
		//条件1:プレイヤーが勝った
		//敵キャラを無条件にすべてやられた状態にする
		for (int yy = 0; yy < Enemy::ENEMY_DISP_YNUM; yy++) {
			for (int xx = 0; xx < Enemy:: ENEMY_DISP_XNUM; xx++) {
				en->SetAliveOff(xx,yy);
			}
		}
	}
	else if (nowLKeyPress == 0 && prevLKeyPress == 1) {
		//条件2:敵弾にプレイヤーが撃たれた
		pl->SetAliveOff();
	}
	else if (nowOKeyPress == 0 && prevOKeyPress == 1) {
		//条件3:敵に最下段まで到達された
		//敵キャラをすべてのY座標を最下段に変更
		int chkpos = Application::WINDOW_HIG - Enemy::ENEMY_MOVE_Y_SPEED; //あと一歩で下端に到達する位置
		for (int yy = Enemy::ENEMY_DISP_YNUM - 1; yy >= 0; yy--) {
			for (int xx = 0; xx < Enemy::ENEMY_DISP_XNUM; xx++) {
				if (en->GetAlive(xx,yy) == true) {
					POSITION enPos = en->GetPos(xx.yy);
					enPos.y = chkpos - (Enemy::ENEMY_MOVE_Y_SPEED * (Enemy::ENEMY_DISP_YNUM - (yy + 1)));
				}
			}
		}
	}

	}
#endif

}

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);

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

}

bool GameScene::Release(void)
{
	pl->Release();
	delete pl;
	pl = nullptr;

	pBullet->Release();
	delete pBullet;
	pBullet = nullptr;

	en->Release();
	delete en;
	en = nullptr;

	eBullet->Release();
	delete eBullet;
	eBullet = nullptr;

	expl->Release();
	delete expl;
	expl = nullptr;

	return true;
}
//ステージ終了処理
void GameScene::ExitConditionProc(void)
{
	//ステージが終了したか
	eStageExitConditionsKind exit = StageExitConditionCheck();
	if (exit != ESTAGE_EXIT_NON) {
		switch (exit) {
		case ESTAGE_EXIT_CLEAR:
			//条件1:プレイヤー勝利
			//ステージ番号を1加算
			nowStageNo++;
			//ステージ番号が最大ステージ数を超えたらゲーム終了
			if (nowStageNo > STAGE_NUM_MAX)
			{
				nextScene_ID = SCENE_KIND_GAMEOVER;
			}
			else {
				//次のステージに進む際に敵の位置やフラグを再初期化
				SceneGameNextStageInit();
			}
			break;

		case ESTAGE_EXIT_ENEMY_SHOT:
			//条件2:プレイヤーが敵弾にやられた
			pl->playerStockDec();
			if (pl->GetPlayerStock() < 0) {
				//保有機数がなくなったらゲームオーバー
				nextScene_ID = SCENE_KIND_GAMEOVER;
			}
			else {
				//保有機数が残っていた場合に続行
				//プレイヤーのみ初期化
				pl->SetDefaultPos();
				pl->SetAliveOn();
			}

			break;
		case ESTAGE_EXIT_ENEMY_OCCUPATION:
			//条件3:敵が最下部に到達したらゲームオーバー
			SceneGameStageInit();//配置初期化
			sceneKind = SCENE_KIND_GAMEOVER;
			break;

		}
	}


}

//状況を検知して返す
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) {
		//プレイヤーがやられた
		exitCondition = ESTAGE_EXIT_ENEMY_SHOT;
	}
	else if (en->CheckHitEdgeProc() == ENEMY_HIT_EDGE_DOWN) {
		//敵が最下段に到達した
		exitCondition = ESTAGE_EXIT_ENEMY_OCCUPATION;
	}
	return exitCondition;
}

/*------------------------------------------------------------
*Player弾と敵との当たり判定
*Input:
*  無し
*Output:
*  true = 命中 / false = はずれ
*/------------------------------------------------------------
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);

					return true;
				}
			}

		}
	}
	return false;
}

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();
						return true;
					}
				}
			}

		}
	}
	return false;


}


プレイヤーの爆発も実装していく。
まずはクラス定義に追加。
(Explosion.h)

// Explosion.h(修正版)
#pragma once
#include "StDefine.h"

class Explosion {
public:
    // 定数(全インスタンス共通)
    static constexpr int EXPLOSION_WID = 36;
    static constexpr int EXPLOSION_HIG = 24;
    static constexpr int ENEMY_EXPLOSION_TIME = 5;
	static constexpr int PLAYER_EXPLOSION_TIME = 60;

    Explosion(void);
    ~Explosion(void);

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

    void EnemyExplosionStart(POSITION pos);
    void PlayerExplosionStart(POSITION pos);
    bool GetEnemyExplosionFlag(void) const { return enemyFlag; }
    bool GetPlayerExplosionFlag(void) const { return playerFlag; }

private:
    int image;          // 爆発画像ハンドル
    int enemyCounter;   // 表示時間カウンタ
    bool enemyFlag;     // 表示中フラグ
    POSITION enemyPos;  // 表示位置

	int playerCounter; // プレイヤー爆発用カウンタ  
	bool playerFlag;   // プレイヤー爆発表示中フラグ 
	POSITION playerPos; // プレイヤー爆発表示位置

    void EnemyExplosionEnd(void) { enemyFlag = false; }
    void PlayerExplosionEnd(void) { playerFlag = false; }

};

爆発処理を実装。
(Explosion.cpp)


#include<DxLib.h>
#include "Explosion.h"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool Explosion::GameInit(void)
{
	// 敵爆発関連の変数初期化
	enemyCounter = playerCounter = 0;
	enemyFlag = playerFlag = false;
	enemyPos.x = enemyPos.y = 0;	//(実装をミスった場合に画面外に爆発が表示されたりすると分りづらい、という意味合いも含む)	
	playerPos.x = playerPos.y = 0;
	return true;
}

void Explosion::PlayerExplosionStart(POSITION pos)
{
	playerPos = pos;
	playerFlag = true;
	playerCounter = 0;
}

コメント

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