C言語Ⅱ⑦(2025/10/29)

消去パネルの選択表示にも対応させる。
(InfoArea.cpp)

void InfoArea::Update(void)
{
	int mx, my,ax,ay;
	int prevBtn = edScene->GetPrevButtonStat();	//直前のマウスボタンを取得
	int nowBtn = edScene->GetNowButtonStat();	//今のマウスボタン状態を取得

	GetMousePoint(&mx,&my);	//現在のマウスの座標(ウインドウ内)を取得(mx,myに格納される)

	//情報エリアにマウスカーソルが載っているかどうかを判定
	if (mx >= INFO_AREA_SX && mx < INFO_AREA_SX + INFO_AREA_WID && my >= INFO_AREA_SY && my < INFO_AREA_SY + INFO_AREA_HIG) {
		//情報エリア内の座標に変換する
		ax = mx - INFO_AREA_SX;
		ay = my - INFO_AREA_SY;

	if ((prevBtn & MOUSE_INPUT_LEFT) != 0 && (nowBtn & MOUSE_INPUT_LEFT) == 0) {
			//アップトリガーで左ボタンの押下判定(押された場合)
			//選択一覧内のマップチップが選択されたかどうかを調べる
		for (int ii = 0; ii < E_LAND_MAX; ii++) {
			int dx = INFO_CHIP_LIST_SX + (MAP_CHIP_WID + INFO_CHIP_DISTANCE_DX) * (ii % INFO_CHIP_DSP_XNUM);
		int dy = INFO_CHIP_LIST_SY + (MAP_CHIP_HIG + INFO_CHIP_DISTANCE_DY) * (ii / INFO_CHIP_DSP_XNUM);
		if (ax >= dx && ax < dx + MAP_CHIP_WID && ay >=dy&&ay<dy+MAP_CHIP_HIG) {
			selChipKind = ii;
			break;
		}
			}
		//消去用地形が選択されたかどうかを調べる
		if (ax >= INFO_CHIP_CLR_SX && ax < INFO_CHIP_CLR_SX + MAP_CHIP_WID && ay >= INFO_CHIP_CLR_SY && ay < INFO_CHIP_CLR_SY + MAP_CHIP_HIG) {
			selChipKind = E_LAND_CLEAR;
		}
	}

	}
		
}

全消去ボタンを描画
(InfoArea.cpp)

