0

ゲームの「再生システム」を書いていますが、記録されたフレームをどのように保存すればよいのでしょうか?

今のところ、私はこのコード/構造を持っています(注:このコードは短縮されています):

struct Point4D { float x, y, z, w; };
struct Point3D { float x, y, z; };
struct Point2D { float x, y; };
struct QuatRot { Point4D Front,Right,Up; };
struct VehicleInfo
{
    Point3D     Pos,Velocity,TurnSpeed;
    QuatRot     Rotation;
};
namespace Recorder
{
    struct FrameInfo
    //~380 bytes / frame| max 45600 bytes @ 120 fps
    //max 3.7 GB raw data for 24 hours of recording, not bad..
    {
        std::chrono::high_resolution_clock::duration time;
        VehicleInfo Vehicle;
        int Nitro;
        float RPM;
        int CurrentGear;
    };

    std::deque<FrameInfo> frames;
    FrameInfo g_Temp;

    void ProcessRecord()
    {
        //record vehicle data here to g_Temp
        frames.push_back(g_Temp);
        return;
    }
    //other recording code.......
};

私が考えていたのは、生のバイト配列を作成し、それを deque コンテナーのサイズに割り当て、memcpy で deque から配列にコピーしてから、すべての配列バイトをファイルに書き込むことです..

次に、記録データを読みたい場合は、ファイルのバイトを読み取って新しい配列に割り当て、memcpy を使用して配列の内容を deque にコピーします。

これはよく似ています..まあ..Cの方法ですか?これを行うには、他の方法が必要です。データをファイルに保存してから、それを両端キューに読み込みます (おそらく C++11 の機能を使用しますか?)。

どうすればこれを達成できますか?

どのアプローチをお勧めしますか?

それが重要な場合、私は窓を使用しています。

4

2 に答える 2

1

memcpy時期尚早の最適化です。

ディスクからデータを読み取る場合、ボトルネックはディスク IO であり、メモリのある部分から別の部分にコピーすることではありません。

データ構造を修正して、固定サイズのデータ​​構造を使用するようにします (の代わりにint、32 ビットの int を使用するなど)。

バイナリで記述しないでくださいstd::chrono::high_resolution_clock::duration。ライブラリの更新により、まばたきしたり涙を流したりすることなく、そのサイズが完全に変更される可能性があります。または何かに書き出すmsと、(たとえば) 64 ビット整数で意味が常に同じになります。その後、それを に読み戻すことができますstd::chrono::high_resolution_clock::duration

シリアル化するときは常にバージョン番号と構造サイズを書き出して、逆シリアル化で基本的なバージョン管理も処理できるようにします。

「ストリームへ」と「ストリームから」を書きます。「ストリームする」には、バージョン番号とサイズを書き出します。「ストリームから」は、バージョン番号とサイズを読み取り、現在のバージョンとストリーム バージョンの両方にある各フィールドを読み込み、残りをクリアしてから、残りのデータをストリームから読み取ります。

より多くのパフォーマンスが必要な場合は、車の位置と角度がギアよりもはるかに頻繁に変化することに気付くでしょう。さらに、既存のフレーム間で適切に補間されたフレームをドロップすると、リプレイ形式のサイズが大幅に縮小されます (説明を考えると、リプレイで物理演算を実行しているわけではありません)。最後に、一貫した物理モデルがある場合は、ユーザー入力の保存とそれに基づく再生のみが可能です (ただし、実現するのは困難です)。

その他の狂気: SRECORDASSIGN はoperator=、問題の構造を呼び出すだけで置き換えることができます。ポインターに適用されるようなマジック ナンバー0x4Cはばかげており、ほとんどの場合、単純な構造体メンバー アクセスに置き換えることができます。

于 2013-02-28T23:27:38.467 に答える
0

私があなたの質問を正しく解釈した場合 (私は疲れているので、私が間違っている場合はコメントを残してください)、あなたは記録をファイルに書き込んだり、ファイルから読み込んだりしたいと考えています。

これは、任意の構造体で簡単に実行できます。

struct Foo
{
   float bar;
   int baz;
};
std::ostream& operator<<(std::ostream& stream, const Foo &foo)
{
   stream << foo.bar << " " << foo.baz;
}
std::ofstream& operator<<(std::ofstream& stream, Foo &foo)
{
   stream.write(reinterpret_cast<char*>(&foo.bar), sizeof(bar));
   stream.write(reinterpret_cast<char*>(&foo.baz), sizeof(baz));
}
std::ifstream& operator>>(std::ifstream& stream, Foo &foo)
{
   stream.read(reinterpret_cast<char*>(&foo.bar), sizeof(bar));
   stream.read(reinterpret_cast<char*>(&foo.baz), sizeof(baz));
}

これをテストできます

#include <fstream>
#include <iostream>

int main()
{
   Foo foo;
   foo.bar = -1.2f;
   foo.baz = 37;
    std::cout << foo << "\n";
   std::ofstream output;
   output.open("myfile", std::ios::binary);
   output << foo;
   output.close();
   std::ifstream input;
   input.open("myfile", std::ios::binary);
   input >> foo;
   input.close();
   std::cout << foo << "\n";
}

std::basic_ostream::writeおよびの詳細については、 cppreference.comstd::basic::istream::readを参照することをお勧めします。

于 2013-02-27T21:46:21.107 に答える