2Dゲーム制作Ⅰ⑫(2025/06/30)

第二課題:インベーダーゲーム

【1】開始時点のソースコードの解説
まずは、前回と同じ様に main.cpp 一本である程度動く状態を作り、その後で、関数分割
ファイル分割の手順を踏む。ファイル分割して、敵を動かすあたりまでできたところで、クラス化に入っていく予定(7月中旬目途)。

※DxLibの設定
https://dxlib.xsrv.jp/use/dxuse_vscom2022.html

※ソースファイルのインポート

ソースファイルを右クリック ⇒ 追加 ⇒ 既存の項目

ファイルを選択して[追加]。


※ビルドについて

・ソリューションのビルド:変更点だけをビルド
・ソリューションのリビルド:プロジェクト内のすべてをビルド

インポートしたmain.cppファイル。ここにコードを書き加えていく。

//-----------------------------------------------------------------------------
// インベーダーゲーム
// 氏 名:
//-----------------------------------------------------------------------------
#include <DxLib.h>
#include <time.h>

//-----------------
// 定数定義
//-----------------
const int WINDOW_WID = 800;				// ウィンドウの横サイズ
const int WINDOW_HIG = 600;				// ウィンドウの縦サイズ

// プレイヤー
const int PLAYER_WID = 32;				// プレイヤー画像の横サイズ
const int PLAYER_HIG = 19;				// プレイヤー画像の縦サイズ
const int PLAYER_MOVE_SPEED = 6;		// プレイヤーの左右の移動速度

// プレイヤー弾
const int PLAYER_BULLET_WID = 6;		// プレイヤー弾の画像の横サイズ
const int PLAYER_BULLET_HIG = 30;		// プレイヤー弾の画像の縦サイズ
const int PLAYER_BULLET_MOVE = 12;		// プレイヤー弾の移動速度

// 敵キャラ
const int ENEMY_WID = 32;				// 敵の画像の横サイズ
const int ENEMY_HIG = 23;				// 敵の画像の縦サイズ

// 敵キャラの画面表示関連
const int ENEMY_DISP_XNUM = 8;				// 敵キャラの横の表示個数
const int ENEMY_DISP_YNUM = 7;				// 敵キャラの縦の表示個数
const int ENEMY_DISP_ALL_NUM = ENEMY_DISP_XNUM * ENEMY_DISP_YNUM;

//-----------------
// 変数の宣言
//-----------------
// プレイヤー
int playerImage;							// 自機の画像ハンドル番号
int playerPosX;								// 自機のX座標
int playerPosY;								// 自機のY座標
bool playerFlg;								// 自機の表示状態管理用フラグ(true:表示、false:非表示)

// プレイヤー弾
int playerBulletImage;						// プレイヤー弾の画像ハンドル番号
int playerBulletPosX;						// プレイヤー弾のX座標
int playerBulletPosY;						// プレイヤー弾のY座標
bool playerBulletFlg;						// プレイヤー弾の発射状態管理用フラグ(true:表示、false:非表示)

// 敵キャラ
int enemyImage;								// 敵の画像ハンドル番号
int enemyPosxArray[ENEMY_DISP_YNUM][ENEMY_DISP_XNUM];	// 敵のX座標表示位置テーブル
int enemyPosyArray[ENEMY_DISP_YNUM][ENEMY_DISP_XNUM];	// 敵のY座標表示位置テーブル
bool enemyFlgArray[ENEMY_DISP_YNUM][ENEMY_DISP_XNUM];	// 敵の存在フラグテーブル


