2Dゲーム制作Ⅰ④(2025/05/12)

今週の目標
当たり判定(コリジョン)
・自機の発射する弾と敵機の当たり判定

・自機と敵機の当たり判定
・敵機の発射する弾と自機の当たり判定

データの使い方
int型データの使用用途はキャラの座標、残機数、スコア、ステージ番号等。

キャラの表示/非表示の区別(フラグ)はbool型を使う。

bool型はFalseは表示しない、Trueは表示する、という意味。
※フラグはbool型にすること

画面上を動くキャラを1体出すのに必要なパラメーターは次のようになる。
bool flag  表示/非表示
int handle 画像表示用ハンドルID
posX posY 表示する位置(画像の左上が基準)

自機、自機の弾、敵機、敵機の弾にもこれと同様のパラメーターを用意する。

ハンドル

handleは画像ファイルをメモリにロードする
int LoadGraph(“相対ファイルパス”);でキャラの画像を読み込んだ時の読み込んだ画像のIDのこと。
IDは読み込んだ場合に生成され、重複することはない。(※システム上で一意)。

読み込んだ画像を表示するDrawGraph(posX,posY,handle,TRUE)で画面上に表示する。
表示位置は開いたウインドウ位置(posX,posY)の左上が起点となる。

状態更新(ロジック)
入力処理
背景スクロール量の更新
自機の移動
自機の弾発射
自機の弾移動
敵機の移動
敵機の弾発射
敵機の弾移動
当たり判定(自機vs敵機、自機弾vs敵、敵弾vs自機)
スコア加算や残機現象処理

描画処理
背景の描画(スクロールに応じて)
敵機の描画
敵弾の描画
自機弾の描画
自機の描画
スコアや残機などのUI表示
※処理した順番に積み重なっていく…後に描画したものが上に表示される


#define…定数マクロ(定義した文字列を指定した数値に[ビルド時に]置き換える)

【今回のコード①】

#include<stdlib.h>
#include<time.h>
#include<DxLib.h>

#define SCREEN_W 640
#define SCREEN_H 960

