マップの生成と表示について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
Ofu
記事: 11
登録日時: 8年前
連絡を取る:

マップの生成と表示について

#1

投稿記事 by Ofu » 8年前

毎度お世話になっております。
以下のようなコードでマップをテキストファイルから読み込んで生成、更に主人公(カメラ)の座標に合わせて表示をしたいと思っているのですが、例外が発生してしまい、3日間ほど粗探しししていたのですが直せばいいのか分かりませんでした。

コードは以下の通りです。

コード:

/******* 使用定数宣言 *********/
#define CAMERA_X_RANGE					(9+2)								// カメラで表示できるX方向チップ数
#define CAMERA_Y_RANGE					(7+2)								// カメラで表示できるY方向チップ数

#define CHIP_EDGE_SIZE					32									// 1チップの1辺のサイズ

#define PLAYER_DIV_NUM					20									// プレイヤーの個別コード

#define MAP_X_MAX						100									// 1マップの最大X座標
#define MAP_Y_MAX						60									// 1マップの最大Y座標

/******* 使用構造体宣言 *******/
struct CHARAINDIVDATA {															// CHARAKINDDATA構造体		:キャラ種族別データ構造体
	short X = 0, Y = 0;														// 座標
	DIRECTION Direction = CHARA_DOWN;										// 向き
	short MaxHP = 8, HP = 8;												// 最大HPとHP
	short MaxMP = 0, MP = 0;												// 最大MPとMP
	short MaxFP = 100, FP = 0;												// 最大FPとFP(満腹度)
	short Power = 5, Guard = 5;												// 力と身の守り
	short PowerRaito = 10, GuardRaito = 10;									// 発揮する力の割合と発揮する身の守りの割合
	wchar_t CharaName[10] = L"ななし";										// 名前
};

struct MAPCHIPDATA {															// MAPCHIPDATA構造体		:マップチップデータ構造体
	int NormalTileGraphic[MAPCHIP_FILE_DIV];								// 普通のマップチップグラフィック
	int AutoTileGraphic[AUTOTILE_MAX][AUTOTILE_CHIP_DIV];					// オートタイルグラフィック
};	

struct MAPPROPERTY {															// MAPPROPERTY構造体		:マッププロパティ構造体
	short MaxX = 7, MaxY = 7;												// マップサイズ			
	int AroundChip = 0;														// マップ周囲のマップチップコード		
	BGMCODE BGM = NOPLAY;													// 再生BGM
};

/******* 使用クラス宣言 *******/
class SYSTEMLELATION {															// SYSTEMLELATIONクラス		:システム関連クラス
public:
	short CameraX, CameraY;													// CameraX,CameraY変数		:カメラ座標変数
	COLORSDATA ColorsData;													// ColorsData変数			:色データ記憶変数
	void GameMain();														// GameMain関数				:ゲームメイン画面処理関数
	void Init();															        // Init関数					:疑似コンストラクタ
	~SYSTEMLELATION();														// ~SYSTEMLELATION関数		:デストラクタ
};

class CHARALELATION {															// CHARALELATIONクラス		:キャラ関連クラス
public:
	CHARAINDIVDATA IndivData[MAP_NPC_MAX + 2];								       // IndivData変数			:表示中個体キャラデータ記憶変数
	CHARAKINDDATA KindData[CHARA_KIND];								               // KindData変数				:種族別データ記憶変数
	void Init();															       // Init関数					:疑似コンストラクタ
	~CHARALELATION();													       // ~CHARALELATION関数		:デストラクタ
};

class MAPLELATION {																// MAPLELATIONクラス		:マップ関連クラス
public:
	MAPCHIPDATA MapChipData;												// MapChipData変数			:チップデータ記憶変数	
	MAPPROPERTY Property[MAP_MAX];											// Property変数				:プロパティ記憶変数	
	int **Square[MAP_LAYER_MAX];											        // Square変数				:平面記憶配列
	bool CreateFlag;														// CreateFlag変数			:生成フラグ
	int LivingMapCode;														// LivingMapCode変数		:今いるマップのコード

	void Draw(bool);														// Draw関数				:マップ及びキャラ表示関数
	signed char Create(int);												        // Create関数				:読み込み生成関数
	void Delete();															// Delete関数				:マップ平面データ消去及びメモリ開放関数

	void Init();															        // Init関数				:疑似コンストラクタ
	~MAPLELATION();														// ~MAPLELATION関数		:デストラクタ
};

