現在Dxライブラリでゲーム開発させていただいています。
僕のような知識の乏しい者でもゲーム開発が出来、大変助かっています。
今回プログラムで、僕の手に終えなさそうな挙動が出ましたので質問させていただきます。
挙動は以下です。
特定の条件で、
LoadSoundMem
↓
SetLoopPosSoundMem
↓
ChangeVolumeSoundMem
↓
PlaySoundMem
という操作をおこなった場合、
ChangeVolumeSoundMem以下がエラーを返し、
(SetLoopPosSoundMemまでは、エラーでない。確認済)
音楽が再生されないという状況が発生しました。
(僕の環境のみかもしれませんが)
確認用に、この「特定状況」を再現したプログラムを組んできましたので、
以下に公開いたします。
//******************************************************************
/*
参考サイト、C言語ゲームプログラミングの館さん。
*/
#include "DxLib.h"
//システムデータ*********************************************************************************************
char Key[256];//キーボードの入力状態を入れる配列。
int fdmu=0,btmu=0;//音楽のハンドル。
int fdmu_loop=0,btmu_loop=0;//ループ指定の戻り値格納変数。
int fdmu_blm=0,btmu_blm=0;//音量変更関数戻り値用変数。
int bgm_vol=5;//音量、十段階。
int no=1;//出力状態に振る番号。
//入力キーを押しっぱなしにしても、大丈夫にする関数。
//入力キー状態とフラグを渡す。フラグを返す。(フラグがそのままキーの入力状態になる)
//flag=0入力可能押されていない、flag=1入力された、flag=2キー押しっぱなし、入力されていない。
int botan(int key,int flag){
if(key==1&&flag==0){//キーが押されていて、キーが押し続けられていないなら。
flag=1;//入力されている。
}
else if(key==1)//キーが押され続けていたら。
flag=2;//フラグをあさってに折る。
else if(key==0)//キーが離されたら
flag=0;//入力可能。
return flag;
}
//音楽をメモリに格納する関数。
void refd_mu(){
//音を止める。
StopSoundMem( fdmu ) ;
StopSoundMem( btmu ) ;
DeleteSoundMem( fdmu ) ;//二重に読み込んでしまわないように消しておく。
DeleteSoundMem( btmu ) ;
switch(no){
case 1:
fdmu = LoadSoundMem( "mad\\fdmu01.ogg" ) ;//音楽を読み込む。
fdmu_loop=SetLoopPosSoundMem( 73916, fdmu );//音楽ループ位置指定。
btmu = LoadSoundMem( "mad\\btmu01.ogg" ) ;//音楽を読み込む。
btmu_loop=SetLoopPosSoundMem( 1637 , btmu );//音楽ループ位置指定。
break;
case 2:
fdmu = LoadSoundMem( "mad\\mtmu01.ogg" ) ;//フィールド音楽を読み込む。fdmuをハンドルとする。
fdmu_loop=SetLoopPosSoundMem( 9704 , fdmu ) ;//音楽ループ位置指定。
break;
}
fdmu_blm=ChangeVolumeSoundMem( 255*bgm_vol/10 , fdmu ) ;//音量設定。
btmu_blm=ChangeVolumeSoundMem( 255*bgm_vol/10 , btmu ) ;//音量設定。
return;
}
//フィールド用ループ関数。
void field(int *bt_flag){
int B1_Flag=0,B2_Flag=0,B3_Flag=0;//ボタン変数。
int fdmu_play=0,btmu_play=0;//再生関数戻り値用変数。
int White = GetColor( 255 , 255 , 255 );//色宣言。
int stepon=0;//使わない音だが、バグの発生条件で必要。
stepon = LoadSoundMem( "mad\\step01.ogg" ) ;//バグの発生条件、音を読み込む。
if(*bt_flag==0){//初回のみ。
refd_mu();//音楽読み込み。
ChangeVolumeSoundMem( 255*bgm_vol/10 , fdmu ) ;//音量変更。
fdmu_play=PlaySoundMem( fdmu , DX_PLAYTYPE_LOOP ) ;//フィールド音ループ再生。
}
*bt_flag=0;//0にしておく。
while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]){
//↑メッセージ処理 ↑画面をクリア ↑キーボード入力状態取得 ↑ESCが押されると終了
//ボタン入力判別。
B1_Flag=botan(Key[ KEY_INPUT_A ],B1_Flag);//1番ボタン連続入力防止。
B2_Flag=botan(Key[ KEY_INPUT_S ],B2_Flag);//2番ボタン連続入力防止。
B3_Flag=botan(Key[ KEY_INPUT_D ],B3_Flag);//3番ボタン連続入力防止。
if(B1_Flag==1){//Aが押されたら、メモリに読み込んでいる音楽を書き換える。
if(no==1){//no1の場合、2に書き換えて出力。
no=2;
refd_mu();
fdmu_play=PlaySoundMem( fdmu , DX_PLAYTYPE_LOOP ) ;//音ループ再生開始。
}
else if(no==2){//no2の場合、1に書き換えて出力。
no=1;
refd_mu();
fdmu_play=PlaySoundMem( fdmu , DX_PLAYTYPE_LOOP ) ;//音ループ再生開始。
}
}
else if(B2_Flag==1){//S入力で音楽切り替え。
if(CheckSoundMem( fdmu ) ==1){//fdmu音楽流れているなら
StopSoundMem( fdmu ) ;//音楽を止め
btmu_play=PlaySoundMem( btmu , DX_PLAYTYPE_LOOP ) ;//別の音楽再生。
}
else if(CheckSoundMem( btmu ) ==1){//btmu音楽流れているなら
StopSoundMem( btmu ) ;//音楽を止め
fdmu_play=PlaySoundMem( fdmu , DX_PLAYTYPE_LOOP ) ;//別の音楽再生。
}
else{//それ以外なら、
StopSoundMem( fdmu ) ;//とりあえず、両方止めて
StopSoundMem( btmu ) ;//
fdmu_play=PlaySoundMem( fdmu , DX_PLAYTYPE_LOOP ) ;//両方再生。
btmu_play=PlaySoundMem( btmu , DX_PLAYTYPE_LOOP ) ;//
}
}
else if(B3_Flag==1){//D入力で
DeleteSoundMem( stepon ) ;//読んだ音を削除。
*bt_flag=1;
break;//ループを抜ける。
}
DrawFormatString( 0 , 0 , White , "fdmu音楽ハンドル %d" , fdmu) ;
DrawFormatString( 0 , 20 , White , "fdmuループ箇所指定関数戻り値 %d" , fdmu_loop) ;
DrawFormatString( 0 , 40 , White , "fdmuボリューム変更関数戻り値 %d" , fdmu_blm) ;
DrawFormatString( 0 , 60 , White , "fdmu再生関数戻り値 %d" , fdmu_play) ;
DrawFormatString( 0 , 80 , White , "fdmu再生状態 %d" , CheckSoundMem( fdmu )) ;
DrawFormatString( 0 ,120 , White , "btmu音楽ハンドル %d" , btmu) ;
DrawFormatString( 0 ,140 , White , "btmuループ箇所指定関数戻り値 %d" , btmu_loop) ;
DrawFormatString( 0 ,160 , White , "btmuボリューム変更関数戻り値 %d" , btmu_blm) ;
DrawFormatString( 0 ,180 , White , "btmu再生関数戻り値 %d" , btmu_play) ;
DrawFormatString( 0 ,200 , White , "btmu再生状態 %d" , CheckSoundMem( btmu )) ;
DrawFormatString( 0 ,240 , White , "no(メモリ内音楽番号) %d" , no) ;
DrawString( 0 , 280 , "Aキーでメモリ内音楽変更" , White );
DrawString( 0 , 300 , "Sキーで再生音楽変更" , White );
DrawString( 0 , 320 , "Dキーでブレーク(バグ発生)" , White );
DrawString( 0 , 360 , "音楽提供 煉獄庭園" , White );
ScreenFlip();//裏画面の画像を表に出力。
}
return;
}
//メイン関数
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
SetOutApplicationLogValidFlag(FALSE) ;//ログ出力を行うか否か(TRUE:行う FALSE:行わない)
int bt_flag=0;
if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //ウィンドウ化と初期化処理
SetDrawScreen( DX_SCREEN_BACK ) ; //描画先を裏画面に設定
while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]){
//↑メッセージ処理 ↑画面をクリア ↑キーボード入力状態取得 ↑ESCが押されると終了
field(&bt_flag);//フィールド用ループ関数。戦闘フラグのポインタを渡す。フィールド処理関数。
}
DxLib_End();//ゲーム終了。
return 0;
}
//******************************************************************
以上です。
一応実行ファイルも、製作してきましたのでアップロードさせていただきます。
http://www1.axfc.net/uploader/Ne/so/51391
上記のプログラムは、各々の変数の状態を出力しつつ
Aキーでメモリ内の音楽を書き換え(no=1,no=2の2パターン)
Sキーで再生する音楽を変更する(ハンドルfdmu,btmuの二種類)プログラムです。
AキーとSキーのみで操作する場合は、正常に動作します。
(出力している変数、noが2の時btmuにエラーが出ますが
これはこの変数に音楽を読み込んでいないからなので無視してください)
ですが、Dキーを入力し(長押ししてください)『ループをブレーク』すると
最初に説明しました挙動が発生します。
具体的には、no=2の状態でAキーを押し、fdmuとbtmuを再読み込みすると、
正常に機能していたはずのno=1状態でのfdmuが再生されなくなります。
(btmuは、正常に機能します)
この挙動は、
field関数の
stepon = LoadSoundMem( "mad\\step01.ogg" ) ;
または、refd_mu関数の
fdmu_loop=SetLoopPosSoundMem( 73916, fdmu );
btmu_loop=SetLoopPosSoundMem( 1637 , btmu );
または、refd_mu関数の
btmu = LoadSoundMem( "mad\\btmu01.ogg" ) ;
btmu_loop=SetLoopPosSoundMem( 1637 , btmu );
のいずれかをコメント文にし、外すことで発生しなくなります。
(逆に言えば上記が、この挙動の発生条件)
ですが、僕の目指すプログラムではこれらは外すことが出来ません。
なんとかこの挙動の発生条件までは、突き止めたのですが
これ以上どうすることも出来ず、質問に上がったしだいです。
お手数ですが、なにとぞご教授ください。