#define CENTER_X (SCREEN_W / 2)
#define CENTER_Y (SCREEN_H / 2)

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
ChangeWindowMode(TRUE); // ウィンドウモード
SetGraphMode(SCREEN_W, SCREEN_H, 32);
DxLib_Init(); // DXライブラリ初期化
SetDrawScreen(DX_SCREEN_BACK); // 裏画面に描画
int handleBg = LoadGraph("bg.png");
int handle = LoadGraph("chara/blackpiyo-s.png");
int x = CENTER_X;
int y = CENTER_Y;
int scrollY = 0;
int shotX = 0, shotY = 0, shotFlag = 0;
int shotX2 = 0, shotY2 = 0, shotFlag2 = 0;
int shotX3 = 0, shotY3 = 0, shotFlag3 = 0;// shotFlag…0:表示しない 1:表示
int shotTimer = 0;
int enemyFlag = 1, enemyX = 0 , enemyY = 100, enemyTimer = 0,enemyVX = 0, enemyVY = 0; //enemy画像の幅の半分をずらして、真ん中付近に表示
srand((unsigned)time(NULL) * 123);
int handleShot = LoadGraph("chara/egg.png");
int handleEnemy = LoadGraph("chara/mike.png");
while (ProcessMessage() == 0) {
ClearDrawScreen();
 if (CheckHitKey(KEY_INPUT_RIGHT))
    {
        x += 2;
    }
    if (CheckHitKey(KEY_INPUT_LEFT))
    {
        x -= 2;
    }
    if (CheckHitKey(KEY_INPUT_DOWN))
    {
        y += 2;
    }
    if (CheckHitKey(KEY_INPUT_UP))
    {
        y -= 2;
    }
    if (CheckHitKey(KEY_INPUT_SPACE) && (shotTimer == 0))
    {
        if (shotFlag == 0)
        {
            shotX = x + 6;
            shotY = y;
            shotFlag = 1;
            shotTimer = 20;
        }
        else if (shotFlag2 == 0)
        {
            shotX2 = x + 6;
            shotY2 = y;
            shotFlag2 = 1;
            shotTimer = 20;
        }
        else if (shotFlag3 == 0)
        {
            shotX3 = x + 6;
            shotY3 = y;
            shotFlag3 = 1;
            shotTimer = 20;
        }
    }
    if (shotTimer > 0)
    {
        shotTimer--;
    }
    int dx = 0;
    if (shotFlag == 1 && enemyFlag == 1)
    {
        dx = (shotX - enemyX) * (shotX - enemyX) + (shotY - enemyY) * (shotY - enemyY);
        if (dx < 300 * 300)
        {
            enemyFlag = 0;
            shotFlag = 0;
            enemyTimer = (rand() % 100);
            enemyX = (rand() % 360);
        }
    }
    if (shotFlag2 == 1 && enemyFlag == 1)
    {
        dx = (shotX2 - enemyX) * (shotX2 - enemyX) + (shotY2 - enemyY) * (shotY2 - enemyY);
        if (dx < 300 * 300)
        {
            enemyFlag = 0;
            shotFlag2 = 0;
            enemyTimer = (rand() % 100);
            enemyX = (rand() % 360);
        }
    }
    if (shotFlag3 == 1 && enemyFlag == 1)
    {
        dx = (shotX3 - enemyX) * (shotX3 - enemyX) + (shotY3 - enemyY) * (shotY3 - enemyY);
        if (dx < 300 * 300)
        {
            enemyFlag = 0;
            shotFlag3 = 0;
            enemyTimer = (rand() % 100);
            enemyX = (rand() % 360);
        }
    }
    scrollY += 8;
    if (scrollY > SCREEN_H)
    {
        scrollY = 0;
    }
    DrawGraph(0, scrollY, handleBg, TRUE);
    DrawGraph(0, scrollY - SCREEN_H, handleBg, TRUE);
    DrawGraph(x, y, handle, TRUE);
    if (shotFlag == 1)
    {
        shotY -= 4;
        if (shotY < 0)
        {
            shotFlag = 0;
        }
        DrawGraph(shotX, shotY, handleShot, TRUE);
    }
    if (shotFlag2 == 1)
    {
        shotY2 -= 4;
        if (shotY2 < 0)
        {
            shotFlag2 = 0;
        }
        DrawGraph(shotX2, shotY2, handleShot, TRUE);
    }

    if (shotFlag3 == 1)
    {
        shotY3 -= 4;
        if (shotY3 < 0)
        {
            shotFlag3 = 0;
        }
        DrawGraph(shotX3, shotY3, handleShot, TRUE);
    }

    if (enemyFlag == 1) {
        enemyX += enemyVX; // X方向の移動
        enemyY += enemyVY; // Y方向の移動

        // 範囲外判定:敵が画面外に出たらフラグをオフにし再出現を準備
        if (enemyX < 0 || enemyX > SCREEN_W) {
            enemyVX = -enemyVX; // X方向の反転
        }
        if (enemyY < 0 || enemyY > SCREEN_H) {
            enemyVY = -enemyVY; // Y方向の反転
        }
        DrawGraph(enemyX, enemyY, handleEnemy, TRUE);
    }
    else {
        // 敵の再出現処理
        if (enemyTimer-- < 0) {
            enemyFlag = 1;
            enemyX = rand() % SCREEN_W;
            enemyY = -100;
            enemyVX = rand() % 5 - 2; // -2~2のランダム速度
            enemyVY = rand() % 5 - 2; // -2~2のランダム速度
            enemyTimer = 50;
        }
    }


    ScreenFlip();
}
DxLib_End();
}

#define で直指定を置き換えただけ。中身はない。

ウインドウタイトル設定
・SetMainWindowText(“タイトル文字列”)
※ウインドウのタイトルバーに表示される文字列を設定するDxLibの関数

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
ChangeWindowMode(TRUE); // ウィンドウモード
SetGraphMode(SCREEN_W, SCREEN_H, 32);

