ページ 1 / 1
現在音ゲーを製作中なのですが
Posted: 2010年11月26日(金) 15:37
by 空道
はじめまして、空道と申します。
早速ですが質問させていただきます。
現在音ゲーを作成中なのですが、曲の一覧を取得するのにてこずっています。
形式としては、StepManiaやこちらで配布されているAerobeatPlusのようにファイルを作ることで自動的にデータを読み取るものを目指しています。
今のところ、FindFirstFile系列で特定のフォルダ以下に入っているフォルダを列挙し、その中にtxtファイルがあれば開く。
txtファイルには曲情報(曲名や、BPM)などが入っており、それぞれを用意した構造体にいれていく事で一覧表示できるようにしています。
しかし、ファイル列挙→txtファイルならば特定の処理を行う、まではうまく行ったのですが、その先のファイルオープンから中身を構造体に入れることができません。
そこで質問なのですが、
一、charで宣言したファイルパスではfopenで開けないのでしょうか。
二、もし開けるのであれば、中身はfgetsで一行ごとに読み込むのがいいのでしょうか。それとも配列に一文字ずつ入れるほうがいいのでしょうか
三、この方法でいいのでしょうか。もしも他に効率の良い方法があればヒントだけでもいいので教えていただけると幸いです。
また、列挙からデータ取得まで一発で行っています。
コード:
//構造体宣言
typedef struct {
char *filepath;
char *title, *rubi;
int bpm, music_long;
int difficulty_easy, difficulty_nomale, difficulty_hard, difficulty_caos;
} NewMusicInfo;
NewMusicInfo MusicInfo[400];
//ファイル列挙
void music_folder (char *pszBasePath) {
char szSearchPath[MAX_PATH+1];
char szSubPath[MAX_PATH+1];
char szFileName[MAX_PATH+1];
int n = 0;
WIN32_FIND_DATA fd;
lstrcpy(szSearchPath, pszBasePath);
if (szSearchPath[lstrlen(szSearchPath)-1] != '*') {
lstrcat(szSearchPath, "*");
}
HANDLE hFind = FindFirstFile(szSearchPath, &fd);
do {
if (lstrcmp(fd.cFileName, "..") != 0 && lstrcmpi(fd.cFileName, ".") != 0) {
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
// ディレクトリの場合
lstrcpy(szSubPath, pszBasePath);
lstrcat(szSubPath, fd.cFileName);
lstrcat(szSubPath, "\\");
music_folder(szSubPath);
} else {
// ファイルの場合
lstrcpy(szFileName, pszBasePath);
lstrcat(szFileName, fd.cFileName);
if (stricmp(PathFindExtension(szFileName),TEXT(".txt")) == 0) { //txtファイルであれば
FILE *fp;
char fileline[256];
fp = fopen(szFileName,"r");
if (fp == NULL) { printDx( "File Open Error" ); break; }
int linenomber = 0, n = 0;
while (NULL != (fgets(fileline, 256, fp))) {
//構造体にデータを入れる処理
}
}
}
}
} while(FindNextFile(hFind, &fd));
FindClose(hFind);
return;
}
//WinMainにてmusic_folder("data/Movie/");として関数を呼び出しています。
日本語のおかしい所があるかもしれません。
もし、意味が伝わらないところがあれば遠慮なく言ってくださって結構です。
また、ファイル列挙のアルゴリズムに関しては検索時に出てきたものを使用しています。
長文、乱文失礼しました。
Re: 現在音ゲーを製作中なのですが
Posted: 2010年11月26日(金) 19:30
by softya(ソフト屋)
全コードがないので、こちらで動作確認できないのですが、ファイルパスがちゃんと加工できているかMesssageBoxやデバッガで確認されましたでしょうか?
Re: 現在音ゲーを製作中なのですが
Posted: 2010年11月26日(金) 20:58
by 空道
softya(ソフト屋) さんが書きました:全コードがないので、こちらで動作確認できないのですが、ファイルパスがちゃんと加工できているかMesssageBoxやデバッガで確認されましたでしょうか?
返信ありがとうございます。
一応、ファイル処理のエラーが起きない、ファイル名単体であれば表示されることから加工できていると勝手に思い込んでいます。
cおよびc++言語に関しては疎いので本当に出来ているかと問われると断言できないのですが……。
また、全コードとありますが関係の無い部分を含めて提示したほうが良いのでしょうか。
全コードとなると、かなり読みにくいものを晒してしまう事になりますがよろしいでしょうか。
また、ファイルパスの確認については
コード:
if (stricmp(PathFindExtension(szFileName),TEXT(".txt")) == 0) { //txtファイルであれば
FILE *fp;
char fileline[256];
fp = fopen(szFileName,"r");
if (fp == NULL) { printDx( "File Open Error" ); break; }
int linenomber = 0, n = 0;
while (NULL != (fgets(fileline, 256, fp))) {
//構造体にデータを入れる処理
}
}
上の部分を
コード:
if (stricmp(PathFindExtension(szFileName),TEXT(".txt")) == 0) { //txtファイルであれば
printDx (szFileName);
}
のようにして確認しました。
Re: 現在音ゲーを製作中なのですが
Posted: 2010年11月26日(金) 21:16
by ゆーずぃ
>ファイル処理のエラーが起きない
"File Open Error"にはならないということですか?
Re: 現在音ゲーを製作中なのですが
Posted: 2010年11月26日(金) 21:17
by ゲスト
ゆーずぃ さんが書きました:>ファイル処理のエラーが起きない
"File Open Error"にはならないということですか?
はい、そういうことです。
Re: 現在音ゲーを製作中なのですが
Posted: 2010年11月26日(金) 21:19
by 空道
ゲスト さんが書きました:ゆーずぃ さんが書きました:>ファイル処理のエラーが起きない
"File Open Error"にはならないということですか?
はい、そういうことです。
申し訳ありません。
ログインが切れていたようです。
上の記事は私のものです。
Re: 現在音ゲーを製作中なのですが
Posted: 2010年11月26日(金) 21:21
by softya(ソフト屋)
何にしても、そこの部分だけを取り出して動くプログラムを作ってちゃんとテストしてみてください。
分からなければ、そのプログラムだけ提示してもらえば良いです。
本人の思い込みってのが一番バグの原因だったりします(私自身の失敗の経験からしても)。
Re: 現在音ゲーを製作中なのですが
Posted: 2010年11月26日(金) 21:27
by ゆーずぃ
試しに
while (NULL != (fgets(fileline, 256, fp)))を
while (fgets(fileline, 256, fp) != NULL)に変えてみて下さい。
結合規則の問題で関数の実行よりも先にNULLとの比較が行われるパターンがあります。
上手くいかないときは逆にしたり判定を別にしたりすると上手くいったりします。
Re: 現在音ゲーを製作中なのですが
Posted: 2010年11月26日(金) 21:29
by bitter_fox
>>二、もし開けるのであれば、中身はfgetsで一行ごとに読み込むのがいいのでしょうか。それとも配列に一文字ずつ入れるほうがいいのでしょうか
今回の場合は、fgetsで一行ごと読む込むので良いと思います。
fscanfという関数があるにはあるのですが、根本的にこの関数はぶっ飛んだ仕様ですので、実用的ではないです。
>>三、この方法でいいのでしょうか。もしも他に効率の良い方法があればヒントだけでもいいので教えていただけると幸いです。
もし一行の文字数が255を超えていたら、一行のすべてのデータを読み込めないので動的に確保するべきです。
>>ファイルオープンから中身を構造体に入れることができません。
strtokで分割して構造体の各要素に代入するのが定石だと考えます。
Re: 現在音ゲーを製作中なのですが
Posted: 2010年11月26日(金) 21:32
by 空道
先ほど他の処理を消してデバックしたところ、きちんと動作してくれました。
原因が何なのかは分からなかったですが、ゆっくりと解析していきたいと思います。
大変お騒がせして申し訳ありませんでした。
また、さまざまな書き込みありがとうございました。
Re: 現在音ゲーを製作中なのですが
Posted: 2010年11月27日(土) 10:59
by 空道
解決したようなことを言ったのですが、また行き詰ったのでご教授お願いします。
↓data.txt
↓main.cpp
コード:
//変数宣言
int now_music_no, max_music_no;
//構造体宣言
typedef struct {
char *filepath;
char *title, *rubi;
int bpm, music_long;
int difficulty_easy, difficulty_nomale, difficulty_hard, difficulty_caos;
} NewMusicInfo;
NewMusicInfo MusicInfo[400];
//キー入力情報
int GetHitKeyStateAll_2(int GetHitKeyStateAll_InputKey[]) {
char GetHitKeyStateAll_Key[256];
GetHitKeyStateAll( GetHitKeyStateAll_Key );
for(int i=0;i<256;i++){
if(GetHitKeyStateAll_Key[i]==1) GetHitKeyStateAll_InputKey[i]++;
else GetHitKeyStateAll_InputKey[i]=0;
}
return 0;
}
//フォルダ列挙
void music_folder (char *pszBasePath) {
char szSearchPath[MAX_PATH+1];
char szSubPath[MAX_PATH+1];
char szFileName[MAX_PATH+1];
int n = 0;
WIN32_FIND_DATA fd;
lstrcpy(szSearchPath, pszBasePath);
if (szSearchPath[lstrlen(szSearchPath)-1] != '*') {
lstrcat(szSearchPath, "*");
}
HANDLE hFind = FindFirstFile(szSearchPath, &fd);
do {
if (lstrcmp(fd.cFileName, "..") != 0 && lstrcmpi(fd.cFileName, ".") != 0) {
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
// ディレクトリの場合
lstrcpy(szSubPath, pszBasePath);
lstrcat(szSubPath, fd.cFileName);
lstrcat(szSubPath, "\\");
music_folder(szSubPath);
} else {
// ファイルの場合
lstrcpy(szFileName, pszBasePath);
lstrcat(szFileName, fd.cFileName);
if (stricmp(PathFindExtension(szFileName),TEXT(".txt")) == 0) {
FILE *fp;
char fileline[256];
fp = fopen(szFileName,"r");
if (fp == NULL) { MusicInfo[0].title = "FileOpenError"; break; } //ファイル確認のためMusicInfo[0].titleにいれています。
int linenomber = 0;
while ((fgets(fileline, 256, fp)) != NULL) {
MusicInfo[n].title = fileline;
printfDx(fileline); //ファイル確認のためいれています。
n++;
}
max_music_no = n - 1;
}
}
}
} while(FindNextFile(hFind, &fd));
FindClose(hFind);
return;
}
//結果表示
void desk_graphic() {
if (Key[ KEY_INPUT_UP ] == 1) {
now_music_no -= 1;
if (now_music_no < 0) now_music_no = max_music_no;
} else if (Key[ KEY_INPUT_DOWN ] == 1) {
now_music_no += 1;
if (now_music_no > max_music_no) now_music_no = 0;
}
DrawString(100,100, "filelist" , GetColor( 255 , 255 , 255 ));
DrawString(200,100, MusicInfo[now_music_no].title, GetColor( 255 , 255 , 255 ));
DrawString(200,130, MusicInfo[1].title, GetColor( 255 , 255 , 255 )); //確認用
DrawString(200,70, MusicInfo[2].title, GetColor( 255 , 255 , 255 )); //確認用
}
//メイン処理
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
ChangeWindowMode(TRUE);//ウィンドウモード
if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化
PlayMovieToGraph( MovieGraphHandle ) ;
while(ProcessMessage()==0 && ClearDrawScreen()==0 && GetHitKeyStateAll_2(Key)==0 && Key[KEY_INPUT_ESCAPE]==0){
music_folder("data/Movie/");
desk_graphic();
ScreenFlip();
}
DxLib_End();
return 0;
}
現在このようなコードにしています。
しかしながら、こうするとMusicInfo[n].titleの中身がすべて同一のものになっています。(現在の例で行くとMusicInfo[n].titleがすべてsampleに)
私としては、MusicInfo[0].titleに"サンプル"が、MusicInfo[1].titleに"さんぷる"、MusicInfo[2].titleに"sample"が入ってほしいのですが……。
そこで質問なのですが、
一、このコードの何がまずいのか。(ヒントだけでも結構です)
二、下記のコードにすると構造体の中身が空になる理由。
を教えていただけると幸いです。
コード:
//一番上に追加
int mode_select = 0;
//メイン処理
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
ChangeWindowMode(TRUE);//ウィンドウモード
if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化
PlayMovieToGraph( MovieGraphHandle ) ;
while(ProcessMessage()==0 && ClearDrawScreen()==0 && GetHitKeyStateAll_2(Key)==0 && Key[KEY_INPUT_ESCAPE]==0){
switch(mode_select) {
case 0:
music_folder("data/Movie/");
mode_select = 30;
break;
case 30:
desk_graphic();
break;
}
ScreenFlip();
}
DxLib_End();
return 0;
}
Re: 現在音ゲーを製作中なのですが
Posted: 2010年11月27日(土) 14:36
by bitter_fox
空道 さんが書きました:
コード:
char fileline[256];
fp = fopen(szFileName,"r");
if (fp == NULL) { MusicInfo[0].title = "FileOpenError"; break; } //ファイル確認のためMusicInfo[0].titleにいれています。
int linenomber = 0;
while ((fgets(fileline, 256, fp)) != NULL) {
MusicInfo[n].title = fileline;
printfDx(fileline); //ファイル確認のためいれています。
n++;
}
一、このコードの何がまずいのか。(ヒントだけでも結構です)
fileline のアドレスを仮に 0x008000とすると。
まず、fgets関数で0x008000には、「サンプル」が代入されます。
MusicInfo[0].title = fileline はMusicInfo[0]のtitleというポインタに filelineのアドレスを代入するという意味なので、MusicInfo[0].title の値は 0x008000になり、その参照先の値は、「サンプル」になります。
次に、fgets関数で0x008000に、「さんぷる」が代入され、
MusicInfo[1]のtitle というポインタにfilelineのアドレスを代入して値が 0x008000になり、その参照先の値は、「さんぷる」なり、MusicInfo[0]のtitleの値も0x008000なので、参照先の値は、「さんぷる」になります。
最後に、もう一度fgets関数で0x008000に、「sample」が代入され、
MusicInfo[2]のtitleというポインタにfilelineのアドレスを代入して値が0x008000になり、その参照先の値は、「sample」になり、MusicInfo[0]及びMusicInfo[1]のtitleの値も0x008000で、参照先の値も同様に「sample」になってしまいます。
Re: 現在音ゲーを製作中なのですが
Posted: 2010年11月27日(土) 14:41
by softya(ソフト屋)
組み合わせてもコンパイルが通らないです。
解析するのも大変のなので、動くプログラムを提示してもらえいでしょうか?
あとデバッガでトレースしましたか?
これをするだけで大半のバグは取れます。
Re: 現在音ゲーを製作中なのですが
Posted: 2010年11月27日(土) 16:36
by 空道
fileline のアドレスを仮に 0x008000とすると。
まず、fgets関数で0x008000には、「サンプル」が代入されます。
MusicInfo[0].title = fileline はMusicInfo[0]のtitleというポインタに filelineのアドレスを代入するという意味なので、MusicInfo[0].title の値は 0x008000になり、その参照先の値は、「サンプル」になります。
次に、fgets関数で0x008000に、「さんぷる」が代入され、
MusicInfo[1]のtitle というポインタにfilelineのアドレスを代入して値が 0x008000になり、その参照先の値は、「さんぷる」なり、MusicInfo[0]のtitleの値も0x008000なので、参照先の値は、「さんぷる」になります。
最後に、もう一度fgets関数で0x008000に、「sample」が代入され、
MusicInfo[2]のtitleというポインタにfilelineのアドレスを代入して値が0x008000になり、その参照先の値は、「sample」になり、MusicInfo[0]及びMusicInfo[1]のtitleの値も0x008000で、参照先の値も同様に「sample」になってしまいます。
何とか別々に表示することが出来ました。
ご教授ありがとうございます。