リプレイ保存の方法

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
匿名

リプレイ保存の方法

#1

投稿記事 by 匿名 » 16年前

リプレイを保存する処理を作っているんですが
皆さんはどんな方法で保存しているんでしょうか?
参考にしたいので教えてください。

ちなみに私が使っている方法は
i=0;

if( Key[KEY_INPUT_Z]>0        )i+= 1;

if( Key[KEY_INPUT_X]>0        )i+= 2;

if( Key[KEY_INPUT_LSHIFT]>0   )i+= 4;

if( Key[KEY_INPUT_LCONTRO[/url]>0 )i+= 8;

if( Key[KEY_INPUT_UP]>0       )i+=16;

if( Key[KEY_INPUT_RIGHT]>0    )i+=32;

if( Key[KEY_INPUT_DOWN]>0     )i+=64;

if( Key[KEY_INPUT_LEFT]>0     )i+=128;

fputc(i,REPLAY_fp);
で保存して
i=fgetc(fp);

Key[KEY_INPUT_Z]=i%2;

i-=i%2;

i-=i/2;

Key[KEY_INPUT_X]=i%2;

i-=i%2;

i-=i/2;

Key[KEY_INPUT_LSHIFT]=i%2;

i-=i%2;

i-=i/2;

Key[KEY_INPUT_LCONTRO[/url]=i%2;

i-=i%2;

i-=i/2;

Key[KEY_INPUT_UP]=i%2;

i-=i%2;

i-=i/2;

Key[KEY_INPUT_RIGHT]=i%2;

i-=i%2;

i-=i/2;

Key[KEY_INPUT_DOWN]=i%2;

i-=i%2;

i-=i/2;

Key[KEY_INPUT_LEFT]=i%2;
で読み込んでいます

8個のボタンが押されているかを
2進数の各ビットの状態に置き換えて保存しています。
この方法を使っている理由はボタンごとに保存するより
1バイトにまとめた方が容量が8分の1になるからです。

本当の理由は他のファイル操作系関数がまだ使えないからなんですが・・

SooA

Re:リプレイ保存の方法

#2

投稿記事 by SooA » 16年前

入力用のカウントを回して、
各キーに変化があった場合にのみ
その変化とカウント値を記録していく
方法もあります。

例)
カウント/キーの変化
1020 Left_Down
1030 X_Down
1052 X_Up
1100 Left_Up

匿名

Re:リプレイ保存の方法

#3

投稿記事 by 匿名 » 16年前

なるほど~

Justy

Re:リプレイ保存の方法

#4

投稿記事 by Justy » 16年前

過去ログでも似たような話題をしていたことがあります。

C言語何でも質問掲示板
ttp://www.play21.jp/board/formz.cgi?action=res&resno=22359&page=&lognum=70&id=dixq&rln=22441

匿名

Re:リプレイ保存の方法

#5

投稿記事 by 匿名 » 16年前

かなり参考になりました。
でもわからない所が二つあったので質問します。

まず

if(leftが押されている) keydat |= (1 << 0); と if(keydata & (1 << 0))

なんですが、ジョイパッドの関数とかでも使われてたと思いますけど、ちょっと意味がわからないんですよね。
見た感じ、指定したビットを立てたり、指定したビットが立っているかを調べる式みたいですが
どうなんでしょうか?
上で書いた式だと無駄が多すぎるので、こんな風にできれば便利なんですが・・

もう一つは

キーの入力状態の変化を保存する

という所ですが、キーが何フレーム目で変化したかはどうやって調べるんですか?

Justy

Re:リプレイ保存の方法

#6

投稿記事 by Justy » 16年前


>指定したビットを立てたり、指定したビットが立っているかを調べる式みたいですが
>どうなんでしょうか

 そうです。
 指定したビットと | することでそのビットを立てられますし、
立っているかどうかはそのビットと & すれば調べることができます。

 詳しくは「ビット演算」で検索をかけてみてください。
 いろんなサイトでわかりやすく説明していますので。



>キーが何フレーム目で変化したかはどうやって調べるんですか?

 1フレーム前の押下情報を覚えておきます(どのみち押した瞬間を検知するために
記録しているかと思いますが)。

 で、前のフレームと比較して、押下情報が変化していなければカウンタをインクリメントし、
変化していたらそのカウンタから同じ押下情報だったフレーム数がわかります。

 たとえば押されていたキーが
[color=sans-serif]
1 frame 上
2 frame 上
3 frame 上
4 frame 下[/color]


だった場合、1フレーム目は最初なので「上」を記録してカウンタ1としておきます。

 2フレーム目は直前のフレームである1フレーム目と比較し、同じなのでカウンタを+1して、2とします。
 3フレーム目は同様に2フレーム目と比較し、やはり同じなのでカウンタを+1して、3とします。

 4フレーム目は3フレーム目と比較すると、「上」から「下」に変化しています。
 ここでカウンタ値である3が何フレーム目で変化したのかを表している、ということになります
 
(カウンタは1に初期化して次のフレームでも同様の処理を行えば続けて同じだったフレーム数を
調べられます)。

匿名

Re:リプレイ保存の方法

#7

投稿記事 by 匿名 » 16年前

調べてみて大体理解したんですが
(1 << 0))はこの場合1ビット目を
指定しているんですか?
つまり00000001を左に0個シフトしてるの・・かな
1は変数じゃないけど同じように使えるんですか?

あとリプレイですが、ちょっとピンとこないんですけど
一番上のSooAさんのやり方みたいな感じですか?

Justy

Re:リプレイ保存の方法

#8

投稿記事 by Justy » 16年前


>つまり00000001を左に0個シフトしてる

y



>1は変数じゃないけど同じように使えるんですか?

 使えます。試してみてください。



>一番上のSooAさんのやり方みたいな感じですか?

 似ていますが、ちょっとだけ違いますね。
 分かりやすくいえば、そのキーの組み合わせで何フレーム押されていたのか(※)を
記録しますので、押されたキーの組み合わせが変化するたびにカウンタは初期化されます。


※ 実際には「そのキーの組み合わせで何フレーム押されいたのか-1」を記録した方が
効率はいいですね。気にならなければどちらでもいいのですが。

匿名

Re:リプレイ保存の方法

#9

投稿記事 by 匿名 » 16年前

わかりました、ちょっとコードを作ってみます。

リプレイですが、つまり押されているボタンの組み合わせが何フレーム維持されたかを記録するって事ですか?

Justy

Re:リプレイ保存の方法

#10

投稿記事 by Justy » 16年前


>何フレーム維持されたかを記録するって事ですか

 そうです。

匿名

Re:リプレイ保存の方法

#11

投稿記事 by 匿名 » 16年前