DxLib_Init(); // DXライブラリ初期化 SetMainWindowText(“BlackPiyo VS Mike”);

※プロトタイプ宣言について
関数を処理の後ろに書く場合に、関数の形式だけ先に指定しておくこと。
詳細は↓
https://9cguide.appspot.com/11-01.html

※ポインタ
変数の「先頭アドレス」を指定するもの。&を変数の頭につける。
(今回は&widthなど)

上記を踏まえて、以下のコードをWinMainの下に追加。

void DrawGraphCenter(int playerX, int playerY, int handle, bool flag)
{
 int width, height;if (flag)
 {
    GetGraphSize(handle, &width, &height);
    DrawGraph(playerX - (width / 2), playerY -( height / 2), handle, TRUE);
 }
}

この DrawGraphCenter 関数の目的は、画像の中心を指定した座標 (x, y) に合わせて描画する ことです。通常 DrawGraph() を使うと、画像の左上の座標 (x, y) が指定されますが、それだとキャラクターなどを中央に配置しづらいので、画像の中心を基準に描画するように工夫しているんですね。

関数の詳細説明

  1. 引数
    • playerX, playerY:画像を表示したい座標
    • handle:画像のハンドル(LoadGraph() で取得したもの)
    • flag:描画を行うかどうかのフラグ(true のときのみ描画)
  2. 処理の流れ
    • GetGraphSize(handle, &width, &height);
      画像の 横幅 (width)高さ (height) を取得します。
    • DrawGraph(x - (width / 2), y - (height / 2), handle, TRUE);
      画像の中心を (x, y) に持ってくるために、横幅の半分 (width / 2)高さの半分 (height / 2) を引いた座標に描画。
  3. 処理のポイント
  • flagtrue の場合のみ描画を実行するので、条件によって描画を制御できる。
  • GetGraphSize() を使うことで、画像のサイズが変更されても正しく中央に配置される。

描画のイメージ

例えば、画像のサイズが 100×100 の場合:

DrawGraphCenter(200, 300, handle, true);

この関数を呼び出すと、画像の中心が (200, 300) に配置されます。DrawGraph() だけだと (200, 300) に左上が配置されてしまうので、中心に合わせるにはこのような調整が必要ですね!

この関数を活用すると、キャラクターや背景を きれいに中央揃え で描画できるので便利です!
(by Copilot)

【今日のコード②】

#include<stdlib.h>
#include<time.h>
#include<DxLib.h>

#define SCREEN_W 480
#define SCREEN_H 880

#define CENTER_X (SCREEN_W / 2)
#define CENTER_Y (SCREEN_H / 2)

bool playerFlag = true; //自機の表示フラグ
int playerX = CENTER_X;
int playerY = CENTER_Y;
int scrollY = 0;
int shotX = 0, shotY = 0, shotFlag = 0;
int shotX2 = 0, shotY2 = 0, shotFlag2 = 0;
int shotX3 = 0, shotY3 = 0, shotFlag3 = 0;// shotFlag…0:表示しない 1:表示
int shotTimer = 0;
int enemyFlag = 1, enemyX = 0, enemyY = 100, enemyTimer = 0, enemyVX = 0, enemyVY = 0; //enemy画像の幅の半分をずらして、真ん中付近に表示


