Contoh Desain Berorientasi Data

8

Saya sepertinya tidak bisa menemukan penjelasan yang bagus tentang Desain Berorientasi Data untuk permainan zombie generik (itu hanya contoh, contoh yang cukup umum).

Bisakah Anda membuat contoh Desain Berorientasi Data pada pembuatan kelas zombie generik? Apakah yang berikut ini baik?

Kelas daftar zombie:

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
}

Contoh:

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
}

Atau akan menciptakan wadah Dunia generik yang berisi setiap tindakan dari bite(zombieId, playerId)ke moveTo(playerId, vector)ke createPlayer()ke shoot(playerId, vector)ke face(radians)/face(vector); dan mengandung:

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

menjadi contoh yang baik?

Apa cara yang tepat untuk mengatur gim dengan DOD?

Sepatu
sumber

Jawaban:

11

Tidak ada yang namanya "permainan dengan DOD". Pertama, kata buzz itu agak kabur, karena setiap sistem dirancang berorientasi data. Setiap program bekerja pada satu set data dan membuat transformasi tertentu untuk itu. Tidak mungkin melakukan itu tanpa mengarahkan desain ke data. Jadi itu tidak saling eksklusif dengan desain "normal", tetapi menambahkan kendala dalam tata letak memori dan cara memori diakses masing-masing.

Gagasan di balik DOD adalah untuk mengemas dan mengelompokkan data milik satu fungsi yang lebih dekat bersama-sama dalam blok memori yang berkelanjutan, agar memiliki lebih sedikit cache yang hilang, menyingkirkan fungsi dan tabel virtual, paralelisasi yang lebih mudah, tidak ada (atau minimal) akses memori acak dan untuk menulis kode untuk prosesor yang sangat optimal seperti SPU Cell di PS3 dengan sumber daya memori yang terbatas, mengoptimalkan akses memori dan DMA ke dan dari memori utama itu.

Ini tidak hanya berarti mengubah segalanya dari "Array-of-Structures" (AoS) menjadi "Structure of Arrays" (SoA) seperti yang ditunjukkan pada contoh di sini. Ini juga dapat berarti mencampurkan keduanya dan menyisipkan dan mengemas data yang dimiliki oleh satu fungsi secara berdekatan, seperti misalnya "posisi" dan "kecepatan" untuk menghindari lompatan dalam memori untuk integrasi posisi.

Namun, sistem DOD murni sangat sulit untuk melaksanakan, karena setiap akses pointer adalah pelanggaran itu murni konsep, karena Anda tidak mengakses blok memori continious lagi, tapi melakukan memori akses acak oleh dereferencing pointer. Ini khususnya penting untuk menulis kode untuk SPU ketika memindahkan misalnya sistem partikel dari CPU ke SPU, tetapi dalam pengembangan permainan sehari-hari normal itu tidak penting. Ini adalah cara untuk mengoptimalkan sub-fungsionalitas, bukan untuk menulis game dengannya (belum, seperti yang dijelaskan artikel Noels).

Mike Acton dari Insomniac Games memiliki banyak materi menarik terkait dengan topik ini, Anda dapat menemukan beberapa barangnya di sini serta artikel Noel , keduanya sangat direkomendasikan.

Maik Semder
sumber
Satu hal yang ingin saya tambahkan ke jawaban ini: DOD tidak SEMUA tentang sistem SoA. Sementara struktur SoA cenderung bekerja paling baik untuk DOD, mereka tidak selalu cocok dengan konsep DOD yang sebenarnya. Konsep di balik DOD hanyalah gagasan bahwa Anda merancang kode di sekitar data, bukan sebaliknya, yang merupakan metode biasa.
Gurgadurgen
0

Saya telah mencari contoh yang baik dari ini juga, tetapi dengan sumber daya terbatas di internet dan tidak ada yang memberi tahu saya bagaimana melakukannya dengan benar, saya melakukannya dengan implementasi berikut. (mungkin bukan yang terbaik, tetapi mengikuti ide dasar)

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);

Jadi implementasinya kurang lebih seperti ini: Anda memiliki kelas objek dasar, yang menampung semua data umum. Ketika kelas mobil Anda dibangun, Anda menentukan jumlah data yang Anda ingin mengumpulkan, dan karenanya memiliki memori yang cukup untuk semua objek.

dari sana Anda dapat menambahkan pengidentifikasi atau apa pun yang diperlukan untuk implementasi Anda di luar kantor. tetapi saya mencoba ini pada permainan yang lebih sederhana, dan itu berhasil dengan cukup rapi.

Itu tidak jauh dari desain Anda, dan terus terang saya tidak tahu cara yang lebih efisien untuk melakukan ini.

Tordin
sumber
Beberapa masalah DOD: 1. Menurunkan skala, pasti. Perhitungan mengenai posisi & rotasi hampir selalu tidak terpengaruh oleh skala, jadi itu akan cukup banyak tidak pernah digunakan, dan hanya mengambil ruang cache. 2. Saya juga kehilangan rotasi, dan menggantinya dengan kecepatan. Mobil dimaksudkan untuk bergerak lurus, tetapi kecepatannya pada akhirnya akan menentukan arahnya. Pengemudi menekan kelopak gas, tetapi fisika menggerakkan mobil. 3. Jangan mewarisi dari kelas untuk data jika Anda tidak berencana menggunakannya dalam hampir semua perhitungan, bersama-sama. 4. Bahkan di OOP, mobil tidak memperbarui satu sama lain. Gunakan fungsi gratis.
Gurgadurgen
Ini lebih merupakan contoh, bukan panduan utama. Anda tentu saja harus memilih fitt terbaik untuk implementasi Anda sendiri. (seperti yang dinyatakan)
Tordin
Contoh Anda adalah contoh abstraksi OOP standar, dan tidak banyak mengambil manfaat dari strategi DoD. DoD adalah tentang data, bukan tentang model. Fakta bahwa Anda bahkan memiliki objek "mobil" adalah hadiah mati bahwa ini bukan contoh DoD. Sebuah mobil cukup spesifik, dan DoD cenderung melakukan komposisi objek berbasis polimorfisme, bukan berbasis warisan. Jadi, misalnya, Anda mungkin memiliki objek yang menyimpan informasi yang diperlukan untuk transformasi tertentu, dan membuat array objek-objek itu, bukan objek dengan informasi untuk banyak transformasi.
Gurgadurgen