DXライブラリとVisalStudio2017communityを利用しています。
次のマップデータを読み込みたいのですが出来ません。
次のマップデータは、ご覧の通り、カンマで区切っている2桁で一組の文字列で出来ています。
次のマップデータを読み込むには、次の課題をクリアしなければなりません。
1.カンマを読み込まないで読み込みたい文字列だけを読み込む。
2.00,11,AAなど、一組の文字列として読み込む。
00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11,00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11
00,00,00,00,00,00,00,00,00,00,00,00,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
以上のマップデータを読み込むために、書籍やネットなどの情報を参考に、考えられる方法を試しました。
しかし、すべて失敗してフリーズしてしまいました。
ソースコードは、「配列とfor文を使っているのに画像が一つしか表示されない。」に体裁されたものに、
ファイル読み込み用関数void MapLoad();を追加したものです。
画像は、以前、みけCATさんが投稿してくれたものそのまま利用するのはいかがなものかと思ったので、
参考にして自分で描いたものを投稿します。
ファイル読み込みのソースコードはvoid MapLoad(){}の中に書いています。
一つは、以下のようにsscanf_s();関数で分割する方法です。
しかし、失敗してフリーズしてしまいました。
方法1
#include <DxLib.h>
#define MAPSIZE 32 //マップサイズを決めます。
#define HEIGHT 15 //Y座標の最大値を決めます
#define WIDTH 40 //X座標の最大値を決めます
//キャラクターの数の最大値を決めます。念のために多めにします。今回はマップデータの数に合わせます。
#define CHARA HEIGHT*WIDTH
//画像データの構造体を作ります。
//画像データは無理に配列やポインタで整理しようとすると、エラーやフリーズの原因になります。
struct ImageData{
int kabe01; //
int teki0A[2]; //
};
struct ImageData im; //
//各キャラクターのデータの構造体を作ります。
struct CharaData{
//int *ghandle; //アニメーションさせるために画像データハンドル。
//ポインタ設定をしたが、これが原因の一つでした。
char kind; //キャラクターの種類を格納。
int anime_pattern; //アニメパーン数
float x; //座標はfloatにします。
float y;
int body; //体力
};
struct CharaData charadata[CHARA]; //今回はcharadataと名づけます。
//キャラクターは複数出現させるので、配列内に各キャラクターの最大値CHMAXを格納します。
//struct CharaData im[2]; //画像を描画するための変数。
//or//struct CharaData im[CHARA]; //画像を描画するための変数。
//アニメーションカウンター用の変数を作ります。
unsigned int g_anime_counter=0;
//マップデータを作ります。
char mapdata[HEIGHT][WIDTH];
//メモ帳からマップデータを読み込み
void MapLoad(){
//各キャラクターのデータを初期化します。
ZeroMemory(charadata,sizeof(charadata));
char buf[1024];
sprintf_s(buf,1024,"media/map%d",1); //ファイル名を用意する
int fp; //ファイルハンドル
fp==FileRead_open(buf); //ファイルを開く
//ファイル読み込みエラー処理
if(fp=NULL){
printfDx("ファイル読み込みエラー");
return;
}
/////////////////////////////ここから////////////////////////////
int x=0;
for(int y=0;y<HEIGHT;y++){
for(int x=0;x<WIDTH;x++){
//1024が1023に減っているのは、NULL文字対策
FileRead_gets(buf,1023,fp); //ファイルを一行読み込む
char c[WIDTH];
//01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40
sscanf_s(buf,"%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s",
"&c[0]","&c[1]","&c[2]","&c[3]","&c[4]","&c[5]","&c[6]","&c[7]","&c[8]","&c[9]",
"&c[10]","&c[11]","&c[12]","&c[13]","&c[14]","&c[15]","&c[16]","&c[17]","&c[18]","&c[19]",
"&c[20]","&c[21]","&c[22]","&c[23]","&c[24]","&c[25]","&c[26]","&c[27]","&c[28]","&c[29]",
"&c[30]","&c[31]","&c[32]","&c[33]","&c[34]","&c[35]","&c[36]","&c[37]","&c[38]","&c[39]");
mapdata[y][x] = c[x];
//FileRead_gets(mapdata[y], c[x], fp);
//FileRead_gets(mapdata[y], buf[x], fp);
//FileRead_gets(mapdata[y], buf[WIDTH], fp);
x++;
} //for(int x=0;x<WIDTH;x++)
} //for(int y=0;y<HEIGHT;y++)の最後
/////////////////////////////ここまで////////////////////////////
FileRead_close(fp); //ファイルを閉じる
} //void MapLoad();の最後
//画像をロードする関数を作ります。
void Load(){
im.kabe01=LoadGraph("media/kabe01.bmp");
LoadDivGraph("media/teki0A.bmp",2,2,1,32,32,im.teki0A);
}
//初期化用の関数を作ります。
void Init(){
//キャラクターをカウントする変数を作ります。必要な変数の一つです。
//キャラクターをカウントする変数はローカル変数でも問題ありませんでした。
int counter=0;
for(int y=0;y<HEIGHT;y++){
for(int x=0;x<WIDTH;x++){
char c=mapdata[y][x];
//初期化してマップデータから、キャラクターのデータを取り出します。
//kindにマップデータを代入します。
//これも必要な変数の一つです。
charadata[counter].kind=c;
charadata[counter].x=(float)x*MAPSIZE;
charadata[counter].y=(float)y*MAPSIZE;
int charaValid=0;
//この変数を利用しないと初期化関数Init();をwhile文に入れた場合に適切に描画されません。
//Validは英語で「有効、根拠の確実な、確かな、正当な」などの意味です。
//キャラクターごとに異なるものはswicth文を使います。
switch(c){ //なお、ここにcounterを入れてしまうと、フリーズしてしまいました。
case '11':
charadata[counter].body=1;
charaValid=1; //case毎にcv=1;と代入します。
break;
case 'AA':
charadata[counter].anime_pattern=2; //アニメーションさせる場合はここで代入します。
charadata[counter].body=1;
charaValid=1; //
break;
}
//このif文がないと初期化関数Init();をwhile文に入れた場合に適切に描画されません。
if(charaValid){
mapdata[y][x]='0'; //マップデータを'0'にする事で、データの取り出しは終わりです。
//ここでキャラクターの数を一つずつ増やしていきます。
counter++;
}
}
}
}
//描画と移動処理用の関数を作ります
void Move(){
for(int i=0;i<CHARA;i++){
char c=charadata[i].kind;
switch(c){
//ここにcharadata[i].kindではなくiを入れると、一つしか描画されませんでした。
//また、フリーズしてまった場合もあります。
case '11':
DrawGraph(charadata[i].x,charadata[i].y,im.kabe01,TRUE);
break;
case 'AA':
int a=g_anime_counter/20%charadata[i].anime_pattern;
DrawGraph(charadata[i].x,charadata[i].y,im.teki0A[a],TRUE);
break;
}
//キャラクター単位で動かす方法でマップスクロールを行います。
charadata[i].x=charadata[i].x-1;
}
}
//WinMain関数の中に、先ほど作った関数を入れます。//Move();だけwhile内に入れます。
int WINAPI WinMain(HINSTANCE hI,HINSTANCE hP,LPSTR lpC,int nC){
if(ChangeWindowMode(TRUE)!=0) return -1; //ウィンドウモードの変更
if(DxLib_Init()!=0) return -1; //DXライブラリ初期化処理
if(SetDrawScreen(DX_SCREEN_BACK)!=0) return -1; //描画先を裏画面に設定
//ロードの関数は、ここではここに入れます。
MapLoad(); //マップデータのロード
Load(); //画像のロード
Init(); //初期化。//if(charaValid)に関するコードを書いていない時は、ここに置かないで、while文の中に置くと、適切に描画されません。
while(ProcessMessage()==0&&CheckHitKey(KEY_INPUT_ESCAPE)==0){
//メッセージ処理(XキーかAlt+F4キーが押されたら終了)
//ESCキーが押されたら終了
if(ClearDrawScreen()!=0) return -1; //裏画面を消す
//Init(); //初期化。//if(charaValid)に関するコードを書いていないでwhile文の中に初期化関数Init();置くと、適切に描画されません。
//この関数をそのままwhile文の中に入れてしまうと、一番最初の画像が消えてしまう。
Move(); //画像の描画と移動用の関数をここに置きます。
g_anime_counter++; //
if(ScreenFlip()!=0) return -1; //裏画面を表画面に反映
}
if(DxLib_End()!=0) return -1; //DXライブラリの終了処理
return 0; //ソフトの終了
}
以下はvoid MapLoad(){}の中身だけを投稿します。
次に、カンマや改行を調べて、それをヌル文字に変換する方法も試してみました。
方法2
//メモ帳からマップデータを読み込み
void MapLoad(){
//各キャラクターのデータを初期化します。
ZeroMemory(charadata,sizeof(charadata));
char buf[1024];
sprintf_s(buf,1024,"media/map%d",1); //ファイル名を用意する
int fp; //ファイルハンドル
fp==FileRead_open(buf); //ファイルを開く
//ファイル読み込みエラー処理
if(fp=NULL){
printfDx("ファイル読み込みエラー");
return;
}
/////////////////////////////ここから////////////////////////////
char c=0; //文字を読み込む
int i=0; //文字列のデータのカウント
//1024が1023に減っているのは、NULL文字対策
while(FileRead_gets(buf,1023,fp)!='\n'); //改行に来たら読み込みを辞める
for(int y=0;y<HEIGHT;y++){
for(int x=0;x<WIDTH;x++){
//1024が1023に減っているのは、NULL文字対策
c=FileRead_gets(buf,1023,fp);
buf[i]=c;
if(buf[i]==','||buf[i]=='\n'||buf[i]==EOF){
buf[i]='\0'; //ヌル文字を代入
i=-1; //カウントをリセットする。
} //if(buf[i]==','||buf[i]=='\n'||buf[i]==EOF)の最後
//いずれもフリーズしました。
//mapdata[y][x]=buf[i];
//FileRead_gets(mapdata[y],buf[i],fp);
if(c==EOF) break;
i++;
} //for(int x=0;x<WIDTH;x++)の最後
} //for(int y=0;y<HEIGHT;y++)の最後
/////////////////////////////ここまで////////////////////////////
FileRead_close(fp); //ファイルを閉じる
} //void MapLoad();の最後
方法3
//メモ帳からマップデータを読み込み
void MapLoad(){
//各キャラクターのデータを初期化します。
ZeroMemory(charadata,sizeof(charadata));
char buf[1024];
sprintf_s(buf,1024,"media/map%d",1); //ファイル名を用意する
int fp; //ファイルハンドル
fp==FileRead_open(buf); //ファイルを開く
//ファイル読み込みエラー処理
if(fp=NULL){
printfDx("ファイル読み込みエラー");
return;
}
/////////////////////////////ここから////////////////////////////
int i=0; //文字列データのカウント
for(int y=0;y<HEIGHT;y++){
//1024が1023に減っているのは、NULL文字対策
FileRead_gets(buf,1023,fp);
//for(int x=0;x<WIDTH;x++){
if(buf[i]==','||buf[i]=='\n'||buf[i]==EOF){
buf[i]='\0'; //ヌル文字を代入
i=-1; //カウントをリセットする。
} //if(buf[i]==','||buf[i]=='\n'||buf[i]==EOF)の最後
//mapdata[y][x]=buf[x];
FileRead_gets(mapdata[y],buf[i],fp);
i++;
//} //for(int x=0;x<WIDTH;x++)の最後
} //for(int y=0;y<HEIGHT;y++)の最後
/////////////////////////////ここまで////////////////////////////
FileRead_close(fp); //ファイルを閉じる
} //void MapLoad();の最後
mapdataを二次元配列から一次元配列にする方法も試しました。
//メモ帳からマップデータを読み込み
void MapLoad(){
//各キャラクターのデータを初期化します。
ZeroMemory(charadata,sizeof(charadata));
char buf[1024];
sprintf_s(buf,1024,"media/map%d",1); //ファイル名を用意する
int fp; //ファイルハンドル
fp==FileRead_open(buf); //ファイルを開く
//ファイル読み込みエラー処理
if(fp=NULL){
printfDx("ファイル読み込みエラー");
return;
}
/////////////////////////////ここから////////////////////////////
//1024が1023に減っているのは、NULL文字対策
while(FileRead_gets(buf,1023,fp)!='\n'); //改行に来たら読み込みを辞める
int x=0;
for(int y=0;y<HEIGHT;y++){
//1024が1023に減っているのはヌル文字対策
fp=FileRead_gets(buf,1023,fp);
//for(int x=0;x<WIDTH;x++){
if(buf[x]==','||buf[x]=='\n'||buf[x]==EOF){
buf[x]='\0'; //ヌル文字を代入
x=-1; //カウントをリセットする。
} //if(buf[x]==','||buf[x]=='\n'||buf[x]==EOF)の最後
mapdata[y*WIDTH+x]=buf[x];
x++;
//} //for(int x=0;x<WIDTH;x++)の最後
} //for(int y=0;y<HEIGHT;y++)の最後
/////////////////////////////ここまで////////////////////////////
FileRead_close(fp); //ファイルを閉じる
} //void MapLoad();の最後
しかし、どれも失敗してフリーズしてしまいました。
さらに、読み込んだデータをmapdataの中に変換や代入する方法も、分かりません。
お手上げです。
どのソースコードをどのように直せば、カンマ付き文字列のデータの読み込みが出来るようになるでしょうか。