データ指向設計の例


8

一般的なゾンビゲームのデータ指向のデザインの良い説明が見つからないようです(これは単なる例であり、かなり一般的な例です)。

ジェネリックゾンビクラスの作成に関するデータ指向デザインの例を挙げていただけませんか?以下は良いですか?

ゾンビリストクラス:

class ZombieList {
    GLuint vbo; // generic zombie vertex model
    std::vector<color>;    // object default color
    std::vector<texture>;  // objects textures
    std::vector<vector3D>; // objects positions
public:
    unsigned int create(); // return object id
    void move(unsigned int objId, vector3D offset);
    void rotate(unsigned int objId, float angle);
    void setColor(unsigned int objId, color c);
    void setPosition(unsigned int objId, color c);
    void setTexture(unsigned int, unsigned int);
    ...
    void update(Player*); // move towards player, attack if near
}

例:

Player p;

Zombielist zl;
unsigned int first = zl.create();
zl.setPosition(first, vector3D(50, 50));
zl.setTexture(first, texture("zombie1.png"));
...

while (running) { // main loop
    ...
    zl.update(&p);
    zl.draw(); // draw every zombie
}

またはからのすべてのアクションが含まれ、一般的な世界のコンテナの作成うbite(zombieId, playerId)moveTo(playerId, vector)するcreatePlayer()までshoot(playerId, vector)にしますface(radians)/face(vector)。含まれています:

std::vector<zombie>
std::vector<player>
...
std::vector<mapchunk>
...
std::vector<vbobufferid> player_run_animation;
...

良い例ですか?

DODでゲームを整理する適切な方法は何ですか?

回答:


11

「DODとのゲーム」というものはありません。第一に、各システムはデータ指向で設計されているため、その流行語は少しあいまいです。各プログラムは一連のデータを処理し、特定の変換を行います。設計をデータに向けることなしにそれを行うことは不可能です。したがって、「通常の」デザインと相互に排他的ではありませんが、メモリレイアウトとメモリへのアクセス方法にそれぞれ制約が追加されます。

DODの背後にある考え方は、1つの機能に属するデータを連続したメモリブロックに近づけてパックし、グループ化して、キャッシュミスを減らし、仮想関数とvtableを取り除き、並列化を容易にし、ランダムメモリアクセスを行わない(または最小限に抑える)ことです。限られたメモリリソースでPS3のCellのSPUなどの高度に最適化されたプロセッサのコードを記述し、メインメモリへのメモリアクセスとメインメモリからのDMAを最適化します。

これは、ここに示す例のように、単に「構造の配列」(AoS)から「配列の構造」(SoA)にすべてを変更することを意味するのではありません。また、両方を混合し、1つの機能に属するデータをインターリーブおよびパックすることも意味します。

ただし、連続したメモリブロックにアクセスせず、ポインタを逆参照してランダムメモリアクセスを行うため、各ポインタアクセスはその純粋な概念に違反するため、純粋なDODシステムの実装は非常に困難です。これは、たとえばパーティクルシステムをCPUからSPUに移動するときにSPUのコードを記述する場合に特に重要ですが、通常の日常のゲーム開発では重要ではありません。これは、(Noelsの記事で説明されているように)ゲームを作成するのではなく、サブ機能を最適化する方法です。

インソムニアックゲームズからマイク・アクトンは、このトピックに関連intesting材料をたくさん持っている、あなたは彼のものをいくつか見つけることができるここだけでなく、ノエルの記事、両方を強くお勧めします。


この回答に追加したいことが1つあります。DODはSoAシステムのすべてではありません。SoA構造はDODに最適に機能する傾向がありますが、実際のDODコンセプトに常に適合するとは限りません。DODの背後にある概念は、単にデータを中心にコードを設計しているという概念であり、その逆ではなく、通常の方法です。
グルガドゥルゲン、2015年

0

私もこの良い例を探していますが、ネット上のリソースが限られているため、適切な方法を教えてくれる人がいないため、次の実装でそれを行いました。(最高ではないかもしれませんが、基本的な考え方に従っています)

Object
   //Basic data
   Vector3* Position;
   Vector3* Rotation;
   Vector3* Scale;



Car : Object
    float* acceleration;
    Object* GetObjectData();
    //invoke the updateCars, to update all cars.
    void    UpdateCar() { UpdateCars(Postion, Rotation, Scale);

    //Update all your objects in a big loop.
    void    UpdateCars(vector3* Position, vector3* Rotation, Vector3* scale);

したがって、実装は多かれ少なかれ次のようになります。すべての共通データを保持する基本オブジェクトクラスがあります。車のクラスが作成されるとき、プールするデータの量を指定します。そのため、すべてのオブジェクトに対して十分なメモリがあります。

そこから、識別子を追加したり、実装に必要だと感じるものを追加したりできます。しかし、私はより単純なゲームでこれを試しました、そしてそれはかなりきちんと動作しませんでした。

それはあなたのデザインからそれほど遠くもありません、そして率直に言って、私はこれを行うためのより効率的な方法を知りません。


いくつかのDODの問題:1.確かに、スケールが失われます。位置と回転に関する計算は、事実上常にスケールの影響を受けないため、ほとんど使用されず、キャッシュスペースを占有します。2.回転も失われ、速度に置き換えられます。自動車は直進を目的としていますが、速度によって最終的に方向が決まります。運転手はガスの花びらを押しますが、物理学は車を動かします。3.ほぼすべての計算で一緒に使用する予定がない場合は、データのクラスから継承しないでください。4. OOPでさえ、車は互いに更新しません。無料の機能を使用してください。
グルガドゥルゲン、2015年

これは単なる例であり、最終的なガイドではありません。もちろん、自分の実装に最適なフィッティングを選択する必要があります。(それが述べられているように)
Tordin

あなたの例は、標準のOOP抽象化の例であり、DoD戦略をほとんど、またはまったく利用していません。DoDはデータではなく、モデルに関するものです。あなたが「車」オブジェクトさえ持っているという事実は、これが国防総省の例の多くではないという完全な景品です。車はかなり具体的で、DoDは継承ベースではなく、存在ベースのオブジェクト構成とポリモーフィズムを行う傾向があります。したがって、たとえば、複数の変換の情報を持つオブジェクトの代わりに、特定の変換に必要な情報を保持し、それらのオブジェクトの配列を作成するオブジェクトがあるとします。
グルガドゥルゲン、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.