IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Développement 2D, 3D et Jeux Discussion :

[Architecture] - Interaction entre éléments


Sujet :

Développement 2D, 3D et Jeux

  1. #1
    Membre habitué Avatar de poussinphp
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    428
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 428
    Points : 176
    Points
    176
    Par défaut [Architecture] - Interaction entre éléments
    Bonjour,

    Je viens vers vous concernant l'architecture d'un jeu. Jusqu'à maintenant, j'avais pour habitude d'utiliser une architecture basé sur l'héritage et la décoration.

    Un object nommé "Component" contenait une base et d'autres classes "IDrawable", "IUpdatable".... venais s'ajouter. J'avais donc un objet "Entity" qui héritait de Component + IDrawable + IUpdatable.... et une class sprite qui héritait de Component avec sa gestion spécifique etc... Côté fonctionnenement, je parcourais les Entity via un foreach qui executait via polymorphisme "Update()", "Draw()".... ça marche pas trop mal mais je trouvais que ça cassais la notion Responsabilité. En effet, Un sprite avait donc le role de gerer les input, l'affichage, la physique etc...

    un exemple que j'ai pu trouve de ce qui ressemblait au mieux à ce que j'avais fais :
    Nom : CCSprite_diagram.jpg
Affichages : 277
Taille : 22,7 Ko
    Source : http://www.raywenderlich.com/24878/i...cture-in-games


    J'ai donc fais mes recherches sur le sujet et je suis tombé sur une autre façon de faire et qui, d'après ce que j'ai compris était réellement utilisé dans l'industrie. L'idée est de défini un object de base qui contiendrais une liste de composant (DrawComponent, InputComponent etc...).

    Voici à quoi ça pourrais ressembler :
    Nom : temp.gif
