リプレイをいまさら実装したのですが、
バグが発生しました。
リプレイを再生していると、
replayのカウンタがずれるというものです。
支館にあったプログラムは正常に動きます。
支館のプログラムは、key入力を記憶して
再生時にそのとおりに動かすというものです。
//この処理はたぶんバグに関係ないかと・・・
//パッドとキーボードの両方の入力をチェックする関数
void GetHitPadStateAll(){
int i,PadInput,mul=1;
PadInput = GetJoypadInputState( DX_INPUT_PAD1 );//パッドの入力状態を取得
for(i=0;i<16;i++){
if(PadInput & mul) pad.key[i]++;
else pad.key[i]=0;
mul*=2;
}
input_pad_or_key(&pad.key[configpad.left] ,CheckStateKey(KEY_INPUT_LEFT ));
input_pad_or_key(&pad.key[configpad.up] ,CheckStateKey(KEY_INPUT_UP ));
input_pad_or_key(&pad.key[configpad.right] ,CheckStateKey(KEY_INPUT_RIGHT ));
input_pad_or_key(&pad.key[configpad.down] ,CheckStateKey(KEY_INPUT_DOWN ));
input_pad_or_key(&pad.key[configpad.shot] ,CheckStateKey(KEY_INPUT_Z ));
input_pad_or_key(&pad.key[configpad.bom] ,CheckStateKey(KEY_INPUT_X ));
input_pad_or_key(&pad.key[configpad.slow] ,CheckStateKey(KEY_INPUT_LSHIFT ));
input_pad_or_key(&pad.key[configpad.change] ,CheckStateKey(KEY_INPUT_LCONTROL));
input_pad_or_key(&pad.key[configpad.start],CheckStateKey(KEY_INPUT_ESCAPE));
if (replay.flag == true && func_state == 100) {//通常のステージなら
if (replay.num == 0) {
memcpy(&replay.rec[replay.num], pad.key, sizeof(pad.key));
replay.count[replay.num] = replay_count;
replay.num++;
}
if (memcmp(&replay.rec[replay.num-1], pad.key, sizeof(pad.key)) != 0) {
if (replay.num >= REPLAY_TIME_MAX) {
printfDx("リプレイ最大保存時間を越えました。リプレイを保存する事はできません\n");
replay_free();
return;
}
memcpy(&replay.rec[replay.num], pad.key, sizeof(pad.key));
replay.rec[replay.num].key[configpad.esc]=0;//再生終了用のキーだから、入力をなかったことに
replay.count[replay.num] = replay_count;//カウンタを記憶
replay.num++;
}
}
else if (replay.flag == true && func_state == 109) {//リプレイ再生中なら
if (replay.count[replay.num] == replay_count) {
if(replay.end_count[0]>=replay_count){//まだ、再生が終わったはずのタイミングでないなら
replay.num++;
}
else{
printfDx("本来のタイムをオーバーしました");
}
}
if(CheckStatePad(configpad.esc)==1){//再生終了処理
delete_bgm();
func_state = 107; // 戻る
}
memcpy(pad.key, &replay.rec[replay.num-1], sizeof(pad.key));//先にnum++してしまってるので-1で
}
}
これだけではそのままは動いてくれないので、
こちらも全て記憶するようにしました。
そうしたら、この関数内でバグがおこるようになりました
//渡された-ang~angまでのランダムな角度を返す
double rang(double ang){
double anc;
if(func_state!=109){//リプレイ再生中でないなら
anc= -ang + ang*2 * GetRand(10000)/10000.0 ;//返り値にランダムな数字を
if(replay.flag == true && func_state==100){//リプレイ情報を保存するときなら
replay.rand_count[replay.rand_num]=replay_count;//今のカウンタを保存
replay.rand_anc[replay.rand_num]=anc;//結果を保存
}
}
else{//リプレイ再生中なら
if(replay.rand_count[replay.rand_num]==replay_count){//関数が呼び出されたタイミングが再生元と同じなら
if(replay.end_count[1]>=replay_count){//まだ、再生が終わったはずのタイミングでないなら
anc=replay.rand_anc[replay.rand_num];//返り値に前の記録のものを
}
else{
printfDx("本来のタイムをオーバーしました");
anc=0;//返り値はてきとう
}
}
else{
printfDx("タイミングが本来のリプレイと違います\n再生を中止します");
delete_bgm();//曲を消して
func_state=107;//リプレイセレクト画面へ
anc=0;//返り値はてきとう
}
}
replay.rand_num++;//番号をプラス
return (anc);
}
なぜか再生してると
ここの処理がたまにelseの処理を行います。
今のところわかっているのは、
・ボスの弾幕が始まってちょっとしてから(300~400cntぐらい?)バグが起こる
・ボスがでてこないようにするとバグは発生しない
・replay_countの値は書き換わっていない
・バグが発生した時(ブレークポイントにひっかかったとき)最後にrang()を呼び出した関数はリプレイによって違う
・無視したら、間違った値が代入されて、本来と全く違うものになる
・ファイルに書きだした値は間違っていない
・きちんと初期化はされてる
・・・ぐらいでしょうか
ただ、自分のデバッグが正しいという保証はないので↑に書いてあることは間違えている可能性もあります。
リプレイ機能をつけてからはボスの関数はいじってません。
ひょっとしたら、func_state==100(ゲームを通常にプレイしている処理)
でしか行われない処理があって、そこでrang()が呼び出されている
可能性もあります・・・
ただ検索をかけてもそれらしいものはヒットしないので
なにか違う形(func_state<101みたいなの)でおこなわれているかもしれません・・・
処理に不十分な点があれば教えて下さい。
たぶん、ボスがでなければ通常通りおこなわれるので、
↑にある処理は間違ってないかと思います。