少しコードを作ってみました
int KEY[8]={KEY_INPUT_Z,KEY_INPUT_X,KEY_INPUT_LSHIFT,KEY_INPUT_LCONTROL,KEY_INPUT_UP,KEY_INPUT_RIGHT,KEY_INPUT_DOWN,KEY_INPUT_LEFT};

i=0;

for(j=0;j<8;j++)if( Key[ KEY[j] ]>0 )i|=(j << 0);

fputc(i,REPLAY_fp);



i=fgetc(fp);

for(j=0;j<8;j++)Key[ KEY[j] ]=i&(j << 0);
掲示板上でパッと作ったコードなのでちゃんと動くかはわかりませんが
かなり短くなった気がします。
でも保存するときの変数宣言と、その後のi=0;が無駄に見えますね。
何とか省略できないかな・・
あとビットを倒す場合はどうすればいいんでしょうか?

匿名

Re:リプレイ保存の方法

#12

投稿記事 by 匿名 » 16年前

すみません間違えてました・・
int KEY[8]={KEY_INPUT_Z,KEY_INPUT_X,KEY_INPUT_LSHIFT,KEY_INPUT_LCONTROL,KEY_INPUT_UP,KEY_INPUT_RIGHT,KEY_INPUT_DOWN,KEY_INPUT_LEFT};


i=0;

for(j=0;j<8;j++)if( Key[ KEY[j] ]>0 )i|=(1 << j);

fputc(i,REPLAY_fp);


i=fgetc(REPLAY_fp);

for(j=0;j<8;j++)(i&(1 << j)) ? Key[ KEY[j] ]>=1 : Key[ KEY[j] ]>=0 ;
多分これであってると思います
やっぱり最初の変数宣言が長いですね
なんとか短くならないかな・・
次は・・何フレーム維持されたかを記録する機能と組み合わせてみよう・・かな
あと、ビットを倒すにはどうすればいいんでしょうか?

>>STGとかですと、ボスの出現前に
小康状態になって裏でロードをしそれが終わり次第ボス出現、となるようなケースです。

と書いてあったんですが、ロードしている間は関数から処理が出てきませんから
どのくらい時間がかかったかは関係ないような気がするんですが・・

Justy

Re:リプレイ保存の方法

#13

投稿記事 by Justy » 16年前


>多分これであってると思います

 うーん、fputcの引数はたしかに intですが、int型の数値をそのまま書き出せる
わけじゃないので、うまく動かないかと。

 fgetcも然り。



>(i&(1 << j)) ? Key[ KEY[j] ]>=1 : Key[ KEY[j] ]>=0

 変数 iが正しく押下情報を読み出せた正しい値と仮定して、
?の前のビットが立っているかどうかのチェックはいいのですが、
その後の処理が意味不明になっています。

 ビットが立っていれば、 Key[ KEY[j] ]が 1以上か比較し、
そうでなければ Key[ KEY[j] ]が 0以上であることを比較して
終了してしまっています・・・・・・。

Justy

Re:リプレイ保存の方法

#14

投稿記事 by Justy » 16年前


>と書いてあったんですが、ロードしている間は関数から処理が出てきませんから
>どのくらい時間がかかったかは関係ないような気がするんですが・・

 そういう完了復帰型(読み込み終わるまで処理が停止する)の読み込み方法もありますが、
即時復帰型(読み込みのリクエストを出したら処理がすぐに戻ってきて、
別途処理が終わったかどうか調べてから使う)タイプの読み込み方法もあります。

 この方法を使うとゲーム中であっても、大きなファイルを読み込んでも
処理を止めずに読むことができます。

 某ゲームで、ロード中に別のゲームが遊べるのもこの方法を使っているからです。

 ただ、その場合、読み込みがいつ(何フレームで)終わるかはある程度は予測できますが、
正確な時間は環境次第となりますので、押下情報だけではリプレイすることは
難しくなりますね。

匿名

Re:リプレイ保存の方法

#15

投稿記事 by 匿名 » 16年前

すみません見落としていました
とりあえず結果だけ見るなら
こんな感じですかね。
#include "DxLib.h"

int Key[256];