void DrawGraphCenter(int x, int y, int handle, bool flag);

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
	ChangeWindowMode(TRUE); // ウィンドウモード
	SetGraphMode(SCREEN_W, SCREEN_H, 32);

	DxLib_Init(); // DXライブラリ初期化
	SetMainWindowText("BlackPiyo VS Mike");
	int handleShot = LoadGraph("chara/egg.png");
	int handleEnemy = LoadGraph("chara/mike.png");
	int handleBg = LoadGraph("bg.png");
	int handle = LoadGraph("chara/blackpiyo-s.png");
	srand((unsigned)time(NULL) * 123);

	while (ProcessMessage() == 0) {
		ClearDrawScreen();

		if (CheckHitKey(KEY_INPUT_RIGHT))
		{
			playerX += 2;
		}
		if (CheckHitKey(KEY_INPUT_LEFT))
		{
			playerX -= 2;
		}
		if (CheckHitKey(KEY_INPUT_DOWN))
		{
			playerY += 2;
		}
		if (CheckHitKey(KEY_INPUT_UP))
		{
			playerY -= 2;
		}
		if (CheckHitKey(KEY_INPUT_SPACE) && (shotTimer == 0))
		{
			if (shotFlag == 0)
			{
				shotX = playerX + 6;
				shotY = playerY;
				shotFlag = 1;
				shotTimer = 20;
			}
			else if (shotFlag2 == 0)
			{
				shotX2 = playerX;
				shotY2 = playerY;
				shotFlag2 = 1;
				shotTimer = 20;
			}
			else if (shotFlag3 == 0)
			{
				shotX3 = playerX;
				shotY3 = playerY;
				shotFlag3 = 1;
				shotTimer = 20;
			}
		}
		if (shotTimer > 0)
		{
			shotTimer--;
		}
		int dx = 0;
		if (shotFlag == 1 && enemyFlag == 1)
		{
			dx = (shotX - enemyX) * (shotX - enemyX) + (shotY - enemyY) * (shotY - enemyY);
			if (dx < 300 * 300)
			{
				
				enemyFlag = 0;
				shotFlag = 0;
				enemyTimer = (rand() % 100);
				enemyX = (rand() % 360);
			}
		}
		if (shotFlag2 == 1 && enemyFlag == 1)
		{
			dx = (shotX2 - enemyX) * (shotX2 - enemyX) + (shotY2 - enemyY) * (shotY2 - enemyY);
			if (dx < 300 * 300)
			{
				enemyFlag = 0;
				shotFlag2 = 0;
				enemyTimer = (rand() % 100);
				enemyX = (rand() % 360);
			}
		}
		if (shotFlag3 == 1 && enemyFlag == 1)
		{
			dx = (shotX3 - enemyX) * (shotX3 - enemyX) + (shotY3 - enemyY) * (shotY3 - enemyY);
			if (dx < 300 * 300)
			{
				enemyFlag = 0;
				shotFlag3 = 0;
				enemyTimer = (rand() % 100);
				enemyX = (rand() % 360);
			}
		}
		scrollY += 8;
		if (scrollY > SCREEN_H)
		{
			scrollY = 0;
		}
		SetDrawScreen(DX_SCREEN_BACK); // 裏画面に描画
		DrawGraph(0, scrollY, handleBg, TRUE);
		DrawGraph(0, scrollY - SCREEN_H, handleBg, TRUE);
		DrawGraphCenter(playerX, playerY, handle, playerFlag);
		if (shotFlag == 1)
		{
			shotY -= 4;
			if (shotY < 0)
			{
				shotFlag = 0;
			}
			DrawGraph(shotX, shotY, handleShot, TRUE);
		}
		if (shotFlag2 == 1)
		{
			shotY2 -= 4;
			if (shotY2 < 0)
			{
				shotFlag2 = 0;
			}
			DrawGraph(shotX2, shotY2, handleShot, TRUE);
		}

		if (shotFlag3 == 1)
		{
			shotY3 -= 4;
			if (shotY3 < 0)
			{
				shotFlag3 = 0;
			}
			DrawGraph(shotX3, shotY3, handleShot, TRUE);
		}

		if (enemyFlag == 1) {
			enemyX += enemyVX; // X方向の移動
			enemyY += enemyVY; // Y方向の移動

			// 範囲外判定:敵が画面外に出たらフラグをオフにし再出現を準備
			if (enemyX < 0 || enemyX > SCREEN_W) {
				enemyVX = -enemyVX; // X方向の反転
			}
			if (enemyY < 0 || enemyY > SCREEN_H) {
				enemyVY = -enemyVY; // Y方向の反転
			}
			DrawGraph(enemyX, enemyY, handleEnemy, TRUE);
		}
		else {
			// 敵の再出現処理
			if (enemyTimer-- < 0) {
				enemyFlag = 1;
				enemyX = rand() % SCREEN_W;
				enemyY = -100;
				enemyVX = rand() % 5 - 2; // -2~2のランダム速度
				enemyVY = rand() % 5 - 2; // -2~2のランダム速度
				enemyTimer = 50;
			}
		}


		ScreenFlip();
	}
	DxLib_End();
}
//画像の中心位置基準で表示
//input x, y 表示位置座標
//handle 画像ID
//flag 表示/非表示
void DrawGraphCenter(int playerX, int playerY, int handle, bool flag)
{
	int width, height;

	if (flag)
	{
		GetGraphSize(handle, &width, &height);
		DrawGraph(playerX - (width / 2), playerY -( height / 2), handle, TRUE);
	}
}

