SAIさんへ。リプレイデータ保存機能できたよー。

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前
住所: 東京

SAIさんへ。リプレイデータ保存機能できたよー。

投稿記事 by MoNoQLoREATOR » 14年前

はい。できました。
生放送ではSAIさん、ROTOさん、大変お世話になり本当にありがとうございました。
VCのデバッグ機能の使い方がやっとわかりました(爆笑)

ソースと実行ファイルを下記にアップしましたのでどなたでもご自由にお使いください。リリースビルドしているので、使用する際は相対パスの設定にお気を付けください。
http://www1.axfc.net/uploader/Sc/so/272 ... key=replay


さて、解説です。
概要を説明します。

リプレイデータを保存(今回は「キー状態が変更されたのが何フレーム目か」・「どのキー状態が変更されたか」という情報を保存)

リプレイデータを読み込み

リプレイデータに応じて自機を移動させたりする

もう少し詳しく説明します。

//キー操作
z・・・ショット(面倒くさいので未実装)
x・・・低速移動
c・・・ボム
十字キー・・・各移動

//リプレイデータを保存するタイミングについて
1つ前のフレームのキー入力状態を記憶しておき、現在のキー入力状態と比較して変更があればそのキーを保存します。そのため寸分の狂いなく全く同時にキーが押された場合はバグります。TAS対策ということにしておきましょう。

//リプレイデータに応じて自機を移動させたりする処理について
「リプレイデータからのキー状態変更」のみを受け付ける変数を用意し、ユーザーからのキー入力状態の受付終了後にキー状態をコピーすれば、あとは普段通りの処理をするだけで済みます。そうしないとリプレイ時にキー入力があるとめちゃくちゃになります。


近い未来に、徹底的に解説した動画でもつくろうかなと思っています(´・ω・)
では、良いプログラミングライフを。

ISLe
記事: 2650
登録日時: 14年前

Re: SAIさんへ。リプレイデータ保存機能できたよー。

投稿記事 by ISLe » 14年前

デジタル入力なら、enumに合わせてビットをOn/Offした値を使うと良いですよ。
同時入力にも対応できるし、XORだけで変化が分かります。

アバター
SAI
記事: 115
登録日時: 14年前

Re: SAIさんへ。リプレイデータ保存機能できたよー。

投稿記事 by SAI » 14年前

ありがとうございます!明日読ませていただきますね!
ところで同時にキーが押されたらバグるってまずくないですか?
TASじゃなくても同じフレームに2つ以上押されることもあると思います。
あと、ユーザーのキー入力が無視されてしまうと途中でやめたりできないので不便ではないでしょうか?

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前
住所: 東京

Re: SAIさんへ。リプレイデータ保存機能できたよー。

投稿記事 by MoNoQLoREATOR » 14年前

>>ISLeさん
そうですね。STLにbitsetというものがあることを思い出しました。今度やってみます。

>>SAIさん
寸分違わず同時に押すことは人間には不可能だと思いますが・・・。
1フレームさえずれていれば正常に動作しますよ。
一応解決することはできますが、いろいろと面倒です。

ポーズキーだけ無視しないようにすれば解決できますよ。その辺りはカスタマイズしてください。

ちなみにリプレイデータが存在しないときの動作は未定義です。
また、「リプレイデータ作成」を選択した状態でエンターキーによって決定しようとすると、一瞬でリプレイデータ作成が終了するという結果になります。私はこれで構わないと思うのですが、どうしても気になるのなら修正する必要があります。

アバター
SAI
記事: 115
登録日時: 14年前

Re: SAIさんへ。リプレイデータ保存機能できたよー。

投稿記事 by SAI » 14年前

コードを見せていただきました。
私がわからなかったのは、キー入力の保存にvectorやlistのような可変長のものを使用した場合、リプレイをfwrite関数を使用してセーブした場合にfread関数で再び読み込めるのかということだったのですが、
fstreamのread関数やwrite関数を使用することにより可変長のものを読み込んでいるという方法を知ることができ、大変参考になりました。

このコードの中では、ファイルを開いてはいるのもの、閉じていないのですが、これで毎フレームファイルが開かれていてメモリを使用したりしないのですか?
それともスコープを外れると自動的にファイルを閉じるような仕様なのでしょうか?

xxx
記事: 26
登録日時: 14年前

Re: SAIさんへ。リプレイデータ保存機能できたよー。

投稿記事 by xxx » 14年前