/******* 使用グローバル変数宣言 */
extern SYSTEMLELATION SystemLelation;						      				       // SystemLelation変数		:システム関連クラス変数

extern CHARALELATION CharaLetation;											// CharaLelation変数		:キャラ関連クラス変数

extern MAPLELATION MapLelation;												// MapLelation変数			:マップ関連クラス変数

/////// MAPLELATIONクラス関数定義 ///////
void MAPLELATION::Init() {
	CreateFlag = FALSE;		// 生成フラグ初期化

	/////// マップチップインプット ///////
	LoadDivGraph("Material\\MapChip\\MapChip1.png", MAPCHIP_FILE_X_DIV*MAPCHIP_FILE_Y_DIV, MAPCHIP_FILE_X_DIV, MAPCHIP_FILE_Y_DIV, CHIP_EDGE_SIZE, CHIP_EDGE_SIZE, MapChipData.NormalTileGraphic);

	/////// マッププロパティインプット ///////
	Property[(int)DEBUGROOM].MaxX = 7, Property[(int)DEBUGROOM].MaxY = 7, Property[(int)DEBUGROOM].AroundChip = MapChipData.NormalTileGraphic[1];		// デバッグルーム
}

void MAPLELATION::Draw(bool PlayerCenterFlug) {		// マップ描画関数
	if (PlayerCenterFlug == TRUE) {		// プレイヤーが中心に出るように描画(今回はこれ)
		SystemLelation.CameraX = CharaLelation.IndivData[TANUKI_DIV_NUM].X, SystemLelation.CameraY = CharaLelation.IndivData[TANUKI_DIV_NUM].Y;
		for (char layer = 0; layer < MAP_LAYER_MAX; layer++) {
			for (char y = -1; y < CAMERA_Y_RANGE; y++) {
				for (char x = -1; x < CAMERA_X_RANGE; x++) {
					if (((SystemLelation.CameraY - CAMERA_Y_RANGE / 2 + y < 0) || (SystemLelation.CameraY - CAMERA_Y_RANGE / 2 + y > Property[LivingMapCode].MaxY)) || ((SystemLelation.CameraX - CAMERA_X_RANGE / 2 + x < 0) || (SystemLelation.CameraX - CAMERA_X_RANGE / 2 + x > Property[LivingMapCode].MaxX))) {
						DrawGraph(x*CHIP_EDGE_SIZE-16, y*CHIP_EDGE_SIZE, Property[LivingMapCode].AroundChip,TRUE);		// マップ外側(マップデータにない領域)埋める
					} 
					else { 
/*例外*/				DrawGraph(x*CHIP_EDGE_SIZE-16, y*CHIP_EDGE_SIZE, MapChipData.NormalTileGraphic[Square[layer][SystemLelation.CameraY - CAMERA_Y_RANGE / 2 + y][SystemLelation.CameraX - CAMERA_X_RANGE / 2 + x]], TRUE);		// マップ内側の描画
					}
				}
			}
		}
	}


	

	return;
}


signed char MAPLELATION::Create(int mapnum) {		// マップ読み込み生成関数

	for (char layer = 0; layer < MAP_LAYER_MAX; layer++) {		// マップデータメモリ確保&初期化
		Square[layer] = new int*[Property[mapnum].MaxY];	
		for (char y = 0; y < Property[mapnum].MaxY; y++) {
			Square[layer][y] = new int[Property[mapnum].MaxX];
			
			ZeroMemory(Square[layer][y], sizeof(Square[layer][y]));	
		}
	}
	CreateFlag = TRUE;	// 生成フラグつける

	char FileName[32];	// ファイル名記憶
	sprintfDx(FileName, "Material\\MapData\\MapData%d.txt", mapnum + 1);

	char InputFC;	// 文字記憶

	int FileP = FileRead_open(FileName);	// ファイルへのポインタ
	if (FileP == NULL) {	// 失敗した場合
		return -1;
	}

	char cou = 0;

	while (cou <= 5) {
		while (FileRead_getc(FileP) != '\n');	// 1行改行

		for (char y = 0; y < Property[mapnum].MaxY; y++) {
			for (char x = 0; x < Property[mapnum].MaxX; x++) {
				int NumC[3] = { 0,0,0 };	// 1マスの数値格納配列
				for (char cou2 = 0; cou2 <= 3; cou2++) {
					InputFC = FileRead_getc(FileP);	// 1文字読み込む cou2=3なら区切り文字消化
					if (cou2 <= 2) {
						if (cou2 > 0 || InputFC == NULL) break;
						NumC[cou2] = InputFC - '0';		// 文字を数値とする
					}
				}
				Square[cou][y][x] = NumC[0] * 100 + NumC[1] * 10 + NumC[2];		// マップ平面データ配列に代入
			}
		}

		if (cou != 5) {		// 次のレイヤへ
			while (FileRead_getc(FileP) != '\n');
			while (FileRead_getc(FileP) != '\n');
		}
		else {		// ファイル閉じる
			FileRead_close(FileP);
		}
	}

	LivingMapCode = mapnum;		// 今いるマップコード記憶変数に代入

	return 0;
}