それで、変数、定数、関数の命名について。
一般的なコーディング規則として、多くのプログラマーが以下のような命名ルールを採用しています:

  • 変数: 先頭を小文字で始める (playerX, enemyCount)
  • 定数: すべて大文字 (SCREEN_WIDTH, MAX_SPEED)
  • 関数: 先頭を大文字 (GetPlayerPosition(), DrawEnemy())

このルールは特に C言語やC++ などでよく使われる慣習ですが、言語やチームによって異なる場合もあります。

例えば、C++ では 定数を constexprconst で定義 することが多く、その場合は大文字にこだわらず、k を先頭につけて kMaxSpeed のようにするスタイルもあります。(by Copilot)

プレイヤーの移動制限を追加

//プレーヤーの移動制限
	if (playerX > SCREEN_W - PLAYER_W / 2)playerX = SCREEN_W - PLAYER_W / 2;
	if (playerX < PLAYER_W / 2)playerX = PLAYER_W/ 2;
	if (playerY > SCREEN_H - PLAYER_H / 2)playerY = SCREEN_H - PLAYER_H / 2;
	if (playerY < PLAYER_H / 2)playerY = PLAYER_H / 2;

この部分のコードは、プレイヤーが画面外へ移動しないように制限をかける処理 です。
具体的に何をしているのか、詳しく説明していきます!

コードの目的

プレイヤーの x(横方向) と y(縦方向) の座標を 画面の範囲内に収めるための処理 です。
キャラクターが 画面端を超えてしまうと、表示されなくなったりゲームの挙動がおかしくなる ため、それを防いでいます。

処理の流れ

コードを分解して説明すると、以下のようになります:

1. プレイヤーの x 座標の範囲制限

if (playerX > SCREEN_W – PLAYER_W / 2) playerX = SCREEN_W – PLAYER_W / 2; if (playerX < PLAYER_W / 2) playerX = PLAYER_W / 2; 

この処理では、

  • playerX > SCREEN_W - PLAYER_W / 2プレイヤーが画面右端を超えたら、右端に固定
  • playerX < PLAYER_W / 2プレイヤーが画面左端を超えたら、左端に固定

PLAYER_W / 2プレイヤーの画像の幅の半分 で、プレイヤーの中心が基準になっているため、キャラクターの半分が画面外に出ないように 制限しています。

2. プレイヤーの y 座標の範囲制限

if (playerY > SCREEN_H – PLAYER_H / 2) playerY = SCREEN_H – PLAYER_H / 2; if (playerY < PLAYER_H / 2) playerY = PLAYER_H / 2; 

こちらも x の制限と同じく、

  • playerY > SCREEN_H - PLAYER_H / 2プレイヤーが画面の下端を超えたら、下端に固定
  • playerY < PLAYER_H / 2プレイヤーが画面の上端を超えたら、上端に固定

PLAYER_H / 2プレイヤー画像の高さの半分 で、キャラクターの中心が基準。
これにより、キャラが 完全に画面外へ消えるのを防ぎます

この処理がない場合の問題