//-----------------
// WinMain関数
//-----------------
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
	//-----------------
	// システム設定
	//-----------------
	SetWindowText("000000 苗字 名前");				// ウィンドウのタイトルの設定
	SetGraphMode(WINDOW_WID, WINDOW_HIG, 32);		// ウィンドウのサイズと色モードの設定
	ChangeWindowMode(true);							// ウィンドウの表示モード(true=ウィンドウモード/false=フルスクリーン)

	int err = DxLib_Init();					// DXライブラリの初期化
	if (err == -1)return -1;

	SRand((unsigned int)time(NULL));

	//---------------------------
	// グラフィックの登録
	//---------------------------
	// プレイヤー画像の読込み
	playerImage = LoadGraph("image/player.png");
	if (playerImage == -1)return -1;

	// プレイヤー弾の画像の読込み
	playerBulletImage = LoadGraph("image/playerBullet.png");
	if (playerBulletImage == -1)return -1;

	// 敵の画像の読込み
	enemyImage = LoadGraph("image/enemy_1.png");
	if (enemyImage == -1)return -1;

	//-----------------
	// 変数の初期化
	//-----------------
	// プレイヤー
	playerPosX = WINDOW_WID / 2 - PLAYER_WID / 2;		// ウィンドウの中央X座標
	playerPosY = WINDOW_HIG - PLAYER_HIG;
	playerFlg = true;

	// プレイヤー弾
	playerBulletPosX = playerBulletPosY = 0;
	playerBulletFlg = false;

	// 敵キャラ
	for (int yy = 0; yy < ENEMY_DISP_YNUM; yy++) {
		for (int xx = 0; xx < ENEMY_DISP_XNUM; xx++) {
			enemyPosxArray[yy][xx] = ENEMY_WID * xx;
			enemyPosyArray[yy][xx] = ENEMY_HIG * yy;
			enemyFlgArray[yy][xx] = true;
		}
	}

	//-----------------
	// ゲームループ
	//-----------------
	while (ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0) {
		//---------------------------
		// 更新処理
		//---------------------------
		// プレイヤーの移動

		// プレイヤー弾の処理

		// 当たり判定


		//---------------------------
		// 描画処理
		//---------------------------
		SetDrawScreen(DX_SCREEN_BACK);			// 描画する画面を裏の画面に設定する
		ClearDrawScreen();						// 描画する画面の内容を消去する

		// プレイヤーの描画

		// プレイヤー弾の描画

		// 敵の描画

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

	//----------------------
	// システムの終了処理
	//----------------------
	DxLib_End();				// DXライブラリの終了処理

	return 0;					// ゲームの正常終了
}

※二次元配列

int Array[x][y];
もちろんです、佳之さん!
int Array[x][y]; は、2次元配列(二重配列)を宣言する構文です。これで、整数型(int)のデータを格納する表のようなデータ構造を作れます。

📦 構文の意味
int Array[x][y];


- int:この配列が整数 (int) を格納することを示します。
- Array:配列の名前です。自由に名前をつけられます。
- [x][y]:それぞれのインデックス(添え字)
- x は行数(縦方向)
- y は列数(横方向)
たとえば int Array[3][4]; なら、3行4列の配列 → 合計 12個の int 値が格納できます。

🎯 使い方例
#include <stdio.h>

int main() {
    int Array[2][3] = {
        {1, 2, 3},
        {4, 5, 6}
    };

    printf("%d\n", Array[1][2]);  // 結果: 6(2行目3列目の値)
    return 0;
}

💡補足ポイント
- Cでは配列のインデックスは0から始まるため、Array[0][0] が最初の要素になります。
- Array[x][y] という宣言は、x 行、y 列の“固定サイズの表”を作る感覚です。
- 動的にサイズを変えたい場合は、ポインタと malloc() を使った動的2次元配列にする必要があります(少し高度ですが、興味があれば解説します!)

📊 例:int Array[3][4]; のイメージ

行\列0列1列2列3列
0行Array[0][0]Array[0][1]Array[0][2]Array[0][3]
1行Array[1][0]Array[1][1]Array[1][2]Array[1][3]
2行Array[2][0]Array[2][1]Array[2][2]Array[2][3]

この配列は「3行4列」の構造を持ち、全部で 3×4=12個int 型のデータを格納できます。

🔍 ポイントまとめ

  • が先、が後 → Array[行][列]
  • 配列のインデックスは 0から始まる
  • 表形式で管理できるので、ゲームの盤面やデータテーブルなどに便利

(by Copilot)

※代入について
a = b = 0 ;
というような記法も可能。
順序でいえば、b=0⇒a=bの順で処理される。

プレイヤーの描画処理を追加。

		// プレイヤーの描画
		if (playerFlg) {
			DrawGraph(playerPosX, playerPosY, playerImage, true);
		}

プレイヤーの移動処理を追加。(移動制限付き)

		// プレイヤーの移動
		if (playerFlg) {
			//右キーが押されたか
			if (CheckHitKey(KEY_INPUT_RIGHT) == 1) {
				playerPosX += PLAYER_MOVE_SPEED; //右に移動
			}
			//左キーが押されたか
			if (CheckHitKey(KEY_INPUT_LEFT) == 1) {
				playerPosX -= PLAYER_MOVE_SPEED; //左に移動
			}
			//左端のチェック
			if (playerPosX < 0)playerPosX = 0;
			//右端のチェック
			if (playerPosX > (WINDOW_WID - PLAYER_WID - 1))playerPosX = (WINDOW_WID - PLAYER_WID - 1);
		}

プレイヤー弾の描画処理を追加

		// プレイヤー弾の描画
		if (playerBulletFlg) {
			DrawGraph(playerBulletPosX, playerBulletPosY, playerBulletImage, true);
		}