思い当たる箇所はこのくらいです。
毎度のことで大変恐縮でございますが、教えて頂ける方がおりましたら誠に感謝申し上げます。
欠陥等ございましたら申し訳ございません。直ぐに修正します。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: マップの生成と表示について

#2

投稿記事 by みけCAT » 8年前

添字のチェックが甘いので、
(SystemLelation.CameraY - CAMERA_Y_RANGE / 2 + y == Property[LivingMapCode].MaxY) || (SystemLelation.CameraX - CAMERA_X_RANGE / 2 + x == Property[LivingMapCode].MaxX)
のときに確保していない場所にアクセスしてしまい、よくないでしょう。
特に、
(SystemLelation.CameraY - CAMERA_Y_RANGE / 2 + y == Property[LivingMapCode].MaxY)
のとき、でたらめな場所を読み込むことになってしまい、アクセス違反が出る可能性が高いでしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: マップの生成と表示について

#3

投稿記事 by みけCAT » 8年前

Ofu さんが書きました:ZeroMemory(Square[layer][y], sizeof(Square[layer][y]));
ポインタにsizeof演算子を使っても、一般にそのポインタが指す配列の大きさは得られません。
(そのポインタの大きさが得られます)
配列の大きさは、「1要素の大きさ × 要素数」で計算できます。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: マップの生成と表示について

#4

投稿記事 by みけCAT » 8年前

Ofu さんが書きました: char FileName[32]; // ファイル名記憶
sprintfDx(FileName, "Material\\MapData\\MapData%d.txt", mapnum + 1);
mapnumが999以上または-101以下の場合、範囲外への書き込みが発生します。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: マップの生成と表示について

#5

投稿記事 by みけCAT » 8年前

Ofu さんが書きました: char cou = 0;

while (cou <= 5) {
while (FileRead_getc(FileP) != '\n'); // 1行改行

for (char y = 0; y < Property[mapnum].MaxY; y++) {
for (char x = 0; x < Property[mapnum].MaxX; x++) {
int NumC[3] = { 0,0,0 }; // 1マスの数値格納配列
for (char cou2 = 0; cou2 <= 3; cou2++) {
InputFC = FileRead_getc(FileP); // 1文字読み込む cou2=3なら区切り文字消化
if (cou2 <= 2) {
if (cou2 > 0 || InputFC == NULL) break;
NumC[cou2] = InputFC - '0'; // 文字を数値とする
}
}
Square[cou][y][x] = NumC[0] * 100 + NumC[1] * 10 + NumC[2]; // マップ平面データ配列に代入
}
}

if (cou != 5) { // 次のレイヤへ
while (FileRead_getc(FileP) != '\n');
while (FileRead_getc(FileP) != '\n');
}
else { // ファイル閉じる
FileRead_close(FileP);
}
}
コードを読んだだけで実行していないので、もしかしたら勘違いかもしれませんが、
  • whileループ中でcouが更新されず、このループを抜けるbreakやreturnも見当たらないので、無限ループになりそうです。
  • cou2に関するforループ中で
    • cou2 > 0のときループを抜けるという条件があるので、NumC[1]やNumC[2]は常に初期化した時の0のままです。
      バグであるとは限りません(拡張用などの可能性が考えられます)が、わざわざ常に0の変数が式に入っているのは不自然に思えます。
    • 整数(文字)とNULL(通常はポインタとして用いる)を比較しているのも怪しいです。
      参考として、FileRead_getcはエラーが起きたら-1を返します。
Square[cou][y][x]に意図した値が入っているかも確かめた方が良さそうに思えます。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Ofun

Re: マップの生成と表示について

#6

投稿記事 by Ofun » 8年前

>>みけCAT様、いつもアドバイスして下さり有難うございます。
しかし、やはりまだ解決と言うわけにはいきませんでした。

今現在例外の解決の手立てを模索中です。(と言っても殆ど進歩なしですが・・・)

返信

“C言語何でも質問掲示板” へ戻る