もしこの制限がなかったら、以下の問題が発生します:

  1. プレイヤーが 画面外へ移動できてしまう → 消えてしまい、見えなくなる
  2. 当たり判定の処理などが 画面外の座標で計算され、挙動がおかしくなる
  3. プレイヤーが戻って来られなくなる場合がある

そのため、この 範囲制限の処理は必須 なのです!(by Copilot)

上記を踏まえて
【今日のコード③】

#include<stdlib.h>
#include<time.h>
#include<DxLib.h>

#define SCREEN_W 480
#define SCREEN_H 880

#define CENTER_X (SCREEN_W / 2)
#define CENTER_Y (SCREEN_H / 2)

#define PLAYER_W 128 //プレイヤーの横幅
#define PLAYER_H 141 //プレイヤーの高さ

bool playerFlag = true; //自機の表示フラグ
int playerX = CENTER_X;
int playerY = CENTER_Y;
int scrollY = 0;
int shotX = 0, shotY = 0, shotFlag = 0;
int shotX2 = 0, shotY2 = 0, shotFlag2 = 0;
int shotX3 = 0, shotY3 = 0, shotFlag3 = 0;// shotFlag…0:表示しない 1:表示
int shotTimer = 0;
int enemyFlag = 1, enemyX = 0, enemyY = 100, enemyTimer = 0, enemyVX = 0, enemyVY = 0; //enemy画像の幅の半分をずらして、真ん中付近に表示