入力が変わった時のフレームとその時の入力状態をbitで管理して面ごとに保存すると楽っぽかった気がします.

>リプレイデータに応じて自機を移動させたりする処理について
キャラクターのオブジェクトに移動させるmoveと移動量をセットするsetとか作っておくものかと思ってました...

>このコードの中では、ファイルを開いてはいるのもの、閉じていないのですが、これで毎フレームファイルが開かれていてメモリを使用したりしないのですか?
>それともスコープを外れると自動的にファイルを閉じるような仕様なのでしょうか?
めんどうなのでコード見てないんですがデストラクタがやってくれてるのでは?

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前
住所: 東京

Re: SAIさんへ。リプレイデータ保存機能できたよー。

投稿記事 by MoNoQLoREATOR » 14年前

>>このコードの中では、ファイルを開いてはいるのもの、
>>閉じていないのですが、これで毎フレームファイルが開
>>かれていてメモリを使用したりしないのですか?
>>それともスコープを外れると自動的にファイルを閉じるよ
>>うな仕様なのでしょうか?
その通りです。fstreamを使用すれば、スコープを外れると自動的にファイルが閉じられます。


さて、bitsetを使うとか言っていたのですが、単純にbool型配列を使った方が簡単に実装できるという結論に至ったので、そうします。また、それに伴い「状態が変更されたキーを保存する」という仕様から「その時のキー状態を保存する」という仕様に変更します。実は、こちらの方が楽だったのですが、リプレイデータの容量をできるだけ小さくするためにこの仕様をとっていました。

アバター
SAI
記事: 115
登録日時: 14年前

Re: SAIさんへ。リプレイデータ保存機能できたよー。

投稿記事 by SAI » 14年前

ありがとうございます。
自動的にファイルが閉じられるなんてすごい仕様ですね。

私が現在考えているキー入力保存の方法は、各入力(矢印やショットなど)ごとにint型のvectorかlistを用意して、それぞれが変化したときのフレームをそれぞれに記録すれば1回の入力変化あたりint1つで済むと思うのですがどうでしょう?

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前
住所: 東京

Re: SAIさんへ。リプレイデータ保存機能できたよー。

投稿記事 by MoNoQLoREATOR » 14年前

結論から言うと、不可能だと思います。変化が起こったフレームを特定することはできますが、どのキーが変化したかは特定できません。(変化があるごとにintひとつ分のデータを保存していく仕様だと解釈した場合の話)

アバター
SAI
記事: 115
登録日時: 14年前

RE: SAIさんへ。リプレイデータ保存機能できたよー。

投稿記事 by SAI » 14年前

しつこくてすみません。でもどうしても気になるので。
例を出しますと、たとえば十字の4つしかキーがないと仮定します。

CODE:

//includeとか省略
vector> key;
key.resize(4);
これでコンテナを4つ用意します。
1フレーム目に↑が変化
5フレーム目に→が変化
8フレーム目に↓が変化
10フレーム目に↑が変化
したとします。
↑が0、→が1、←が2,↓が3とすると、
key[0]の中身は1、10
key[1]の中身は5
key[3]の中身は8
と記録することでint1つ分で済ませようと思ったのですが間違ってますでしょうか?
まだ頭の中で考えただけですのでどこかに欠陥があるかもしれません。

でもこの場合ロードする際に各コンテナの要素数を記録した変数がないとどれだけロードすればいいかわからないような気がしますので、そこでint1つずつ使いますね。
最後に編集したユーザー SAI on 2011年9月07日(水) 23:55 [ 編集 1 回目 ]

ISLe
記事: 2650
登録日時: 14年前

RE: SAIさんへ。リプレイデータ保存機能できたよー。

投稿記事 by ISLe » 14年前

便利なライブラリは使ってませんが、こんなやり方もあるということで。

CODE:

int prev_inbits = 0; /* 前回の入力状態 ※外部変数 */

int inbits = 0; /* 入力状態を各ビットのOn/Offで */
if (key[KEY_INPUT_UP])    inbits |= 1<<KEY_UP;
if (key[KEY_INPUT_DOWN])  inbits |= 1<<KEY_DOWN;
if (key[KEY_INPUT_LEFT])  inbits |= 1<<KEY_LEFT;
if (key[KEY_INPUT_RIGHT]) inbits |= 1<<KEY_RIGHT;

if (inbits ^ prev_inbits) {
	/* 変化あり */
	prev_inbits = inbits;
}
変化があったらinbitsを記録していけば良いです。