Exemple de conception orientée données


8

Je n'arrive pas à trouver une belle explication de la conception orientée données pour un jeu de zombie générique (ce n'est qu'un exemple, un exemple assez courant).

Pourriez-vous faire un exemple de la conception orientée données sur la création d'une classe zombie générique? Est-ce que ce qui suit est bon?

Classe de liste de zombies:

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
}

Exemple:

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
}

Ou serait la création d' un conteneur du monde générique qui contient toutes les actions de bite(zombieId, playerId)la moveTo(playerId, vector)à createPlayer()la shoot(playerId, vector)à face(radians)/face(vector); et contient:

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

être un bon exemple?

Quelle est la bonne façon d'organiser un jeu avec DOD?

Réponses:


11

Il n'y a pas de "jeu avec DOD". Premièrement, ce mot à la mode est un peu flou, car chaque système est conçu orienté données. Chaque programme fonctionne sur un ensemble de données et y apporte certaines transformations. Impossible de le faire sans orienter le design vers les données. Il n'est donc pas mutuellement exclusif avec une conception «normale», mais ajoute des contraintes dans la disposition de la mémoire et la façon dont la mémoire est accessible respectivement.

L'idée derrière DOD est de regrouper et de regrouper les données appartenant à une fonctionnalité plus près les unes des autres dans un bloc de mémoire continu, afin d'avoir moins de ratés de cache, de se débarrasser des fonctions virtuelles et des tables virtuelles, une parallélisation plus facile, aucun accès aléatoire (ou minimal) à la mémoire et pour écrire du code pour des processeurs hautement optimisés comme les SPU de Cell dans la PS3 avec ses ressources mémoire limitées, optimisant l'accès à la mémoire et les DMA vers et depuis sa mémoire principale.

Cela ne signifie pas simplement de tout changer de "Array-of-Structures" (AoS) à "Structure of Arrays" (SoA) comme indiqué dans les exemples ici. Cela peut également signifier mélanger les deux et entrelacer et empaqueter des données appartenant à une fonctionnalité étroitement ensemble, comme par exemple la "position" et la "vitesse" pour éviter de sauter en mémoire pour l'intégration de la position.

Cependant, les systèmes DOD purs sont très difficiles à implémenter, car chaque accès au pointeur est une violation de ce concept pur , car vous n'accédez plus à un bloc de mémoire continu, mais effectuez des accès aléatoires à la mémoire en déréférençant un pointeur. Ceci est particulièrement important pour écrire du code pour le SPU lors du déplacement, par exemple, d'un système de particules du CPU vers le SPU, mais dans le développement de jeu quotidien normal, ce n'est pas important. C'est un moyen d'optimiser la sous-fonctionnalité, pas d'écrire des jeux avec elle (pour l'instant, comme l'explique l'article de Noels).

Mike Acton d'Insomniac Games a beaucoup de matériel intéressant sur ce sujet, vous pouvez trouver certains de ses trucs ici ainsi que les articles de Noel , tous deux fortement recommandés.


Une chose que j'aimerais ajouter à cette réponse: DOD n'est pas TOUT sur les systèmes SoA. Bien que les structures SoA fonctionnent généralement mieux pour DOD, elles ne correspondent pas toujours au concept DOD réel. Le concept derrière DOD est simplement l'idée que vous concevez le code autour des données, et non l'inverse, qui est la méthode habituelle.
Gurgadurgen

0

Je cherchais également un bon exemple de cela, mais avec des ressources limitées sur le net et personne pour me dire comment le faire correctement, je l'ai fait avec l'implémentation suivante. (ce n'est peut-être pas le meilleur, mais cela suit l'idée de base)

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

Donc l'implémentation est plus ou moins comme ceci: vous avez une classe d'objets de base, qui contient toutes les données communes. Lorsque votre classe de voiture est construite, vous spécifiez la quantité de données que vous souhaitez mettre en commun et disposez donc de suffisamment de mémoire pour tous les objets.

à partir de là, vous pouvez ajouter des identifiants ou tout ce qui vous semble nécessaire pour votre implémentation. mais j'ai essayé cela sur un jeu plus simple, et cela a fonctionné assez bien.

Ce n'est pas loin de votre conception non plus, et franchement, je ne connais pas de moyen plus efficace de le faire.


Quelques problèmes DOD: 1. Perdez l'échelle, c'est sûr. Les calculs concernant la position et la rotation ne sont pratiquement pas affectés par l'échelle, de sorte qu'il ne sera pratiquement jamais utilisé et prendra simplement de l'espace dans le cache. 2. Je perdrais également la rotation et la remplacerais par la vitesse. Une voiture est destinée à se déplacer tout droit, mais sa vitesse déterminera finalement sa direction. Le conducteur appuie sur le pétale de gaz, mais la physique déplace la voiture. 3. N'héritez pas des classes pour les données si vous ne prévoyez pas de les utiliser ensemble dans presque tous les calculs. 4. Même dans la POO, les voitures ne se mettent pas à jour. Utilisez des fonctions gratuites.
Gurgadurgen

C'est plus un exemple, pas un guide ultime. vous devez bien sûr choisir le meilleur ajustement pour votre propre mise en œuvre. (comme il est indiqué)
Tordin

Votre exemple est un exemple d'abstraction OOP standard, et tire peu ou pas du tout des stratégies DoD. Le DoD concerne les données, pas le modèle. Le fait que vous ayez même un objet "voiture" est un signe mort que ce n'est pas vraiment un exemple de DoD. Une voiture est assez spécifique, et le DoD a tendance à faire une composition d'objet basée sur l'existence et un polymorphisme, plutôt que sur l'héritage. Ainsi, par exemple, vous pouvez avoir un objet contenant des informations requises pour une transformation spécifique et créer un tableau de ces objets, au lieu d'un objet contenant des informations pour plusieurs transformations.
Gurgadurgen
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.