プレイヤー弾の発射処理を追加

		// プレイヤー弾の処理
		if (playerBulletFlg == false) {
			//弾が未発射状態なので射撃可能
			if (CheckHitKey(KEY_INPUT_SPACE) == 1) {
				playerBulletPosX = (playerPosX + PLAYER_WID / 2) - (PLAYER_BULLET_WID / 2);
				playerBulletPosY = playerPosY - PLAYER_BULLET_HIG;
				playerBulletFlg = true;
			}
		}

弾の移動処理を追加

			//弾の移動処理
			playerBulletPosY -= PLAYER_BULLET_MOVE;
			if (playerBulletPosY < 0)playerBulletFlg = false;
		}

敵の描画処理を追加

		// 敵の描画
		for (int yy = 0; yy < ENEMY_DISP_YNUM; yy++) {
			for (int xx = 0; xx < ENEMY_DISP_XNUM;xx++) {
				if (enemyFlgArray[yy][xx]) {
					DrawGraphScreen(enemyPosxArray[yy][xx], enemyPosyArray[yy][xx], enemyImage, true);
				}
			}
		}

関数分離

Init(初期化)、Update(更新)、Draw(描画)に分けて記述する。
プロトタイプ宣言はWinMainの直前、関数本体の記述はWinMainの下に配置。

//プロトタイプ宣言
bool Init(void);
void Update(void);
void Draw(void);
	//---------------------------
	//初期化処理
	//---------------------------
	bool Init(void)
	{

		return 0;
	}

	//---------------------------
	//更新処理
	//---------------------------
	void Update(void)
	{

	}
	//---------------------------
	//描画処理
	//---------------------------
	void Draw(void)
	{

	}

関数分割後に、処理を関数に移した結果。
【今日のコード①】

//-----------------------------------------------------------------------------
// インベーダーゲーム
// 氏 名:
//-----------------------------------------------------------------------------
#include <DxLib.h>
#include <time.h>

//-----------------
// 定数定義
//-----------------
const int WINDOW_WID = 800;				// ウィンドウの横サイズ
const int WINDOW_HIG = 600;				// ウィンドウの縦サイズ

// プレイヤー
const int PLAYER_WID = 32;				// プレイヤー画像の横サイズ
const int PLAYER_HIG = 19;				// プレイヤー画像の縦サイズ
const int PLAYER_MOVE_SPEED = 6;		// プレイヤーの左右の移動速度

// プレイヤー弾
const int PLAYER_BULLET_WID = 6;		// プレイヤー弾の画像の横サイズ
const int PLAYER_BULLET_HIG = 30;		// プレイヤー弾の画像の縦サイズ
const int PLAYER_BULLET_MOVE = 12;		// プレイヤー弾の移動速度

// 敵キャラ
const int ENEMY_WID = 32;				// 敵の画像の横サイズ
const int ENEMY_HIG = 23;				// 敵の画像の縦サイズ

// 敵キャラの画面表示関連
const int ENEMY_DISP_XNUM = 8;				// 敵キャラの横の表示個数
const int ENEMY_DISP_YNUM = 7;				// 敵キャラの縦の表示個数
const int ENEMY_DISP_ALL_NUM = ENEMY_DISP_XNUM * ENEMY_DISP_YNUM;

//-----------------
// 変数の宣言
//-----------------
// プレイヤー
int playerImage;							// 自機の画像ハンドル番号
int playerPosX;								// 自機のX座標
int playerPosY;								// 自機のY座標
bool playerFlg;								// 自機の表示状態管理用フラグ(true:表示、false:非表示)

// プレイヤー弾
int playerBulletImage;						// プレイヤー弾の画像ハンドル番号
int playerBulletPosX;						// プレイヤー弾のX座標
int playerBulletPosY;						// プレイヤー弾のY座標
bool playerBulletFlg;						// プレイヤー弾の発射状態管理用フラグ(true:表示、false:非表示)

// 敵キャラ
int enemyImage;								// 敵の画像ハンドル番号
int enemyPosxArray[ENEMY_DISP_YNUM][ENEMY_DISP_XNUM];	// 敵のX座標表示位置テーブル
int enemyPosyArray[ENEMY_DISP_YNUM][ENEMY_DISP_XNUM];	// 敵のY座標表示位置テーブル
bool enemyFlgArray[ENEMY_DISP_YNUM][ENEMY_DISP_XNUM];	// 敵の存在フラグテーブル

//プロトタイプ宣言
bool Init(void);
void Update(void);
void Draw(void);