void InfoArea::Draw(void)
{
	SetDrawScreen(infScrn);	//情報画面用のスクリーンに切り替え

	DrawBox(0, 0, INFO_AREA_WID, INFO_AREA_HIG, GetColor(255, 255, 255), true);
	DrawString(INFO_INDEX_SX, INFO_INDEX_LIST_SY, "地形一覧", GetColor(247, 14, 70));

	//地形選択画像リストの描画
	for (int xy = 0; xy < E_LAND_MAX; xy++)
	{
		//座標計算だけ先に行う
		int dx = INFO_CHIP_LIST_SX + (MAP_CHIP_WID + INFO_CHIP_DISTANCE_DX) * (xy % INFO_CHIP_DSP_XNUM);
		int dy = INFO_CHIP_LIST_SY + (MAP_CHIP_HIG + INFO_CHIP_DISTANCE_DY) * (xy / INFO_CHIP_DSP_XNUM);
		//描画したい画像のハンドルを取得する
		int land = edScene->GetLandImageHndl((eLandFormKind)xy);//引数の型が違うのでキャストする
		DrawGraph(dx, dy, land, true);



	}
	//消去用地形
	DrawBox(INFO_CHIP_CLR_SX, INFO_CHIP_CLR_SY, INFO_CHIP_CLR_SX + MAP_CHIP_WID, INFO_CHIP_CLR_SY + MAP_CHIP_HIG, GetColor(0, 0, 0), true);
	DrawString(INFO_CHIP_LIST_SX + 8, INFO_CHIP_CLR_SY + 8, "消", GetColor(255, 255, 255));

	//選択地形の描画
	DrawString(INFO_INDEX_SX, INFO_INDEX_SELCHIP_SY, "選択地形", GetColor(23u, 14, 70));
	if (selChipKind == E_LAND_NON || selChipKind == E_LAND_CLEAR) {
		DrawBox(INFO_SELCHIP_DX,INFO_SELCHIP_DY,INFO_SELCHIP_DX+MAP_CHIP_WID,INFO_SELCHIP_DY+MAP_CHIP_HIG,GetColor(0, 0, 0), true);
		if (selChipKind == E_LAND_CLEAR) {
			DrawString(INFO_SELCHIP_DX + 8, INFO_SELCHIP_DY + 8, "消", GetColor(255, 255, 255));
		}
	}
	else {
		int hndl = edScene->GetLandImageHndl((eLandFormKind)selChipKind);//描画中の地形番号をキャストして渡して、ハンドル番号をhndlで受ける
		DrawGraph(INFO_SELCHIP_DX, INFO_SELCHIP_DY, hndl, true);
	}
				//消去用地形が選択されたかどうかを調べる
			if (ax >= INFO_CHIP_CLR_SX && ax < INFO_CHIP_CLR_SX + MAP_CHIP_WID && ay >= INFO_CHIP_CLR_SY && ay < INFO_CHIP_CLR_SY + MAP_CHIP_HIG) {
				selChipKind = E_LAND_CLEAR;
			}

			//全消去ボタンが押されたかどうかを調べる
			if (ax >= ALLCLEAR_BTN_DX && ax < ALLCLEAR_BTN_DX + ALLCLEAR_BTN_WID && ay >= ALLCLEAR_BTN_DY && ay < ALLCLEAR_BTN_DY + ALLCLEAR_BTN_HIG) {
				//edScene->ClearAllMapData();まだ未実装
			}

			//セーブボタンが押されたかどうかを調べる
			f (ax >= SAVE_BTN_DX && ax < SAVE_BTN_DX + SAVELOAD_BTN_WID && ay >= SAVE_BTN_DY && ay < SAVE_BTN_DY + SAVELOAD_BTN_HIG) {
				//edScene->SaveMapData();まだ未実装
			}

			//ロードボタンが押されたかどうかを調べる
			if( ax >= LOAD_BTN_DX && ax < LOAD_BTN_DX + SAVELOAD_BTN_WID && ay >= LOAD_BTN_DY && ay < LOAD_BTN_DY + SAVELOAD_BTN_HIG) {
				//edScene->LoadMapData();まだ未実装
			}

この部分は要するにこう。

// 引数
DrawBox(x座標, y座標, x+幅, y+高さ, 色, 塗りつぶし);
DrawString(x+文字オフセット, y+文字オフセット, "ラベル", 色);

追加したボタンの押下判定を作る。
(InfoArea.cpp)

void InfoArea::Update(void)
{
	int mx, my,ax,ay;
	int prevBtn = edScene->GetPrevButtonStat();	//直前のマウスボタンを取得
	int nowBtn = edScene->GetNowButtonStat();	//今のマウスボタン状態を取得

	GetMousePoint(&mx,&my);	//現在のマウスの座標(ウインドウ内)を取得(mx,myに格納される)

	//情報エリアにマウスカーソルが載っているかどうかを判定
	if (mx >= INFO_AREA_SX && mx < INFO_AREA_SX + INFO_AREA_WID && my >= INFO_AREA_SY && my < INFO_AREA_SY + INFO_AREA_HIG) {
		//情報エリア内の座標に変換する
		ax = mx - INFO_AREA_SX;
		ay = my - INFO_AREA_SY;

		if ((prevBtn & MOUSE_INPUT_LEFT) != 0 && (nowBtn & MOUSE_INPUT_LEFT) == 0) {
			//アップトリガーで左ボタンの押下判定(押された場合)
			//選択一覧内のマップチップが選択されたかどうかを調べる
			for (int ii = 0; ii < E_LAND_MAX; ii++) {
				int dx = INFO_CHIP_LIST_SX + (MAP_CHIP_WID + INFO_CHIP_DISTANCE_DX) * (ii % INFO_CHIP_DSP_XNUM);
				int dy = INFO_CHIP_LIST_SY + (MAP_CHIP_HIG + INFO_CHIP_DISTANCE_DY) * (ii / INFO_CHIP_DSP_XNUM);
				if (ax >= dx && ax < dx + MAP_CHIP_WID && ay >=dy&&ay<dy+MAP_CHIP_HIG) {
					selChipKind = ii;
					break;
				}
			}
			//消去用地形が選択されたかどうかを調べる
			if (ax >= INFO_CHIP_CLR_SX && ax < INFO_CHIP_CLR_SX + MAP_CHIP_WID && ay >= INFO_CHIP_CLR_SY && ay < INFO_CHIP_CLR_SY + MAP_CHIP_HIG) {
				selChipKind = E_LAND_CLEAR;
			}

			//全消去ボタンが押されたかどうかを調べる
			if (ax >= ALLCLEAR_BTN_DX && ax < ALLCLEAR_BTN_DX + ALLCLEAR_BTN_WID && ay >= ALLCLEAR_BTN_DY && ay < ALLCLEAR_BTN_DY + ALLCLEAR_BTN_HIG) {
				edScene->ClearAllMapData();
			}

			//セーブボタンが押されたかどうかを調べる
			if (ax >= SAVE_BTN_DX && ax < SAVE_BTN_DX + SAVELOAD_BTN_WID && ay >= SAVE_BTN_DY && ay < SAVE_BTN_DY + SAVELOAD_BTN_HIG) {
				edScene->SaveMapData();
			}

			//ロードボタンが押されたかどうかを調べる
			if( ax >= LOAD_BTN_DX && ax < LOAD_BTN_DX + SAVELOAD_BTN_WID && ay >= LOAD_BTN_DY && ay < LOAD_BTN_DY + SAVELOAD_BTN_HIG) {
				edScene->LoadMapData();
			}
		}

	}
		
}

〇ifの羅列かelse ifか
ifとelse ifの違いは「同時に条件が成立する可能性があるかどうか」です。
そして今回のようなマウスクリック座標による判定
では、同時に複数の条件が成立することは基本的にないので、ifの羅列でも構造的には問題ありません

🧠 if vs else if の構造的違い

if (...) {}条件が成立すれば実行すべてのifが個別に評価される
else if (...) {}直前のifが不成立なら評価どれか1つだけが実行される(最初に成立したもの)

🧩今回のコード構造における意味

if (ax >= INFO_CHIP_CLR_SX && ...) {
    selChipKind = E_LAND_CLEAR;
}

if (ax >= ALLCLEAR_BTN_DX && ...) {
    // 全消去
}
else if (ax >= SAVE_BTN_DX && ...) {
    // セーブ
}
else if (ax >= LOAD_BTN_DX && ...) {
    // ロード
}
  • INFO_CHIP_CLR_SXの判定は選択チップ用で、他のボタンとは別のUI領域
  • ALLCLEAR, SAVE, LOAD同じUIエリア内のボタン群なので、同時に押されることはない
  • つまり、すべてifで書いても、実行結果は変わらない

✅構造的にどう書くべきか?

パターンA:全部ifで書く(並列評価)

if (選択チップが押された) { ... }
if (全消去が押された) { ... }
if (セーブが押された) { ... }
if (ロードが押された) { ... }

構造が明快。それぞれの判定が独立していることがわかる。

パターンB:else ifで書く(排他評価)

if (全消去が押された) { ... }
else if (セーブが押された) { ... }
else if (ロードが押された) { ... }

排他性を強調したいときに有効。
→ ただし、選択チップ判定は別扱いにすべき。(by Copilot)


未実装の関数等を使わずに、動作を確認する場合には
“int a = 1;”のような、意味のないコードを書いて、その行にブレークポイントを設置⇒デバッグで止まるかどうかを確認するのも一つの方法。

※ブレークポイントをまとめて削除
デバッグ>すべてのブレークポイントを削除

EditArea.cpp、EditArea.hを作成。記述していく。
(EditArea.h)

#pragma once

#include "StDefine.h"

class EditScene;

class EditArea
{
	public:
        // マップ表示エリアの幅	
       static const int MAP_AREA_WID = EDIT_AREA_WID - MAP_CHIP_WID;
	// マップ表示エリアの高さ
	static const int MAP_AREA_HIG = EDIT_AREA_HIG - MAP_CHIP_HIG;
        // マップ表示エリアの表示開始位置X
	static const int MAP_AREA_SX = MAP_CHIP_WID / 2;
	// マップ表示エリアの表示開始位置Y
	static const int MAP_AREA_SY = MAP_CHIP_HIG / 2;	

	// 上矢印
	static const int UPPER_ARROW_SX = MAP_AREA_SX;
	static const int UPPER_ARROW_SY = 0;
	static const int UPPER_ARROW_WID = MAP_AREA_WID;
	static const int UPPER_ARROW_HIG = 14;

	// 下矢印
	static const int LOWER_ARROW_SX = UPPER_ARROW_SX;
	static const int LOWER_ARROW_SY = MAP_AREA_SY + MAP_AREA_HIG + 2;
	static const int LOWER_ARROW_WID = UPPER_ARROW_WID;
	static const int LOWER_ARROW_HIG = UPPER_ARROW_HIG;

	// 左矢印
	static const int LEFT_ARROW_SX = 0;
	static const int LEFT_ARROW_SY = MAP_AREA_SY;
	static const int LEFT_ARROW_WID = 14;
	static const int LEFT_ARROW_HIG = MAP_AREA_HIG;

	// 右矢印
	static const int RIGHT_ARROW_SX = MAP_AREA_SX + MAP_AREA_WID + 2;
	static const int RIGHT_ARROW_SY = LEFT_ARROW_SY;
	static const int RIGHT_ARROW_WID = LEFT_ARROW_WID;
	static const int RIGHT_ARROW_HIG = LEFT_ARROW_HIG;

	// 編集エリアの横のマップチップ表示個数
	static const int DSP_CHIP_XNUM = MAP_AREA_WID / MAP_CHIP_WID;
	// 編集エリアの縦のマップチップ表示個数
	static const int DSP_CHIP_YNUM = MAP_AREA_HIG / MAP_CHIP_HIG;
		
	EditArea(EditScene* eds);	//親クラスのインスタンスのポインタを受け取る
	~EditArea(void);
	bool SystemInit(void);
	void Update(void);
	void Draw(void);
	bool Release(void);
	int GetEditScreenHandle(void) { return edScrn; }
	void AllMapClear(void);	//マップデータを全消去する関数
	
private:
	
	EditScene* edScene;		//EditSceneClassのインスタンスのポインタ
	
	int edScrn;			//編集エリア用スクリーンハンドル

	int dspStartX, dspStartY;	//編集エリア内の表示開始マップチップ座標
	int mapData[MAP_SIZE_Y][MAP_SIZE_X];	//マップデータ(縦/横の順序で定義)

};

関数の実装。
(EditArea.cpp)

//----------------------------------------------------
// map editor
// name:ゆき
//----------------------------------------------------
//EditArea class

#include"DxLib.h"
#include"EditArea.h"
#include"EditScene.h"

EditArea::EditArea(EditScene* eds)
{
	edScene = eds;
	edScrn = -1;
}
EditArea::~EditArea(void)
{
}

bool EditArea::SystemInit(void)
{
	//スクリーンの作成
	edScrn = MakeScreen(EDIT_AREA_WID, EDIT_AREA_HIG, true);
	if (edScrn == -1)return false;

	dspStartX = dspStartY = 0;
	//マップデータの初期化(全て海にする)

	AllMapClear();

	return true;
}

void EditArea::Update(void)
{
	//編集エリアの更新処理
}

void EditArea::Draw(void)
{
	//編集エリアの描画処理
}

bool EditArea::Release(void)
{
	return true;
}

void EditArea::AllMapClear(void)
{
	//マップデータの全消去(全て空白にする)
	for (int yy = 0; yy < MAP_SIZE_Y; yy++) {
		for (int xx = 0; xx < MAP_SIZE_X; xx++) {
			mapData[yy][xx] = E_LAND_NON;
		}
	}
}

MakeScreen()

MakeScreen(EDIT_AREA_WID, EDIT_AREA_HIG, true) って、DxLibの関数だよね?? そもそも裏画面とか表画面って概念は、Windowsアプリなら大体同じってならったけど、実装的にはDxLibで定義されているって理解でいいかな?

はい、MakeScreenはDxLibの関数で、裏画面・表画面の概念もDxLib内で定義・管理されています。Windows APIにも類似の概念はありますが、DxLibではそれを独自に抽象化して扱いやすくしています。

🧠 MakeScreen()の役割と構造

  • 関数定義int MakeScreen(int SizeX, int SizeY, int AlphaFlag);
  • 目的:指定サイズの「描画可能なスクリーン(仮想画面)」を作成し、そのハンドルを返す。
  • 引数の意味
  • SizeX, SizeY:スクリーンの幅と高さ(例:EDIT_AREA_WID, EDIT_AREA_HIG
  • AlphaFlagtrueならαチャンネル付き(半透明対応)

このスクリーンは、**裏画面とは別に存在する“描画用のバッファ”**で、
SetDrawScreen()で描画先を切り替えることで、一時的な描画や合成処理が可能になります。

🪟 Windowsアプリとの関係

  • Windows APIにも**バックバッファ(裏画面)→フロントバッファ(表画面)**という描画モデルがあります。
  • DxLibはそれをゲーム開発向けに抽象化・簡略化して提供しており、
  • DX_SCREEN_BACK:裏画面(通常の描画先)
  • DX_SCREEN_FRONT:表画面(直接描画)
  • MakeScreen():任意のサイズの仮想スクリーンを生成

つまり、裏画面・表画面の概念はWindowsにもあるけれど、DxLibではそれを独自に管理・拡張しているという理解で正しいです。

🧩ゆきさんの理解は文明的に正確

「Windowsアプリなら大体同じってならったけど、実装的にはDxLibで定義されているって理解でいいかな?」

→ まさにその通り。概念は共通、実装はライブラリ依存
DxLibは、Windowsの描画モデルをベースに、教育・ゲーム開発向けに構造化された抽象レイヤーです。

🧩 DxLibの描画構造(簡易図

[DX_SCREEN_BACK] ← 通常の裏画面(SetDrawScreenで指定)
       ↑
       │
[MakeScreenで作った仮想スクリーン] ← 任意サイズの描画バッファ
       ↓
[DX_SCREEN_FRONT] ← 表画面(画面に表示される)

🛠 実用例(MapEditor授業での使い方)

int infScrn = MakeScreen(EDIT_AREA_WID, EDIT_AREA_HIG, true);
SetDrawScreen(infScrn); // 情報エリアの描画先を切り替え
DrawBox(...);           // 情報エリアに描画
SetDrawScreen(DX_SCREEN_BACK); // 元に戻す

→ こうすることで、情報エリアだけを別スクリーンに描画して、合成表示することが可能になります。
「裏画面・表画面の概念はWindowsにもあるけど、実装はDxLibで定義されている」——その通りです。

コメント

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