void DrawGraphCenter(int x, int y, int handle, bool flag);

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
	ChangeWindowMode(TRUE); // ウィンドウモード
	SetGraphMode(SCREEN_W, SCREEN_H, 32);

	DxLib_Init(); // DXライブラリ初期化
	SetMainWindowText("BlackPiyo VS Mike");
	int handleShot = LoadGraph("chara/egg.png");
	int handleEnemy = LoadGraph("chara/mike.png");
	int handleBg = LoadGraph("bg.png");
	int handle = LoadGraph("chara/blackpiyo-s.png");
	srand((unsigned)time(NULL) * 123);

	while (ProcessMessage() == 0) {
		SetDrawScreen(DX_SCREEN_BACK); // 裏画面に描画
		ClearDrawScreen();

		if (CheckHitKey(KEY_INPUT_RIGHT))
		{
			playerX += 2;
		}
		if (CheckHitKey(KEY_INPUT_LEFT))
		{
			playerX -= 2;
		}
		if (CheckHitKey(KEY_INPUT_DOWN))
		{
			playerY += 2;
		}
		if (CheckHitKey(KEY_INPUT_UP))
		{
			playerY -= 2;
		}
		if (CheckHitKey(KEY_INPUT_SPACE) && (shotTimer == 0))
		{
			if (shotFlag == 0)
			{
				shotX = playerX;
				shotY = playerY;
				shotFlag = 1;
				shotTimer = 20;
			}
			else if (shotFlag2 == 0)
			{
				shotX2 = playerX;
				shotY2 = playerY;
				shotFlag2 = 1;
				shotTimer = 20;
			}
			else if (shotFlag3 == 0)
			{
				shotX3 = playerX;
				shotY3 = playerY;
				shotFlag3 = 1;
				shotTimer = 20;
			}
		}

		//プレーヤーの移動制限
		if (playerX > SCREEN_W - PLAYER_W / 2)playerX = SCREEN_W - PLAYER_W / 2;
		if (playerX < PLAYER_W / 2)playerX = PLAYER_W/ 2;
		if (playerY > SCREEN_H - PLAYER_H / 2)playerY = SCREEN_H - PLAYER_H / 2;
		if (playerY < PLAYER_H / 2)playerY = PLAYER_H / 2;


		if (shotTimer > 0)
		{
			shotTimer--;
		}
		int dx = 0;
		if (shotFlag == 1 && enemyFlag == 1)
		{
			dx = (shotX - enemyX) * (shotX - enemyX) + (shotY - enemyY) * (shotY - enemyY);
			if (dx < 300 * 300)
			{
				
				enemyFlag = 0;
				shotFlag = 0;
				enemyTimer = (rand() % 100);
				enemyX = (rand() % 360);
			}
		}
		if (shotFlag2 == 1 && enemyFlag == 1)
		{
			dx = (shotX2 - enemyX) * (shotX2 - enemyX) + (shotY2 - enemyY) * (shotY2 - enemyY);
			if (dx < 300 * 300)
			{
				enemyFlag = 0;
				shotFlag2 = 0;
				enemyTimer = (rand() % 100);
				enemyX = (rand() % 360);
			}
		}
		if (shotFlag3 == 1 && enemyFlag == 1)
		{
			dx = (shotX3 - enemyX) * (shotX3 - enemyX) + (shotY3 - enemyY) * (shotY3 - enemyY);
			if (dx < 300 * 300)
			{
				enemyFlag = 0;
				shotFlag3 = 0;
				enemyTimer = (rand() % 100);
				enemyX = (rand() % 360);
			}
		}
		scrollY += 8;
		if (scrollY > SCREEN_H)
		{
			scrollY = 0;
		}

		if (shotFlag == 1)
		{
			shotY -= 4;
			if (shotY < 0)
			{
				shotFlag = 0;
			}
		}
		if (shotFlag2 == 1)
		{
			shotY2 -= 4;
			if (shotY2 < 0)
			{
				shotFlag2 = 0;
			}
		}

		if (shotFlag3 == 1)
		{
			shotY3 -= 4;
			if (shotY3 < 0)
			{
				shotFlag3 = 0;
			}
		}

		if (enemyFlag == 1) {
			enemyX += enemyVX; // X方向の移動
			enemyY += enemyVY; // Y方向の移動

			// 範囲外判定:敵が画面外に出たらフラグをオフにし再出現を準備
			if (enemyX < 0 || enemyX > SCREEN_W) {
				enemyVX = -enemyVX; // X方向の反転
			}
			if (enemyY < 0 || enemyY > SCREEN_H) {
				enemyVY = -enemyVY; // Y方向の反転
			}
		}
		else {
			// 敵の再出現処理
			if (enemyTimer-- < 0) {
				enemyFlag = 1;
				enemyX = rand() % SCREEN_W;
				enemyY = -100;
				enemyVX = rand() % 5 - 2; // -2~2のランダム速度
				enemyVY = rand() % 5 - 2; // -2~2のランダム速度
				enemyTimer = 50;
			}
		}
		DrawGraph(0, scrollY, handleBg, TRUE);
		DrawGraph(0, scrollY - SCREEN_H, handleBg, TRUE);
		DrawGraphCenter(playerX, playerY, handle, playerFlag);
		DrawGraphCenter(shotX, shotY, handleShot, shotFlag == 1);
		DrawGraphCenter(shotX2, shotY2, handleShot, shotFlag2 == 1);
		DrawGraphCenter(shotX3, shotY3, handleShot, shotFlag3 == 1);
		DrawGraphCenter(enemyX, enemyY, handleEnemy, TRUE);

		ScreenFlip();
	}
	DxLib_End();
}
//画像の中心位置基準で表示
//input x, y 表示位置座標
//handle 画像ID
//flag 表示/非表示
void DrawGraphCenter(int playerX, int playerY, int handle, bool flag)
{
	int width, height;

	if (flag)
	{
		GetGraphSize(handle, &width, &height);
		DrawGraph(playerX - (width / 2), playerY -( height / 2), handle, TRUE);
	}
}

ちなみに
DrawGraphCenter(shotX, shotY, handleShot, shotFlag == 1);
DrawGraphCenter(shotX2, shotY2, handleShot, shotFlag2 == 1);
DrawGraphCenter(shotX3, shotY3, handleShot, shotFlag3 == 1);

の部分は、ショットが敵に当たった時に画面にあと残りするようになったため修正。
(TRUEだとShotFlagの値に関係なく描画されていたため)

コメント

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