//-----------------
// WinMain関数
//-----------------
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
	if (Init() == false)return -1;

	//-----------------
	// ゲームループ
	//-----------------
	while (ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0) {
		//---------------------------
		// 更新処理
		//---------------------------
		Update();


		//---------------------------
		// 描画処理
		//---------------------------
		Draw();
	}

	//----------------------
	// システムの終了処理
	//----------------------
	DxLib_End();				// DXライブラリの終了処理

	return 0;					// ゲームの正常終了
}
//---------------------------
//初期化処理
//---------------------------
bool Init(void)
{
	//-----------------
	// システム設定
	//-----------------
	SetWindowText("2505889 桑野 佳之");				// ウィンドウのタイトルの設定
	SetGraphMode(WINDOW_WID, WINDOW_HIG, 32);		// ウィンドウのサイズと色モードの設定
	ChangeWindowMode(true);							// ウィンドウの表示モード(true=ウィンドウモード/false=フルスクリーン)

	int err = DxLib_Init();					// DXライブラリの初期化
	if (err == -1)return false;

	SRand((unsigned int)time(NULL));

	//---------------------------
	// グラフィックの登録
	//---------------------------
	// プレイヤー画像の読込み
	playerImage = LoadGraph("image/player.png");
	if (playerImage == -1)return false;

	// プレイヤー弾の画像の読込み
	playerBulletImage = LoadGraph("image/playerBullet.png");
	if (playerBulletImage == -1)return false;

	// 敵の画像の読込み
	enemyImage = LoadGraph("image/enemy_1.png");
	if (enemyImage == -1)return false;

	//-----------------
	// 変数の初期化
	//-----------------
	// プレイヤー
	playerPosX = WINDOW_WID / 2 - PLAYER_WID / 2;		// ウィンドウの中央X座標
	playerPosY = WINDOW_HIG - PLAYER_HIG;
	playerFlg = true;

	// プレイヤー弾
	playerBulletPosX = playerBulletPosY = 0;
	playerBulletFlg = false;

	// 敵キャラ
	for (int yy = 0; yy < ENEMY_DISP_YNUM; yy++) {
		for (int xx = 0; xx < ENEMY_DISP_XNUM; xx++) {
			enemyPosxArray[yy][xx] = ENEMY_WID * xx;
			enemyPosyArray[yy][xx] = ENEMY_HIG * yy;
			enemyFlgArray[yy][xx] = true;
		}
	}


	return true;
}

//---------------------------
//更新処理
//---------------------------
void Update(void)
{
	// プレイヤーの移動
	if (playerFlg) {
		//右キーが押されたか
		if (CheckHitKey(KEY_INPUT_RIGHT) == 1) {
			playerPosX += PLAYER_MOVE_SPEED; //右に移動
		}
		//左キーが押されたか
		if (CheckHitKey(KEY_INPUT_LEFT) == 1) {
			playerPosX -= PLAYER_MOVE_SPEED; //左に移動
		}
		//左端のチェック
		if (playerPosX < 0)playerPosX = 0;
		//右端のチェック
		if (playerPosX > (WINDOW_WID - PLAYER_WID - 1))playerPosX = (WINDOW_WID - PLAYER_WID - 1);
	}
	// プレイヤー弾の処理
	if (playerBulletFlg == false) {
		//弾が未発射状態なので射撃可能
		if (CheckHitKey(KEY_INPUT_SPACE) == 1) {
			playerBulletPosX = (playerPosX + PLAYER_WID / 2) - (PLAYER_BULLET_WID / 2);
			playerBulletPosY = playerPosY - PLAYER_BULLET_HIG;
			playerBulletFlg = true;
		}
	}
	else {
		//弾の移動処理
		playerBulletPosY -= PLAYER_BULLET_MOVE;
		if (playerBulletPosY < 0)playerBulletFlg = false;
	}
	// 当たり判定

}
//---------------------------
//描画処理
//---------------------------
void Draw(void)
{
	SetDrawScreen(DX_SCREEN_BACK);			// 描画する画面を裏の画面に設定する
	ClearDrawScreen();						// 描画する画面の内容を消去する

	// プレイヤーの描画
	if (playerFlg) {
		DrawGraph(playerPosX, playerPosY, playerImage, true);
	}
	// プレイヤー弾の描画
	if (playerBulletFlg) {
		DrawGraph(playerBulletPosX, playerBulletPosY, playerBulletImage, true);
	}

	// 敵の描画
	for (int yy = 0; yy < ENEMY_DISP_YNUM; yy++) {
		for (int xx = 0; xx < ENEMY_DISP_XNUM;xx++) {
			if (enemyFlgArray[yy][xx]) {
				DrawGraph(enemyPosxArray[yy][xx], enemyPosyArray[yy][xx], enemyImage, true);
			}
		}
	}


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


コメント

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