Affichages : 216
Taille : 26,9 Ko
    Source : http://www.quora.com/Are-dynamic-com...-game-industry

    Pour que le modèle fonctionne, l'objet de jeu contient une collection de composant sur lequel il s'abonne et chaque composant instancé à une référence sur son parent (objet de jeu). Il faut aussi que les composants puissent discuter. Pour ce faire, j'ai vu qu'il était possible de créer un système de message en interne permettant de communiquer.

    Exemple si dans composant, si je dois mettre à jour la position :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    composant :
    parentObject->SendMessage(MSG_MOVE, 1, 1);
     
    object :
    void SendMessage(MESSAGE_ID id, int a, int b)
    {
    //  pour chaque composant défini dans mon objet
     component->SendMessage(id, a, b);
    }
     
    composant position :
    void SendMessage(MESSAGE_ID id, int a, int b)
    {
    switch(id)
    {
     case MSG_MOVE:
     position->x += a;
     position->y += b;
    break;
    .....
    }
    }
    Meme si mon exemple n'est pas top car chaque message à ses paricularité et qu'il faudrait faire une classe de base message etc... l'idée est là.

    Cependant, dans ce cas de figure, je rencontre un soucis dans le cas suivant : Imaginons que le personnage s'approche d'un coffre et souhaite l'ouvrir. Le coffre est dans un autre objet et je pourrais lui envoyer un message "MSG_ACTION".

    De mon point de vue, je vois qu'une seule approche possible. Il faudrait que j'ai une référence de ma scene sur chaque objet de façon à pouvoir envoyer un message depuis un objet vers ma scene en disant "l'objet A a effectué une action" puis d'envoyer un message à tout les objets de la scene en disant "Une action a été effectué par A". Je ne la trouve pas pertinente car ça risque d'impacter les performances si j'ai beaucoup d'objets dans ma scene. De plus, il faudrait que j'envoi une référence de l'objet A et j'ai peur que ça casse le couplage.

    Que pensez-vous de ma seconde approche ? Comment puis-je informer depuis un objet A qu'une action a été faite et que l'objet B qui est le coffre près du personnage s'active mais pas tout les objets de la scène ?

    Disont que mon principal problème est le liens entre objets du jeu, j'ai du mal à concevoir comment interragir entre-eux.


    Merci par avance !

  2. #2
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 860
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 860
    Points : 219 062
    Points
    219 062
    Billets dans le blog
    120
    Par défaut
    Bonjour,

    Vous faites un ECS et je commençais à m'intéresser aussi à cette question (notamment à cause de Qt3D ).
    La solution que je pense la plus fiable :
    • le joueur envoie un message -> j'ai appuyé sur le bouton A (ou bouton d'action).
    • le message est d'abord reçu par Input qui traduira le bouton A en bouton associé à l'action "ouvrir coffre". Donc il renvoie un message : le joueur veut ouvrir un coffre. (cette étape est optionnelle à vrai dire).
    • le message est reçu par un Game/Scene. Son but sera de dire : "Ok, le joueur à voulu faire ça, mais est-ce vraiment possible pour lui ?". Une des étapes sera de vérifier dans la liste des "Ouvrable" s'il y en a un qui est valide pour le joueur et son action (s'il est assez proche, et si toute les autres règles sont respectés). Une fois que tout ça est validé, le Game/Scene peut faire : "Le joueur t'a ouvert" au coffre. Et on peut faire un autre message dans l'autre sens, genre : "Le coffre dépose des objets au sol"...



    Voilà ce que j'en pense. Je ne suis pas sur que ce soit le meilleur système.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  3. #3
    Expert confirmé Avatar de yildiz-online
    Homme Profil pro
    Architecte de domaine
    Inscrit en
    Octobre 2011
    Messages
    1 444
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Architecte de domaine

    Informations forums :
    Inscription : Octobre 2011
    Messages : 1 444
    Points : 4 563
    Points
    4 563
    Par défaut
    Pour ma part, j'utilise une système entièrement orienté action, une entité (un vaisseau dans mon jeu) est composé de modules, chaque module permettant de faire des actions(actives ou passives).

    lorsque le joueur clique droit sur un élément dans le monde, c'est la nature de cet élément (via polymorphisme) qui détermine quel type d'action est approprié(attaquer, atteindre destination, soigner, déployer,...) le module adhoc est donc interrogé et injecté dans l'action manager et agit suivant ses possibilités, ce faisant, il actionne sa matérialisation(qui est une modélisée via composition dans l'objet) et donc le rendu graphique, sonore, physique se fait, en boucle jusqu'à ce que l'action soit complète et retirée de l'action manager(ou remplacée par une autre ou annulée).

    C'est une architecture très évolutive, les comportements et le rendu sont totalement découplés des entités, l'inconvénient restant qu'une entité devient alors relativement anémique(mais je ne désespère pas de trouver une parade!).
    PXL le retro-gaming facile: Essayez-le

    Yildiz-Engine an open-source modular game engine: Website
    Yildiz-Online a 3D MMORTS in alpha: Facebook page / Youtube page

  4. #4
    Membre expert

    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Février 2006
    Messages
    1 031
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2006
    Messages : 1 031
    Points : 3 092
    Points
    3 092
    Par défaut
    C'est effectivement bien mieux ainsi et ce n'est pas propre au jeu vidéo, il faut toujours préférer la composition à l'héritage ( un géniallissime livre à ce sujet : http://www.amazon.fr/Design-patterns.../dp/2841773507 )

    Pour ton soucis de référence de scène :
    - soit tu peux avoir plusieurs scènes et dans ce cas oui il faut envoyer la référence de la scène à tous tes objets
    - soit il n'y en a qu'une et tu n'as aucune honte à en faire un singleton.

    Pour ton soucis de recherche d'objet :
    - en l'occurence sur le cas que tu présentes c'est au moteur physique qui fait du partitionnement d'espace d'envoyer l'information en premier : un trigger sur ton joueur, dès qu'il est assez proche du coffre tu récupères directement le coffre lui même.
    - Pour d'autres usages pouvoir classer les objets par type va accélérer les recherches ; et sinon il est possible de ne faire la recherche qu'au début du lancement du niveau et pas toutes les frames. ( exemple : ton joueur récupères les références vers tous les coffres du niveau )
    Suivez le développement de Chibis Bomba
    twitter : https://twitter.com/MoD_DiB
    DevBlog : http://moddib.blogspot.fr/

  5. #5
    Membre chevronné
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2007
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2007
    Messages : 677
    Points : 2 137
    Points
    2 137
    Par défaut
    Je plussoie la référence de MoDDiB. Quand j’ai ouvert pour la première fois ce livre j’ai eu un peu peur, il faut bien l’avouer ; beaucoup d’images, de l’humour à outrance, j’ai un peu douté du sérieux du bousin. Mais en fin de compte, je l’ai dévoré comme rarement j’ai dévoré un livre d’apprentissage, et j’ai appris (et retenu) beaucoup de choses.

    Seul inconvénient ; à l’époque où je cherchais ce bouquin il était déjà en rupture de stock, et j’ai dû me résoudre à prendre la version originale. A mon avis, dix ans après, la version française est collector.
    Le WIP de The last bastion, mon projet de jeu-vidéo (un TD en 3D)

    Mon portfolio / Ma page fb

  6. #6
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Hello,

    Citation Envoyé par poussinphp Voir le message
    Exemple si dans composant, si je dois mettre à jour la position
    Les composants ne font aucun traitements, les systèmes sont là pour ça.

    Une entité est un simple agrégat de composants. Il y à plusieurs façons de faire ça :
    Soit en disant qu'une entité possède des composants
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // une interface pour les composants
    struct IComponent { /*...*/ };
    struct ComponentA: IComponent { /*...*/ };
    struct ComponentB: IComponent { /*...*/ };
     
    struct Entity {
    	int id;
    	std::vector<IComponent*> components;
     
    	// ou
    	ComponentA *a;
    	ComponentB *b;
    };
    Soit en disant qu'un composant appartient à une entité
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // une interface pour les composants
    struct IComponent { /*...*/ };
    struct ComponentA: IComponent { /*...*/ };
    struct ComponentB: IComponent { /*...*/ };
     
    struct Entity {
    	int id;
    };
     
    std::unordered_map<Entity, ComponentA> as;
    std::unordered_map<Entity, ComponentB> bs;
     
    // peut être avantageusement remplacé par un bitset
    struct HasComponent {
    	bool hasA;
    	bool hasB;
    };
     
    // pour savoir quels composants une entité possède
    std::unordered_map<Entity, HasComponent> hasComponents;
    La 2ème solution à plusieurs avantages : les entités sont plus légères et peuvent être stockées et récupérées très facilement dans une DB (et peut améliorer la localité des données : un système travaillant sur des composants A et B aura la garantie que tous les As et tous les Bs soient proche en mémoire).

    Les composants, eux, indique une fonctionnalité ou un comportement particulier pour l'entité et possèdent simplement les "paramètres" de ces fonctionnalités.

    Pour qu'une entité soit déplaçable, il faut 2 choses : qu'elle ait une position et une vitesse. Ça fait 2 composants.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    struct Entity { int id; };
     
    const std::size_t nbComponents = 2;
    typedef std::bitset<nbComponents> mask_t;
     
    std::unordered_map<Entity, mask_t> hasComponent;
     
    struct IComponent {
    	virtual mask_t mask() const = 0;
    	virtual ~IComponent() {}
    };
     
    struct ComponentPosition : IComponent {
    	float x, y;
    	static const mask_t mask = 0;
    	mask_t mask() const { return mask; }
    };
     
    struct ComponentVelocity : IComponent {
    	float vx, vy;
    	static const mask_t mask = 1;
    	mask_t mask() const { return mask; }
    };
     
    std::unordered_map<Entity, ComponentPosition> positions;
    std::unordered_map<Entity, ComponentVelocity> velocities;
    Et enfin les systèmes, qui eux appliquent les traitements sur les entités qui possèdent les bons composants.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    struct ISystem {
    	virtual void update(float) = 0;
    	virtual ~ISystem() { }
    	virtual mask_t mask() const = 0;
     
    	virtual void add(Entity e) = 0;
    	virtual void remove(Entity e) = 0;
    };
     
    struct MoveSystem : ISystem {
    	// chaque systeme peut garder une copie des entités sur lequel il agit
    	// différents systemes ont différents prérequis pour l'ordre des entités
    	std::unordered_set<Entity> entities;
     
    	// le masque du systeme, pour vérifier facilement si une entité peut etre
    	// traitée par ce systeme ou pas
    	mask_t mask() const { return ComponentPosition::mask | ComponentVelocity::mask; }
     
    	void update(float dt) {
    		for(auto e: entities) {
    			auto & pos = positions[e];
    			auto & vel = velocities[e];
     
    			pos.x += vel.vx * dt;
    			pos.y += vel.vy * dt;
    		}
    	}	
     
    	void add(Entity e) {
    		// l'entité correspond, on peut l'ajouter
    		if((hasComponent[e] & mask()) == mask()) {
    			entities.insert(e);
    		}
    	}
     
    	void remove(Entity e) {
    		// l'entité ne correspond pas / plus, on peut l'enlever
    		if((hasComponent[e] & mask()) != mask()) {
    			entities.erase(e);
    		}
    	}
    };
    On peut appliquer la même logique pour le coffre, il peut par exemple posséder un composant "utilisable"; quand le coffre est utilisé, il perd ce composant et gagne un autre composant "utilisé par" pour être traité par un système différent.

Discussions similaires

  1. Réponses: 4
    Dernier message: 24/08/2011, 09h30
  2. Interaction entre éléments de formulaire
    Par BenoitDenis dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 31/03/2010, 15h24
  3. [VB .Net][Forms] Interaction entre deux forms
    Par plasticgoat dans le forum Windows Forms
    Réponses: 7
    Dernier message: 24/08/2005, 13h14
  4. [Collaboration/Interaction] Peut-on schématiser une interaction entre un bouton de commande et un autre objet ?
    Par manel007 dans le forum Autres Diagrammes
    Réponses: 5
    Dernier message: 21/09/2004, 01h01
  5. [Architecture] Interface entre C++ & Java
    Par yanis97 dans le forum Entrée/Sortie
    Réponses: 13
    Dernier message: 13/07/2004, 15h46

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo