リプレイ再生によるバグ

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
てんむすキツネ
記事: 88
登録日時: 8年前
住所: 岡山

リプレイ再生によるバグ

#1

投稿記事 by てんむすキツネ » 7年前

また、支館にありました
リプレイをいまさら実装したのですが、
バグが発生しました。

リプレイを再生していると、
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);
}
バグがおこって、おかしくなるのは

コード:

if(replay.rand_count[replay.rand_num]==replay_count){//関数が呼び出されたタイミングが再生元と同じなら
の部分です。

なぜか再生してると
ここの処理がたまにelseの処理を行います。

今のところわかっているのは、

・ボスの弾幕が始まってちょっとしてから(300~400cntぐらい?)バグが起こる

・ボスがでてこないようにするとバグは発生しない

・replay_countの値は書き換わっていない

・バグが発生した時(ブレークポイントにひっかかったとき)最後にrang()を呼び出した関数はリプレイによって違う

・無視したら、間違った値が代入されて、本来と全く違うものになる

・ファイルに書きだした値は間違っていない

・きちんと初期化はされてる

・・・ぐらいでしょうか

ただ、自分のデバッグが正しいという保証はないので↑に書いてあることは間違えている可能性もあります。

リプレイ機能をつけてからはボスの関数はいじってません。



ひょっとしたら、func_state==100(ゲームを通常にプレイしている処理)
でしか行われない処理があって、そこでrang()が呼び出されている
可能性もあります・・・

ただ検索をかけてもそれらしいものはヒットしないので
なにか違う形(func_state<101みたいなの)でおこなわれているかもしれません・・・

処理に不十分な点があれば教えて下さい。
たぶん、ボスがでなければ通常通りおこなわれるので、
↑にある処理は間違ってないかと思います。
MLP!MLP!

サウス2

Re: リプレイ再生によるバグ

#2

投稿記事 by サウス2 » 7年前

replay_countが書き変わっていないというのはおかしいです。

replay_count++かreplay_count+=1している処理があるとおもうので、動いているか確認してみては?


余談ですが、ランダム値は初期化値を設定して毎回同じ値を返すランダム関数があるので、調べてみるのもいいと思います。基本的にはこちらを用いた手法が一般的だと思います。

アバター
てんむすキツネ
記事: 88
登録日時: 8年前
住所: 岡山

Re: リプレイ再生によるバグ

#3

投稿記事 by てんむすキツネ » 7年前

初期化するランダムのやつは
rand()・・・ですよね?

とりあえずそれにのりかえました。

しかし、やっぱり呼び出されるタイミングが違います。
エラー等ははかれませんが、
やはりずれるようで
あたってないはずの弾に被弾してしまいます。

そのほかのところはそのとおりに再生されているので(ボス以外)

やっぱりreplay_countが違うのでしょうか・・・
でも、今回のはreplay_countに関係せずに
呼び出されたらランダムな値を返しているので

ひょっとしたらrang()が呼び出されるタイミングが違うのかと思います。
MLP!MLP!

閉鎖

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