マップエディターのファイルの読み込み方。

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

マップエディターのファイルの読み込み方。

#1

投稿記事 by keito94 » 3年前

Platinumというマップエディターでマップを読み込んでそれを呼び出すプログラムを書いているのですが、ソースコードのようなエラーが起こってしまいます。
Source.cpp

コード:

#include "DxLib.h"
#include "fmfmap.h"
const int MAP_CELL = 16;
class CGame {
	int BitCount;
	int MapGraph;
	CFmfMap MapObj;
public:

	//コンストラクター。
	CGame() {
		MapLoad("テスト用.fmf", "マップチップ.bmp");
	}

	//マップチップの読み込みライブラリを呼び出す。
	CFmfMap MapData() {
		return MapObj;
	}
	//マップを呼び出す。
	int MapLoad(const char* mapname,const char* mapchip) {
		if (!MapData().Open(mapname)) {
			return -1;
		}
		BYTE* layer = (BYTE*)MapData().GetLayerAddr(0);
		if (layer == NULL) {
			MapData().Close();
			return -1;
		}
		if (MapGraph = LoadGraph(mapchip) == -1) {
			return -1;
		}
		BitCount = MapData().GetLayerBitCount() == 8 ? 16 : 256;
		return 0;
	}

	//ビットカウントを獲得する。
	int GetBitCount() {
		return BitCount;
	}

	//デストラクター。
	~CGame() {

	}

	//マップの描画。
	void Draw() {
		DWORD cwidth = MapData().GetChipWidth();
		DWORD cheight = MapData().GetChipHeight();
		for (int y = 0; y < 15; y++) {
			for (int x = 0; x < 20; y++) {
				int index = MapData().GetValue(0, x, y);
				int src_x = (index % GetBitCount())*cwidth;
				int src_y = (index / GetBitCount())*cheight;
				DrawRectGraph((x)*MAP_CELL, (y)*MAP_CELL, src_x, src_y, MAP_CELL, MAP_CELL, MapGraph, TRUE, FALSE);
			}
		}
	}
};


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevHinstance, LPSTR lpCmdLine, int nCmdShow) {
	ChangeWindowMode(TRUE), SetGraphMode(320, 240, 32), DxLib_Init();
	CGame* Game;
	Game = new CGame;
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
		Game->Draw();
	}
	delete Game;
	DxLib_End();
	return 0;
}
fmfmap.cpp

コード:


#include "fmfmap.h"

//-----------------------------------------------------------------------------
//	コンストラクタ
//-----------------------------------------------------------------------------
CFmfMap::CFmfMap(void) : m_pLayerAddr(NULL)
{}
//-----------------------------------------------------------------------------
//	デストラクタ
//-----------------------------------------------------------------------------
CFmfMap::~CFmfMap()
{
	Close();
}	
//-----------------------------------------------------------------------------
//	マップを開いてデータを読み込む
// 引数:	szFilePath	= マップファイルのパス
// 戻り値:	正常終了	= TRUE
//			エラー		= FALSE
//-----------------------------------------------------------------------------
BOOL CFmfMap::Open(const char *szFilePath)
{
	Close();

	// ファイルを開く
	HANDLE hFile = CreateFile(	szFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
								OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
		return FALSE;

	// ヘッダ情報を読む
	DWORD dwReadBytes;
	if (!ReadFile(hFile, &m_fmfHeader, sizeof(FMFHEADER), &dwReadBytes, NULL) ||
		dwReadBytes != sizeof(FMFHEADER))
		goto error_return;

	// 識別子のチェック
	if (memcmp(&m_fmfHeader.dwIdentifier, "FMF_", 4) != 0)
		goto error_return;

	// メモリ確保
	m_pLayerAddr = new BYTE[m_fmfHeader.dwSize];
	if (m_pLayerAddr == NULL)
		goto error_return;

	// レイヤーデータを読む
	if (!ReadFile(hFile, m_pLayerAddr, m_fmfHeader.dwSize, &dwReadBytes, NULL) ||
		dwReadBytes != m_fmfHeader.dwSize)
		goto error_return;
	
	// 正常終了
	CloseHandle(hFile);
	return TRUE;

error_return:
	// エラー終了
	CloseHandle(hFile);
	Close();
	return FALSE;
}
//-----------------------------------------------------------------------------
// マップが開かれているか
//-----------------------------------------------------------------------------
BOOL CFmfMap::IsOpen() const
{
	return m_pLayerAddr != NULL;
}
//-----------------------------------------------------------------------------
//	マップメモリを開放
//-----------------------------------------------------------------------------
void CFmfMap::Close(void)
{
	if (m_pLayerAddr != NULL)
	{
		delete [] m_pLayerAddr;
		m_pLayerAddr = NULL;
	}
}
//-----------------------------------------------------------------------------
//	指定レイヤの先頭アドレスを得る
//	引数:	レイヤ番号
//	戻り値:	正常終了	= レイヤデータのアドレス
//			エラー		= NULL
//	各レイヤデータは連続したメモリ領域に配置されてるので
//	指定レイヤデータのアドレスを計算で求める。
//-----------------------------------------------------------------------------
void* CFmfMap::GetLayerAddr(BYTE byLayerIndex) const
{
	// メモリチェック、範囲チェック
	if ((m_pLayerAddr == NULL) || (byLayerIndex >= m_fmfHeader.byLayerCount))
		return NULL;

	BYTE bySize = m_fmfHeader.byBitCount / 8;
	return m_pLayerAddr + m_fmfHeader.dwWidth * m_fmfHeader.dwHeight * bySize * byLayerIndex;
}
//-----------------------------------------------------------------------------
// レイヤ番号と座標を指定して直接データを貰う
// 引数:
// 	byLayerIndex	= レイヤ番号
// 	dwX				= X座標(0~m_fmfHeader.dwWidth - 1)
// 	dwY				= Y座標(0~m_fmfHeader.dwHeight - 1)
// 戻り値:
// 	正常終了	= 座標の値
//	エラー		= -1
//-----------------------------------------------------------------------------
int CFmfMap::GetValue(BYTE byLayerIndex, DWORD dwX, DWORD dwY) const
{
	int nIndex = -1;

	// 範囲チェック
	if (byLayerIndex >= m_fmfHeader.byLayerCount ||
		dwX >= m_fmfHeader.dwWidth ||
		dwY >= m_fmfHeader.dwHeight)
		return nIndex;

	if (m_fmfHeader.byBitCount == 8)
	{
		// 8bit layer
		BYTE* pLayer = (BYTE*)GetLayerAddr(byLayerIndex);
		nIndex = *(pLayer + dwY * m_fmfHeader.dwWidth + dwX);
	}
	else
	{
		// 16bit layer	
		WORD* pLayer = (WORD*)GetLayerAddr(byLayerIndex);
		nIndex = *(pLayer + dwY * m_fmfHeader.dwWidth + dwX);	 //ここでpLayerが0x1110112でしたという例外がスローされる。
	}

	return nIndex;
}

//-----------------------------------------------------------------------------
// レイヤ番号と座標を指定してデータをセット
//-----------------------------------------------------------------------------
void CFmfMap::SetValue(BYTE byLayerIndex, DWORD dwX, DWORD dwY, int nValue)
{
	// 範囲チェック
	if (byLayerIndex >= m_fmfHeader.byLayerCount ||
		dwX >= m_fmfHeader.dwWidth ||
		dwY >= m_fmfHeader.dwHeight)
		return;

	if (m_fmfHeader.byBitCount == 8)
	{
		// 8bit layer
		BYTE* pLayer = (BYTE*)GetLayerAddr(byLayerIndex);
		*(pLayer + dwY * m_fmfHeader.dwWidth + dwX) = (BYTE)nValue;
	}
	else
	{
		// 16bit layer	
		WORD* pLayer = (WORD*)GetLayerAddr(byLayerIndex);
		*(pLayer + dwY * m_fmfHeader.dwWidth + dwX) = (WORD)nValue;
	}
}

//-----------------------------------------------------------------------------
// マップの横幅を得る
//-----------------------------------------------------------------------------
DWORD CFmfMap::GetMapWidth(void) const
{
	return m_fmfHeader.dwWidth;
}
//-----------------------------------------------------------------------------
// マップの高さを得る
//-----------------------------------------------------------------------------
DWORD CFmfMap::GetMapHeight(void) const
{
	return m_fmfHeader.dwHeight;
}
//-----------------------------------------------------------------------------
// チップの横幅を得る
//-----------------------------------------------------------------------------
BYTE CFmfMap::GetChipWidth(void) const
{
	return m_fmfHeader.byChipWidth;
}
//-----------------------------------------------------------------------------
// チップの高さを得る
//-----------------------------------------------------------------------------
BYTE CFmfMap::GetChipHeight(void) const
{
	return m_fmfHeader.byChipHeight;
}
//-----------------------------------------------------------------------------
// レイヤー数を得る
//-----------------------------------------------------------------------------
BYTE CFmfMap::GetLayerCount(void) const
{
	return m_fmfHeader.byLayerCount;
}
//-----------------------------------------------------------------------------
// レイヤーデータのビットカウントを得る
//-----------------------------------------------------------------------------
BYTE CFmfMap::GetLayerBitCount(void) const
{
	return m_fmfHeader.byBitCount;
}
fmfmap.h

コード:

#ifndef __CLASS_FMFMAP_H__
#define __CLASS_FMFMAP_H__
#pragma once

#include <windows.h>

// FMFファイルヘッダ (20 bytes)
typedef struct tag_FMFHeader
{
	DWORD	dwIdentifier;	// ファイル識別子 'FMF_'
	DWORD	dwSize;			// ヘッダを除いたデータサイズ
	DWORD	dwWidth;		// マップの横幅
	DWORD	dwHeight;		// マップの高さ
	BYTE	byChipWidth;	// マップチップ1つの幅(pixel)
	BYTE	byChipHeight;	// マップチップ1つの高さ(pixel)
	BYTE	byLayerCount;	// レイヤーの数
	BYTE	byBitCount;		// レイヤデータのビットカウント
}FMFHEADER;

class CFmfMap
{
public:
	// 構築/消滅
	CFmfMap(void);
	~CFmfMap();

	// マップを開いてデータを読み込む
	BOOL Open(const char *szFilePath);

	// マップが開かれているか
	BOOL IsOpen() const;

	// マップメモリを開放
	void Close(void);
		
	// 指定レイヤーの先頭アドレスを得る
	void* GetLayerAddr(BYTE byLayerIndex) const;
	
	// レイヤ番号と座標を指定して直接データを貰う
	int GetValue(BYTE byLayerIndex, DWORD dwX, DWORD dwY) const;

	// レイヤ番号と座標を指定してデータをセット
	void SetValue(BYTE byLayerIndex, DWORD dwX, DWORD dwY, int nValue);

	// ヘッダの情報を得る
	DWORD GetMapWidth(void) const;
	DWORD GetMapHeight(void) const;
	BYTE GetChipWidth(void) const;
	BYTE GetChipHeight(void) const;
	BYTE GetLayerCount(void) const;
	BYTE GetLayerBitCount(void) const;
protected:
	// FMFファイルヘッダ構造体
	FMFHEADER	m_fmfHeader;
	// レイヤーデータへのポインタ
	BYTE* 		m_pLayerAddr;
};
エラーログを取っておいたのでそれも参考にしてください。

コード:

例外がスローされました:読み取りアクセス違反。
**pLayer** が 0x1110112 でした。 が発生しました
デバッグは投げ捨てるものではない。
今までの質問でこれは学んだこと。
質問する時は、必ずちゃんと調べた上に問題をもとにした仕様書を作ってから質問すること。
仕様書の大切さを改めて思い知った…。

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

Re: マップエディターのファイルの読み込み方。

#2

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

keito94 さんが書きました:ソースコードのようなエラーが起こってしまいます。
わざわざご報告ありがとうございます。
デバッグトレーニング中なんですよね。
何か質問はありますか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
keito94
記事: 264
登録日時: 3年前
連絡を取る:

Re: マップエディターのファイルの読み込み方。

#3

投稿記事 by keito94 » 3年前

みけCAT さんが書きました: 何か質問はありますか?
すいません、質問を忘れていました。
どうすれば、例外をスローせずにマップを表示させることができますか?
デバッグは投げ捨てるものではない。
今までの質問でこれは学んだこと。
質問する時は、必ずちゃんと調べた上に問題をもとにした仕様書を作ってから質問すること。
仕様書の大切さを改めて思い知った…。

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

Re: マップエディターのファイルの読み込み方。

#4

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

オフトピック
このエラーの原因ではないと思いますが、
keito94 さんが書きました:Source.cpp

コード:

		if (MapGraph = LoadGraph(mapchip) == -1) {
という行では読み込んだ結果のハンドルではなく読み込めなかったかどうかがMapGraphに代入され、不自然だと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

梅衣堂ひよ
記事: 24
登録日時: 3年前

Re: マップエディターのファイルの読み込み方。

#5

投稿記事 by 梅衣堂ひよ » 3年前

GetLayerAddrの返り値、

コード:

    return m_pLayerAddr + m_fmfHeader.dwWidth * m_fmfHeader.dwHeight * bySize * byLayerIndex;
となっていますが、レイヤー全体の先頭アドレスに対してマップのサイズを足しちゃダメじゃないですかね?
結構説明が下手ですのでご了承ください。割と言葉が足りなかったり文字だらけで分かりにくかったりします。

アバター
keito94
記事: 264
登録日時: 3年前
連絡を取る:

Re: マップエディターのファイルの読み込み方。

#6

投稿記事 by keito94 » 3年前

>>梅衣堂ひよ さん
マップエディターについているマップ読み込みのためのコードで、可読性を重視しているから仕方ないのです。
デバッグは投げ捨てるものではない。
今までの質問でこれは学んだこと。
質問する時は、必ずちゃんと調べた上に問題をもとにした仕様書を作ってから質問すること。
仕様書の大切さを改めて思い知った…。

梅衣堂ひよ
記事: 24
登録日時: 3年前

Re: マップエディターのファイルの読み込み方。

#7

投稿記事 by 梅衣堂ひよ » 3年前

あ、すいません。マップの座標と勘違いしてましたw
レイヤーだから3次元目の移動だから2次元分である座標は無視しないとですよね
最後に編集したユーザー 梅衣堂ひよ on 2017年4月29日(土) 18:58 [ 編集 1 回目 ]
結構説明が下手ですのでご了承ください。割と言葉が足りなかったり文字だらけで分かりにくかったりします。

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

Re: マップエディターのファイルの読み込み方。

#8

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

CGame::MapData()関数が毎回MapObjのコピーを返しているので、せっかく読み込んだマップを投げ捨てて以降の処理で利用できなくなっています。
コピーではなく参照を返すようにするか、この関数を消して直接MapObjを使うようにするといいでしょう。
ただし、Source.cppの51行目でxのかわりにyをインクリメントしているので、落ちなくなってもフリーズするでしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
keito94
記事: 264
登録日時: 3年前
連絡を取る:

Re: マップエディターのファイルの読み込み方。

#9

投稿記事 by keito94 » 3年前

データ関係は、コピーではなく参照を渡せばいいわけなんですね!!
一つC++の知識が増えました!!
ありがとうございます!!
オフトピック
僕がthisポインタを学んだことによって、炎上の原因にもなった問題が簡単に解決しました!!(あの時はC++の知識がほんとになかったもので…。)
あと、51行目のxの代わりにyをインクリメントしていた件についてはご指摘ありがとうございました!!
デバッグは投げ捨てるものではない。
今までの質問でこれは学んだこと。
質問する時は、必ずちゃんと調べた上に問題をもとにした仕様書を作ってから質問すること。
仕様書の大切さを改めて思い知った…。

梅衣堂ひよ
記事: 24
登録日時: 3年前

Re: マップエディターのファイルの読み込み方。

#10

投稿記事 by 梅衣堂ひよ » 3年前

オフトピック
テストしていて気付いたことですが、描画の際に気になった点が2つあります。
まず、チップサイズはヘッダーからマップ情報として読み込んでいるのに定数で用意していますね。
定数の方は消してマップ情報からチップのサイズを引っ張ったやつを使ってあげましょう。
それとfor文の条件の最大値ですね。
マップのサイズを与えればいいと思います。
画面外を描画しないようにするのはスクロールと合わせてちょっと工夫は必要ですが…
結構説明が下手ですのでご了承ください。割と言葉が足りなかったり文字だらけで分かりにくかったりします。

アバター
keito94
記事: 264
登録日時: 3年前
連絡を取る:

Re: マップエディターのファイルの読み込み方。

#11

投稿記事 by keito94 » 3年前

あっ、解決押すの忘れてました!
デバッグは投げ捨てるものではない。
今までの質問でこれは学んだこと。
質問する時は、必ずちゃんと調べた上に問題をもとにした仕様書を作ってから質問すること。
仕様書の大切さを改めて思い知った…。

返信

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