int GetHitKeyStateAll_2(int GetHitKeyStateAll_InputKey[/url]){
    char GetHitKeyStateAll_Key[256];
    GetHitKeyStateAll( GetHitKeyStateAll_Key );
    for(int i=0;i<256;i++){
        if(GetHitKeyStateAll_Key==1) GetHitKeyStateAll_InputKey++;
        else                            GetHitKeyStateAll_InputKey=0;
    }
    return 0;
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
ChangeWindowMode(TRUE);SetOutApplicationLogValidFlag( FALSE );
if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化

FILE *REPLAY_fp;

int i,j;

int KEY[8]={KEY_INPUT_Z,KEY_INPUT_X,KEY_INPUT_LSHIFT,KEY_INPUT_LCONTROL,KEY_INPUT_UP,KEY_INPUT_RIGHT,KEY_INPUT_DOWN,KEY_INPUT_LEFT};

Key[KEY_INPUT_Z]=1;
Key[KEY_INPUT_X]=0;
Key[KEY_INPUT_LSHIFT]=1;
Key[KEY_INPUT_LCONTRO[/url]=0;
Key[KEY_INPUT_UP]=1;
Key[KEY_INPUT_RIGHT]=0;
Key[KEY_INPUT_DOWN]=1;
Key[KEY_INPUT_LEFT]=0;



DrawFormatString( 0 , 0 , GetColor(255,255,255) , "%d %d %d %d %d %d %d %d" , Key[KEY[0]] , Key[KEY[1]] , Key[KEY[2]] , Key[KEY[3]] , Key[KEY[4]] , Key[KEY[5]] , Key[KEY[6]] , Key[KEY[7]] );

REPLAY_fp = fopen("REPLAY.txt", "w");

i=0;

for(j=0;j<8;j++)if( Key[ KEY[j] ]>0 )i|=(1 << j);

fputc(i,REPLAY_fp);

fclose(REPLAY_fp);



REPLAY_fp = fopen("REPLAY.txt", "r");

i=fgetc(REPLAY_fp);

for(j=0;j<8;j++)(i&(1 << j)) ? Key[ KEY[j] ]=1 : Key[ KEY[j] ]=0 ;

fclose(REPLAY_fp);

DrawFormatString( 0 , 16 , GetColor(255,255,255) , "%d %d %d %d %d %d %d %d" , Key[KEY[0]] , Key[KEY[1]] , Key[KEY[2]] , Key[KEY[3]] , Key[KEY[4]] , Key[KEY[5]] , Key[KEY[6]] , Key[KEY[7]] );



ScreenFlip();

WaitKey();

DxLib_End();
return 0;

}
あとDXライブラリに即時復帰型の関数はありますか?

Justy

Re:リプレイ保存の方法

#16

投稿記事 by Justy » 16年前


>fputcの引数はたしかに intですが、int型の数値をそのまま書き出せる
わけじゃないので、うまく動かないかと

 すみません、ちょっと見落としてました。
 値は 0xffを越えないので fputc/fgetcでも問題なさそうですね。



>あとDXライブラリに即時復帰型の関数はありますか?

 残念ながら、無いようです。
 でも強いて挙げるなら、自前で WinAPIを使ってスレッド(*)を立てて、
ファイルをメモリに読み込んでから、~FromMem()系の関数を使ってライブラリに登録する
という手はあります。

* ttp://www.google.com/search?hl=ja&lr=lang_ja&ie=UTF-8&oe=UTF-8&q=WinAPI+%E3%82%B9%E3%83%AC%E3%83%83%E3%83%89&num=50

匿名

Re:リプレイ保存の方法

#17

投稿記事 by 匿名 » 16年前

う~ん、ちょっと今の実力じゃ無理そうですね・・

あと、ビットを倒すにはどうしたらいいでしょうか?

チルチル

Re:リプレイ保存の方法

#18

投稿記事 by チルチル » 16年前

匿名からチルチルに改名しました

実際にやってみたんですが
ステージ最初とボス出現時に処理が止まるんですよね・・

最終手段としてはSetCreateSoundDataType関数がありますが
あまり使いたくないですね。

龍神録でも同じ事をやっているみたいですが
何で処理が止まらないんだろう?

Dixq (管理人)

Re:リプレイ保存の方法

#19

投稿記事 by Dixq (管理人) » 16年前

あ、その関数ご存知だったんですね。
何故使いたくないのでしょう?

チルチル

Re:リプレイ保存の方法

#20

投稿記事 by チルチル » 16年前

SetCreateSoundDataType関数を使うと
ProcessMessage関数の呼び出し間隔を0.2秒以上空けた場合
再生中の音が途切れるって書いてあるんですよ

最近のPCなら普通にプレイしていれば0.2秒も空かないと思いますが
古いPCでプレイすることもあるかもしれませんし
私自身あまり弾幕シューティングがうまくないので
初心者の人のためにゲームの進行スピードをFPSの値が60,30,15,1ぐらいの単位で
変えられる機能を付けてみようかなと思っているんですが

これを実装した場合0.2秒以上空いてしまうので使えないんですよね。
まあ、この機能を付けると決めたわけではないし
Sleep関数を何回かにわけて間にProcessMessage関数を入れれば問題ないと思いますが
ちょっとうまくやる自信が無くて一歩が踏み出せないんです。

それにSetCreateSoundDataType関数を使っても少しは止まるかもしれないし
その少しがプレイヤーにもわかる長さだったら、あまり意味がなくなってしまうんですよね。

Justy

Re:リプレイ保存の方法

#21

投稿記事 by Justy » 16年前


>あと、ビットを倒すにはどうしたらいいでしょうか?

 倒したいビットの値を ~で反転し、&すれば倒れます。

ビット操作
ttp://www.hiramine.com/programming/c_cpp/bitoperation.html




>進行スピードをFPSの値が60,30,15,1ぐらいの単位で
>変えられる機能を付けてみようかな

 低スペックマシン向けなら話はわかりますが、初心者向けのそういう機能を用意するなら
フレームを落とすのではなくスローモーション・・・移動速度を落とした方がいいです。

 そうしないと、カクついているように見えるだけでなくユーザーの入力に対する
レスポンスも悪くなりゲームとしてかなり微妙なものになってしまいます。

チルチル

Re:リプレイ保存の方法

#22

投稿記事 by チルチル » 16年前

確かにスローモーションの方がレスポンスが高くなると思いますが
ちょっと難しい気がしますね・・
毎フレームのショットのスピードから背景のスクロールまで遅くするのは
かなり広範囲を変更しないといけませんし
あと、カウンタの増える速度も遅くしないといけませんし・・
何かフレームを落とす以外で一括して遅くする方法はありませんか?

Justy

Re:リプレイ保存の方法

#23

投稿記事 by Justy » 16年前


>何かフレームを落とす以外で一括して遅くする方法はありませんか?

 現状をどう作っているのかにもよりますが、広範囲の修正はどうしても必要になって
しまう気がします。

 一番オーソドックスなのは、各種カウンタを整数から浮動小数点に変更して、
メインシステムの方で毎フレームどれだけ(ゲーム内の仮想)時間が進んだのか
(1秒を 1.0か 60.0とするのが分かりやすいでしょうか)を計算して、
その値を各種カウンタに加算する、というものです。

 スローにしたい場合はシステムの方で進んだ時間を調整すれば、
ゲーム全体を早くしたり遅くしたりできます。

(敵システムの方でそれとは別にスピード係数を持たせて敵のカウンタに
メインシステムの時間×敵のスピード係数をした値を足せば、
メインのスピードに合わせつつ、敵だけさらに遅くしたり速くしたりすることもできます。)


 あるいは浮動小数点でなく整数のままでも、毎フレーム +1でなく +100を基本とし、
これをシステムで管理して、適宜 +50とか +20にしてもいいですね。


 1点問題があるとすれば、何かしらのイベントなどの管理で整数カウンタを ==で
比較していることがあると思いますが、この方法ではそれは使えなくなります
(値が一致せず、飛び越えてしまうことがある)のでそのあたりは修正が必要になります。



 マシンパワーに余裕があるなら、もう1つ簡単な手があります。
 通常ゲームを作るときは更新処理(Update)と描画処理(Draw)を分けていると思いますが、
それを利用して

Update();
Update();
Draw();

 としたとき、普通の状態で動くように調整すれば

Update();
Draw();

 とすれば、半分の速度で動かすことができます。

チルチル

Re:リプレイ保存の方法

#24

投稿記事 by チルチル » 16年前

やはり広範囲の修正は必要みたいですね。
とりあえず今は初期に作った手抜き部分を修正中なので、
それが終わったらやってみようかな・・

ところで更新処理と描画処理って具体的にはどういうものでしょうか?

EnemyShot.x+=cos(EnemyShot.Angle)*EnemyShot.Speed;//X方向の移動
EnemyShot.y+=sin(EnemyShot.Angle)*EnemyShot.Speed;//Y方向の移動

とかが更新処理で

DrawRotaGraphF( EnemyShot.x , EnemyShot.y , 1.0 , PI/2+EnemyShot.Angle , EnemyShot.Graph , TRUE );//弾を描画

とかが描画処理でしょうか?

だとすると私はこれを同時にやってしまっているので
かなりまずいですね・・

Justy

Re:リプレイ保存の方法

#25

投稿記事 by Justy » 16年前


>とかが更新処理で
>とかが描画処理でしょうか?

 大まかに言えばそんなかんじです。
 更新処理で内部的な処理や描画に必要な情報を計算し、描画処理で実際の描画を行います。

 同時にやってしまっているとなると・・・・・・この方法は使えないですね。

チルチル

Re:リプレイ保存の方法

#26

投稿記事 by チルチル » 16年前

何か管理人さんのプログラムと合わないな~
と思ってましたけど、原因の一つはこれみたいですね。
自分でも気づかないうちに通常から大きく外れていたようです・・

チルチル

Re:リプレイ保存の方法

#27

投稿記事 by チルチル » 16年前

今まで気づきませんでしたが私のコードはかなりまずいことになっていますね・・
更新処理と描画処理が複雑に絡み合っています。

登録~計算~描画の計算と描画を同じ関数でやってますからね・・

計算と描画の基本の形は全関数同じで
void EnemyShotMove(void){//敵弾の関数



for( i=0;i<MAX;i++ ){//ショットfor文

if( EnemyShot.flag>0 ){//フラグが立っていれば

	if( EnemyShot.Graph!=-1 ){
	DrawRotaGraphF( EnemyShot.x , EnemyShot.y , 1.0 , PI/2+EnemyShot.Angle , EnemyShot.Graph , TRUE );//弾を描画
	}

	EnemyShot.Graze=PlayerJudge( EnemyShot.x , EnemyShot.y , EnemyShot.Size , EnemyShot[i].Graze );

	EnemyShot[i].x+=cos(EnemyShot[i].Angle)*EnemyShot[i].Speed;//X方向の移動
	EnemyShot[i].y+=sin(EnemyShot[i].Angle)*EnemyShot[i].Speed;//Y方向の移動

	if( EnemyShot[i].x<0 || EnemyShot[i].x>447 || EnemyShot[i].y<0 || EnemyShot[i].y>479 )EnemyShot[i].flag=0;//画面外に出たらフラグを倒す

switch(EnemyShot[i].Pattern){//ショットのスイッチ文



case 0:



break;



}//ショットのスイッチ文

	++EnemyShot[i].Count;//カウントを進める

}//フラグが立っていれば

}//ショットfor文



}//敵弾の関数
こんな感じです、
改めて見てみると本当に応用ができない処理になっています。
でも描画は一行ですからそれ以外をfor文で囲ってやればできない事もないですね、
弾のパターンの中で描画する場合は最初の一回だけ描画するようにしておけば行けそうだし・・

ところで押されているボタンの組み合わせが何フレーム維持されたかを記録する処理を作ろうとしたんですが
うまくいきません、誰かサンプルを作っていただけないでしょうか?

Justy

Re:リプレイ保存の方法

#28

投稿記事 by Justy » 16年前


>登録~計算~描画の計算と描画を同じ関数でやってますからね・

 分けた方が何かと便利なことがある、というだけで
同じ関数でやってしまっても悪いというわけではないんですけどね。



>サンプルを作っていただけないでしょうか

 まぁそんな簡単に諦めないで、もう少し自力で頑張ってみてください。

 どうしてもうまくいかなければ、どううまくいかなかったのかを説明した方がいいかと。
 状況を整理できますし、書いているうちに気づかなかった解決方法を思いつくかもしれませんよ。

めいらる

Re:リプレイ保存の方法

#29

投稿記事 by めいらる » 16年前

横から失礼しますっ
自分もいつかリプレイを実装しなくてはならないので参考にと覗いてみたのですがなんだかものすごくレベルの高い話が…(^ω^;)

私は毎フレームのキー入力情報を保存する変数配列を用意してコースの進行度カウンターと照らし合わせて記憶、再生を行う仕組みを考えているのですがどうでしょうか?
保存はコースクリア時などにまとめて行うつもりです。
大雑把な流れとしては


通常プレイ時------------------------------

・キー入力を保存する変数を富豪のごとくキーの数だけ用意
(たとえば bool A[10][10000] のように)
           ↑ ↑コースの何フレーム目か
           ∟何ステージ目なのか
ゲームループ{
・キー入力情報を取得し、入力情報変数に入れる
・入力情報をコースカウンターを添字にしたキー変数配列に保存( A[stage][counte[/url]=1 )ボタンAが押されているなら1
・入力情報に従い自機移動処理
・その他弾とか敵とか移動処理
・描画処理
・counter++
}
(コースクリア時とかに変数配列をファイル出力)


リプレイ再生時---------------------------

・コース開始前にそのコースの変数配列にファイルの情報を読み込む

ゲームループ{
・入力情報変数にそのフレームでのキー配列変数の情報をねじこむ
 ( A = A[stage][counte[/url] )
・入力情報に従い自機移動処理
・その他弾とか敵とか移動処理
・描画処理
・counter++
}

…となります。わかりにくくてすみません;

SooA

Re:リプレイ保存の方法

#30

投稿記事 by SooA » 16年前

>・入力情報をコースカウンターを添字にしたキー変数配列に保存( A[stage][counte[/url]=1 )ボタンAが押されているなら1
それだとそのフレームに対して一つのキーしか記録されないので
同時押し状態が保存できません。


>・キー入力を保存する変数を富豪のごとくキーの数だけ用意
流石に全ステージのデータを確保するのもアレなので、
入力回数でステージごとに記録・読み込みすれば良いかな。


例えば以下のような感じでデータを記録して、

AutoKeyData[0] = ステージ1の入力回数
AutoKeyData[1] = ステージ2の入力回数
 :
 :

AutoKeyBuff[0].flame = 30 // 入力に変化があったフレーム
AutoKeyBuff[0].key = ビット変換した入力情報
AutoKeyBuff[1].flame = 60 // 入力に変化があったフレーム
AutoKeyBuff[1].key = ビット変換した入力情報
 :
 :

・再生時
入力回数からデータサイズを求めてステージごとに読み込む。

・キー復元
復元用のテーブル(AutoKey[/url])を用意して、
フレームが一致したら AutoKey[/url] に
AutoKeyBuff[?][1] から入力状態を復元、
次にフレームが一致するまで AutoKey[/url] の情報で
キーバッファを書き換える。

めいらる

Re:リプレイ保存の方法

#31

投稿記事 by めいらる » 16年前

SooAさん>
返信ありがとうございます

>同時押し状態が保存できません。
キーの数だけ配列を用意するので(上下左右ABCDの8個の予定)そのあたりの対応は大丈夫です。例としてAのみ書いた形になりましたが説明不足でした。申し訳ありません…

>復元用のテーブル(AutoKey[/url])を用意して…
…とあるのですが今現在の実装でキーコンフィグの都合上通常時の入力情報も一旦テーブルに置き、それを元に操作しているので再生時にもそのテーブル変数がほとんどそのまま使えると思います。(テーブル=一時的にデータを置いておくスペース という解釈でよろしいでしょうか?)

やはりbool型変数でもゲームとして致命的なレベルのメモリを占有するのでしょうか?今後可能であればコース切り替えはシームレスにする可能性もあるのでまとめて読んで置いておかないとコース切り替え時に止まるかな?と思ったのです。

あと自分はまだビット演算(?)についてほとんど勉強していないのですが推測するに1バイトのサイズの変数で8ボタンの押下情報は記録できますか?それだとしたら記録用の配列がコースにつき一つずつで済みそうなので…
ビットに、「上下左右ABCD」とボタンを割り当てて、そのうち下とBとCが押されている場合、「01000110」と記録するといった感じに…です。

せっかく書いて頂いた例を理解できていないみたいで申し訳ないです

SooA

Re:リプレイ保存の方法

#32

投稿記事 by SooA » 16年前

> >復元用のテーブル(AutoKey[/url])を用意して…
> …とあるのですが今現在の実装でキーコンフィグの都合上通常時の入力情報も一旦テーブルに置き、それを元に操作しているので再生時にもそのテーブル変数がほとんどそのまま使えると思います。(テーブル=一時的にデータを置いておくスペース という解釈でよろしいでしょうか?)

例えば○○フレーム目で入力に変化があり、
AutoKeyBuff[/url].key から情報を復元したとします、
次のフレームに進んみ、入力に変化が無い場合は
前回フレームと同じデータを使います、
そのためのテーブルですので、
既に用意しているテーブルが
リプレイデータ以外で書き換わらないのであれば
そのまま使えると思います。


> やはりbool型変数でもゲームとして致命的なレベルのメモリを占有するのでしょうか?
致命的とまでは言いませんが、
1ステージだけでもフレーム数分+アルファの確保が必要になり
結構な容量が必要になると思いますよ、消費を抑えられる部分であれば
それに越したことは無いかなと思いました。


> まとめて読んで置いておかないとコース切り替え時に止まるかな?と思ったのです。
プレイ中のラグは問題ありですが、
ステージ切り替え時なら他にも読み込むデータがあるだろうし
許容範囲かなと思います。


> あと自分はまだビット演算(?)についてほとんど勉強していないのですが推測するに1バイトのサイズの変数で8ボタンの押下情報は記録できますか?それだとしたら記録用の配列がコースにつき一つずつで済みそうなので…
> ビットに、「上下左右ABCD」とボタンを割り当てて、そのうち下とBとCが押されている場合、「01000110」と記録するといった感じに…です。

そうです。

1 byteは2進数で表すと 00000000(0)~11111111(255)のとなります。

詳しくはWeb検索等で調べてもらうとして、
チルチルさん(旧 匿名さん)のソースを
参考にデータを表示するだけのサンプルを
作ってみると良いかと思います。

めいらる

Re:リプレイ保存の方法

#33

投稿記事 by めいらる » 16年前

なるほどなるほど…
参考になります(^ω^)

ビットが0か1かで判断する方法はビットフラグ?とか言う名称でしたっけ…DXライブラリリファレンスで見かけていたので…

とりあえずググってこようと思います!質問に答えていただきありがとうございます&長々と横入り失礼しました~

チルチル

Re:リプレイ保存の方法

#34

投稿記事 by チルチル » 16年前

なんか私が学校に行っていた間に話が終ってしまったようですね・・
話に加われなくてすいません。

めいらるさんまだ見てますか?

int KEY[8]={KEY_INPUT_Z,KEY_INPUT_X,KEY_INPUT_LSHIFT,KEY_INPUT_LCONTROL,KEY_INPUT_UP,KEY_INPUT_RIGHT,KEY_INPUT_DOWN,KEY_INPUT_LEFT};

の宣言により配列でキーを指定できるようにして、

for(j=0;j<8;j++)if( Key[ KEY[j] ]>0 )i|=(1 << j);

でビットに保存し

for(j=0;j<8;j++)(i&(1 << j)) ? Key[ KEY[j] ]=1 : Key[ KEY[j] ]=0 ;

でビットから変数に読み込んでいます。

今もう一度、押されているボタンの組み合わせが何フレーム維持されたかを記録する処理を作ろうとしています。

よくわからない所は「1フレーム目はどうするか」です。

ところでリプレイの保存ですが、ファイルの新規作成はできますけど
ファイルの削除は多分できませんよね、
だからプレイしている時は画像とか音楽とかを入れているフォルダの中に
ファイルを作って一時的に保存して
「リプレイを保存する」が選択された時に一時ファイルから読み込んで
リプレイフォルダの中にファイルを作成して保存しているんですが
この方法は一般的でしょうか?

Justy

Re:リプレイ保存の方法

#35

投稿記事 by Justy » 16年前


>よくわからない所は「1フレーム目はどうするか」です。

 強制的にカウンタ0で書き込めばいいのではないでしょうか。

 擬似的に処理を書くと
[color=#d0d0ff" face="monospace]
// 追加フラグ(とりあえず最初は falseで)
bool add = false;

if(リプレイバッファが空ではない)
{
if(リプレイバッファの最後に記録されたデータのキーの値と現フレームで押されたキーの値が異なる
|| リプレイバッファの最後に記録されたデータのカウンタが最大に達している)
{
// 追加するフラグを立てる
add = true;
}
else
{
リプレイバッファの最後に記録されたデータのカウンタを +1する
}
}
else
{
// 要素を追加するフラグを立てる
add = true;
}

if(add)
{
リプレイバッファにカウンタ0で現在押された値を追加する
}
[/color]

こんな感じでしょうか。



>ファイルの新規作成はできますけどファイルの削除は多分できませんよね、

 WinAPIを使えば問題なく可能です。




>だからプレイしている時は画像とか音楽とかを入れているフォルダの中に ファイルを作って
>~略~
>リプレイフォルダの中にファイルを作成して保存しているんですが
>この方法は一般的でしょうか?

 普通にリプレイフォルダに適当な名前 "temp.rec"とかで保存しておいて、
「リプレイを保存」されたらリネームすればいいんじゃないでしょうか?

 まぁ、そもそも「リプレイを保存」される前ならファイルに保存しないで
メモリにずっと持っておけばいい、と思いますが(上の擬似的な処理もそれを想定して書いています)。

チルチル

Re:リプレイ保存の方法

#36

投稿記事 by チルチル » 16年前

WinAPIは今の実力ではちょっとむりですね。

メモリにずっと持っておくのはメモリの動的な確保になれていないから
難しいですが、よく考えたらステージのカウントとボスの自爆までの時間を足せば
だいたい何個ぐらい配列が必要かはわかりますね・・

まあ、そんなに気にならないのでとりあえずリプレイを頑張ってみます。

BEMANI

Re:リプレイ保存の方法

#37

投稿記事 by BEMANI » 16年前

>>チルチルさん
プログラムからのファイル削除でしょうか。
stdio.h に remove(ファイル名)という関数があったような気がします。
WinAPI は DeleteFileがあったと思います。
そんなに難しくないので調べてみればいいと思います。

さが

Re:リプレイ保存の方法

#38

投稿記事 by さが » 16年前

横からすみません。自分も考えてみたので致命的な部分があったら教えてもらいたいです。
一部のpad_tなどは龍神録のものをちょっといじったものです。
memcpy memset は動作をよく分かってないので適当です。
typedef struct{
   int time;
   bool input[PAD_MAX]//入力の最大個数の配列
}data;
typedef struct{
   bool key[PAD_MAX];//パッドのボタンが押されたらtrue、押されなかったらfalse
//一部略
}pad_t;
data buf;        //前回のデータ
data temp[10000];//キーの保存
pad_t pad;       //pad.keyにプレイ中のキー情報が保存されている
int count;       //tempにアクセスするための変数
int num;         //待機用カウント変数

//ゲームスタート前に実行
void replay_ini(){
   count = 0;
   memset(&buf,0,sizeof(data));
   memset(&temp,0,sizeof(data)*10000);
}
//pad更新後実行
void replay_stock(bool *p){
   buf.time++;
   for(int i=0;i<PAD_MAX;i++)
      if(buf.input != *(p+i)){  //前回記憶した入力と異なっているか
         memcpy(temp[count], buf, sizeof(data)); //tempに保存
         memcpy(buf.input,p, sizeof(bool)*PAD_MAX); //現在の入力の状態を保存
         count++;
         buf.time = 0;
         return;
      }
}
//ゲーム終了後実行
void replay_save(){
   char *name = "replay.dat";
   FILE *fp;
   if((fp = fopen(name,"w")) == NULL)
      printfDx("replay書き込みエラー\n");
   else{
      fwrite(&count,sizeof(int),1,fp)
      fwrite(&temp,sizeof(data),count,fp);
      fclose(fp);
   }
}
//リプレイ再生のための初期化
void replay_ini2(){
   num = 0;
   char *name = "DAT/keycon.dat";
   FILE *fp;
   if((fp = fopen(name,"r")) == NULL)
      printfDx("keycon読み込みエラー\n");
   else{
      fread(&count,sizeof(int),1,fp)
      fread(&temp,sizeof(data),count,fp);
      fclose(fp);
   }
}
//リプレイ再生するためpad.keyのアドレスをpで受け取り、保存した値を代入
//プレイ時のキー入力取得の直後がいいかと
void replaydata_key(bool *p){
   num++
   if(temp[count].time == num){  //count番目とcount-1番目の入力時間差timeまで待機
      memcpy(p, temp[count].input, sizeof(bool)*PAD_MAX);
      num = 0;
      count++;
   }
}

replay_save()の中身は実際自分が使っているものを引っ張って来ましたが、fopen などで警告がでます。
問題なく動いていますが、警告を消すやり方はあるのでしょうか。
メモリ操作、ポインタの部分は自信ありません。

Justy

Re:リプレイ保存の方法

#39

投稿記事 by Justy » 16年前

さがさん
>自分も考えてみたので致命的な部分があったら教えてもらいたいです。

 実行してみたわけじゃないので憶測になりますが、

1 記録時に最後まで記録されない??
 replay_stockでパッドデータをメモリに記録しているようですが、
前回記憶した入力と異なっていた場合、その前回の入力情報を記録していっていますので、
記録をとる最後のフレーム直前でAボタンが押され、そのまま記録終了となった場合
そのAボタンを押した情報が記録されないような感じがします。

2 再生時のカウンタ
 replay_ini2では tempにリプレイデータが、count変数にそのデータ数が入ります。
 となると、replaydata_key()での temp[count]はリプレイデータの外を指していませんか?



>警告を消すやり方はあるのでしょうか

 あるかないか、で言えばあります。
 大抵の場合、コンパイラの納得のできる形で消す方法と、強制的に消してしまう方法と
ありますが、どちらにしても環境やエラーメッセージの内容がわからないと具体的にはわかりません。

さが

Re:リプレイ保存の方法

#40

投稿記事 by さが » 16年前

Justyさん返信ありがとうございます。

>1 記録時に最後まで記録されない??
そうですね、全くもってその通りです。
ゲーム終了時にキー状態を記憶する関数を呼び出す必要がありますね。

>2 再生時のカウンタ
こちらも死んでますね。読み込み後初期化忘れてます。
void replay_ini2(){
   num = 0;
   count = 0;
   char *name = "replay.dat";
   FILE *fp;
   if((fp = fopen(name,"r")) == NULL)
      printfDx("replay読み込みエラー\n");
   else{
      int n;
      fread(&n,sizeof(int),1,fp)
      fread(&temp,sizeof(data),n,fp);
      fclose(fp);
   }
}
警告は
warning C4996: 'sprintf': This function or variable may be unsafe.
Consider using sprintf_s instead. To disable deprecation,
use _CRT_SECURE_NO_WARNINGS. See online help for details.

これと

ローカルで定義されたシンボル _sprintf がフィクション "void __cdecl graph_main(void)"
(?graph_main@@YAXXZ) にインポートされました。

こんなのが fopen なども同様に出ます。

SooA

Re:リプレイ保存の方法

#41

投稿記事 by SooA » 16年前

さがさん話をぶったぎって申し訳ありません。

> めいらるさん
シンプルなリプレイサンプルを作りましたので、
良かったら参考にしてみてください。

開発環境
Windows XP
VC++2008(BCCでもたぶん動くと思います)

プログラムは四角い豆腐キャラを動かすだけのものです。
実行すると記録するか再生するかの入力待ちになります。
記録を選択すると500フレームまでのカーソルキーの
監視&記録が始まります。

※記録と再生を選択できるように修正を加えました。

さが

Re:リプレイ保存の方法

#42

投稿記事 by さが » 16年前

>SooAさん
途中で入ってきたのは自分の方なので、気になさらないでください。

最初は気になった程度だったのに気が付いたらリプレイを実装していました。
SooAさん、Justyさんのレスを参考に作ってみました。


pad_t は龍神録のものを使ってます。ただ、持つ値は0or1です。
boolだとキャストする時に怒られるので。しかし容量的に考えたらboolにした方がいいですね。
PAD_MAX は 16 に設定してます。

問題点はどれだけ押されたか(長さ)が出てこないことですね。
自分の作っているものには絡んでこないので大丈夫ですけど。

チルチル

Re:リプレイ保存の方法

#43

投稿記事 by チルチル » 16年前

さがさん、キーがどれだけ押されたかを調べる処理を作る場合は
GetHitKeyStateAll_2関数みたいにリプレイデータが1ならインクリメントするようにしてみてはどうですか?

Justy

Re:リプレイ保存の方法

#44

投稿記事 by Justy » 16年前

さがさん
>warning C4996

 警告文の中にヒントが書いてると思いますが、この掲示板の過去ログとか
"C4996"で検索しても対処方法が出てきますので、
そちらを参考にしてください。

 強制的に消してしまいたい場合は
 
気まぐれソフトハウス &raquo; warning C4996
ttp://wind-master.dip.jp/soft-info/item/61

のようにすると消せます。



>シンボル _sprintf がフィクション

 多分コンパイラオプションがおかしいのだとは思いますが。
 リビルドしても直らなければ、コンパイラオプションを見直してください。

リンカ ツールの警告 LNK4217 (C++)
ttp://msdn.microsoft.com/ja-jp/library/aa3se25k(VS.80).aspx

めいらる

Re:リプレイ保存の方法

#45

投稿記事 by めいらる » 16年前

SooAさん>

わざわざサンプルを作っていただいてありがとうございます!
実はまだファイル入出力関係はあまり勉強していなくてよくわからず…
いつかリプレイを実際に実装する時に参考にさせていただきます!

チルチル

Re:リプレイ保存の方法

#46

投稿記事 by チルチル » 16年前

ちょっと学校のレポートを書いていてプログラムができません、
すいませんちょっと待って下さい・・
あと、さがさん&めいらるさん、よかったら話を持たせて下さい・・

Justy

Re:リプレイ保存の方法

#47

投稿記事 by Justy » 16年前

 じゃぁまぁ折角なので、No22407の方法でサンプルを書いてみました。

Uploader
ttp://toku.xdisc.net/tuyu.html
小物(1) 1Mの
nm14140.zip

解凍 pass : u1R51JvcQCTz


 readmeの中にビルド方法と操作方法が書いてあります。
 ソースはちょっと数がありますが、中心になっているのは work.cppで、
記録と再生のコア部分は key_recorder.cppとなります。

 5000フレームくらいガチャガチャとキーを押して保存してみましたが、
2KBもありませんでした。

 結構小さいものですね。

さが

Re:リプレイ保存の方法

#48

投稿記事 by さが » 16年前

返信遅くなりました。

Justyさん指摘ありがとうございます。
最初の方は警告は出なくなりましたが、2番目の方は別のエラーが出てしまうので
手が空いてる時にやろうと思います。


前あげた自分のリプレイモジュールは、2P用に拡張して1Pが1000と2Pが100入力で8KBでした。
まだまだ未熟ですね。

チルチル

Re:リプレイ保存の方法

#49

投稿記事 by チルチル » 16年前

remove関数の使い方は理解しましたが
よく考えたら、データフォルダからリプレイフォルダに
保存しなおす時にステージ情報とかを先頭に加えているので
あまり意味が無かったですね・・

チルチル

Re:リプレイ保存の方法

#50

投稿記事 by チルチル » 16年前

コードを作ってみたのですがうまく動きません、どこか間違っているでしょうか?
unsigned char InputKey,InputCount;//キー入力データ

long i,j,Count;//カウンタ

InputKey=0;//初期化

InputCount=0;//初期化



//ループの中



int KEY[8]={KEY_INPUT_Z,KEY_INPUT_X,KEY_INPUT_LSHIFT,KEY_INPUT_LCONTROL,KEY_INPUT_UP,KEY_INPUT_RIGHT,KEY_INPUT_DOWN,KEY_INPUT_LEFT};



if( Mode!=4 ){//リプレイ再生中でなければリプレイを一時保存

	i=0;

	for(j=0;j<8;j++)if( Key[ KEY[j] ]>0 )i|=(1 << j);

	if( Count==0 ){

		for(j=0;j<8;j++)if( Key[ KEY[j] ]>0 )InputKey|=(1 << j);

		fputc(InputKey,REPLAY_fp);

	}

	else if( InputKey!=i || InputCount==255 ){

		fputc(InputCount,REPLAY_fp);

		InputKey=0;

		InputCount=0;

		for(j=0;j<8;j++)if( Key[ KEY[j] ]>0 )InputKey|=(1 << j);

		fputc(InputKey,REPLAY_fp);

	}

	++InputCount;

}

else{//リプレイ再生中ならリプレイを再生

	if( InputCount==0 ){

		InputKey=fgetc(REPLAY_fp);

		InputCount=fgetc(REPLAY_fp);

	}

	for(j=0;j<8;j++)(InputKey&(1 << j)) ? Key[ KEY[j] ]=1 : Key[ KEY[j] ]=0 ;

	--InputCount;

}

SooA

Re:リプレイ保存の方法

#51

投稿記事 by SooA » 16年前

最初の Count=0 の処理でデータを一つ分しか書き込んでいないのに対して
読み込み時は二つ分ずつ読み込んでいます。
更新時の処理ですが InputKey に i と同じ値を入れてるので
InputKey = i ; で良いかと。

SooA

Re:リプレイ保存の方法

#52

投稿記事 by SooA » 16年前

Count = 0 時に InputCountが記録されていないという意味です。
一つ分とか訳のわからない書き方してしまったので追記しておきます。@@;

SooA

Re:リプレイ保存の方法

#53

投稿記事 by SooA » 16年前

申し訳ないです、よく見ていませんでした。
データを交互に書き込んでるんですね。
しかし最終的に最初の InputCount分
足りなくなるので対処は必要だと思います。

全体的な処理としてはじっくり見てみたいと思います。

チルチル

Re:リプレイ保存の方法

#54

投稿記事 by チルチル » 16年前

とりあえずファイルの最後に達していたらリプレイを終了するようにしないといけませんね、
しかし、どこが間違っているのだろうか・・

チルチル

Re:リプレイ保存の方法

#55

投稿記事 by チルチル » 16年前

ちょっと実行してみたんですが、作成されたリプレイファイルが途中で改行されているんですよね・・
多分うまく動かない原因はこれですね、前の方法では最後まで行ってから改行されていましたから、
何で改行されてるんだろう?
数値が改行記号に対応して・・ないですよね。

今さらですけど計算部と描画部を分けた方が良かったですね・・
当たり判定の目安を描画する時とかが・・

SooA

Re:リプレイ保存の方法

#56

投稿記事 by SooA » 16年前

> 数値が改行記号に対応して・・ないですよね。
改行コードは 0x0d(13) 0x0a(10) ですので
この数値が並べばテキストエディタで開いた場合
改行として認識されます。

InputKey、InputCount共にその数値が出る可能性があるため
改行される可能性は十分あります。

チルチル

Re:リプレイ保存の方法

#57

投稿記事 by チルチル » 16年前

やっぱり改行になりますか・・
あれ~前は改行が発生しなかったんだけどな~
しかし改行をfputc/fgetcはどう認識するんでしょうか?
改行してたらストリームも改行してくれれば問題は無いんですが・・
いや、プログラムで開いた場合は改行コードの後も普通に数値が並んでるのかな?

kazuoni

Re:リプレイ保存の方法

#58

投稿記事 by kazuoni » 16年前

横から失礼します^^;

っといってもJustyさんへのコメントなんですが。。

RecordKeyをこそっとDLし、大方解析させていただきました^^;
ありがとうございました。
経験されている方のコードは本当に参考になります。。
RecordKeyぐらいの規模かつC++で組まれている
(ちょっとした)ソフトのコードをどんどん見ていきたいですね。。
ただ、ネットで探すと(探し方が甘いかも知れないですけど)規模の大きさが両極端なんですよね。
デザインパターンが使ってあるっと絞るとさらに狭く・・・。
コード見せてください!なんてスレ立てる勇気もないですが^^;


トピ主さんの質問には関係のないレスで申し訳ないです。。
失礼しました。

Justy

Re:リプレイ保存の方法

#59

投稿記事 by Justy » 16年前


>本当に参考になります

 いえいえ、あんなんで良ければ。
 
 細かいところ見ていくと結構粗というか「?」な部分が見つかったりしますが、
そのあたりはサンプルということで……。



>ネットで探すと規模の大きさが両極端なんですよね

 たしかにそういう傾向はあるかもしれませんね。

 でも少し大きめの規模のものは全体を把握するのは大変ですし時間もかかりますが、
あえて全体を見ず細かいところから見てってもいいわけですし、
規模が大きいなりの工夫(ソースの書き方だけでなく、フォルダ・プロジェクトの構成とか)があり、
大抵複数人で書いているのでそれぞれの書き方の違いを見ていったり、と読み解いていくと
得られるものも多いので、それなりに面白いですよ。

チルチル

Re:リプレイ保存の方法

#60

投稿記事 by チルチル » 16年前

う~ん、改行しないようにリプレイを保存して再生してみたら、
見た感じ正常に再生されました。
やっぱりfputc/fgetcは改行を認識していないのかな?

チルチル

Re:リプレイ保存の方法

#61

投稿記事 by チルチル » 16年前

と言うよりプログラムは改行を認識しているんでしょうか?
一応改行された時の処理とかはあった気がしますが・・

チルチル

Re:リプレイ保存の方法

#62

投稿記事 by チルチル » 16年前

う~んわからないですね改行・・

さが

Re:リプレイ保存の方法

#63

投稿記事 by さが » 16年前

バイナリで保存してはどうですか?
自分はバイナリモードで開かなかったのでバグが出ましたけど、そこに気をつければ大丈夫なはずです。

添付は前あげたものにvectorに改良したものです。2Pのものを1P用にしたので変換ミスがあるかも。
pad_tの指定がありますが、
ReplayRecInit と ReplayLoad 、
ReplayRec と ReplayInput をそれぞれ同じ位置にすれば動作するはずです。

vectorを使うには
vectorをincludeする必要があります。


参考程度にどうぞ

チルチル

Re:リプレイ保存の方法

#64

投稿記事 by チルチル » 16年前

あ~そう言えばバイナリがありましたね・・

チルチル

Re:リプレイ保存の方法

#65

投稿記事 by チルチル » 16年前

検証してみたのですが、どうも改行は関係ないようですね、
改行のあるテキストファイルも、問題なく読み込んで表示できましたし・・

そもそも上のコードで言うと
13と10はZ,X,LCONTROLとX,LCONTROLの組み合わせになるんですが
リプレイのテストをする時はボムを使わないようにしているので
改行してるのは多分カウントみたいですね・・

むしろ読み込む時に何か間違って読み込んでいるように見えますね・・

怪しいのは(InputKey&(1 << j))の戻り値ですね、
普通戻り値は1か0ですが上の式は戻り値がビットシフトのようです、
for(j=0;j<8;j++)(InputKey&(1 << j)) ? Key[ KEY[j] ]=1 : Key[ KEY[j] ]=0 ;
が正確に実行されているのか心配ですが、式の場合は0以外は1と認識されるから
多分大丈夫だと思うのですが・・

チルチル

Re:リプレイ保存の方法

#66

投稿記事 by チルチル » 16年前

よく考えたら今でも上の式は使っているから大丈夫かも・・

SooA

Re:リプレイ保存の方法

#67

投稿記事 by SooA » 16年前

先日から頭痛に悩まされていたのですがやっと完治。
3錠飲むべき薬を1錠で済ませ、しかも一日一回しか
服用しなかったのが敗因?なのか長引いて
こちらの返信遅くなりました><;

問題の方は解決しましたでしょうか?
貼られているソースは部分的なものだと思うのですが、
リプレイ選択時 InputCount を 0 で初期化していますか?
Count = 0 の時の処理で(メインで回してるフレーム数ですよね?)
正しく一回目が読み込まれていない可能性はないでしょうか?

チルチル

Re:リプレイ保存の方法

#68

投稿記事 by チルチル » 16年前

InputCountはループに入る前に初期化しているので大丈夫だと思います、
一回目は多分正しく読み込まれているみたいです、
最初の方は正確に再生されるんですが、3秒経過したあたりで
InputKeyとInputCountの中身がおかしくなります、
そしてデータに改行が無いと結構うまくいったりします・・

チルチル

Re:リプレイ保存の方法

#69

投稿記事 by チルチル » 16年前

そういえば他の関数はストリームの位置が変更されるのだろうか?

チルチル

Re:リプレイ保存の方法

#70

投稿記事 by チルチル » 16年前

そういえばストリームを変更する関数もうまくいかないな・・

256bit

構造体の知識について

#71

投稿記事 by 256bit » 16年前

 現在、構造体を利用したキャラクター分割を行っています。構造体の知識は中級ほどの知識が無いと難しいですか?

MNS

Re:構造体の知識について

#72

投稿記事 by MNS » 16年前

中級ほどの知識、というものがどれ程なのかが分からないので、回答しようが無いのですが、
構造体自体はそれほど難しいものではありません。
そもそもC言語は典型的な構造化プログラミング言語なので、
基本といっても過言ではないと思います。


256bit

Re:構造体の知識について

#74

投稿記事 by 256bit » 16年前

 ↑すみません。またやってしまいました。(--;)
 
 >>MNSさん

 どうも、ありがとうございます。
 構造体の勉強頑張ります。(^_^)/~

紅葉

Re:構造体の知識について

#75

投稿記事 by 紅葉 » 16年前

構造体は変数をまとめたものですので理解はすぐにできるかと思います。

例えば下記の場合(書き方が何種類かあります)
typedef struct{
   float x,y;
   int type;
}CHR;

CHR Play;
CHR Enm;
のように書いて同じような変数を使うものをまとめるだけなんです。
float Play_x,Play_y;
float Enm_x,Enm_y;
のように分けて書く必要がありません。

例の通り書けばPlay.xのように変数を定義できます。

ご存知の事でしたら申し訳ないです。

256bit

Re:構造体の知識について

#76

投稿記事 by 256bit » 16年前

 >>紅葉さん

 ありがとうございます。
 構造体勉強への参考にしたいと思います。 

閉鎖

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