-J'instancie des entités de types différents, et j'utilise des fonctions virtuelles qui ont un coût à l'exécution et je me suis rendu compte que le seul moyen de réduire l'appel à des fonctions virtuelles c'est d'utiliser un design Entity/Component/System. (ECS)
Mais je n'aime pas cela, ça me semble très lourd à implémenter, il y a beaucoup de manières différentes d'implémenter cela et de plus, pour chaque entité il faut ajouter un composant par type de composant ce qui peut être lourd quand il y en a beaucoup ce qui est mon cas et quand un composant peut contenir d'autres composants. (Si j'ai plusieurs types d'entités qui sont Transformable et Drawable) je dois ajouter des composants de type drawable et transformable pour tous ces types d'entités si il y a deux/trois types ça passe encore mais si il y en a 1000 ça devient ingérable (c'est ce qu'il faut faire avec Unity), de plus il faut créer ses composants pour chaque instances.
De plus pour chaque système il faut vérifier si l'entité possède bien le (ou les) composant(s) nécessaire avant de les mettre à jour puisqu'il n'y a pas de types.
J'avais essayé de résoudre ce problème à l'aide du polymorphisme statique pour virer les appels aux fonctions virtuelles et utiliser un template variadique pour tout les types avec un ID pour la position du type dans le parameter pack et un vector pour chaque type mais je me retrouve avec le problème des parameter pack c'est à dire :
-Il faut passer tout les types au parameter pack, si il y en a quelque un, ça passe, mais si il y en a 1000, ça devient ingérable.
Ce que j'avais pensé faire c'est utiliser une classe qui génère elle même les types en compilation à passer au parameter pack, puisque de toute façon, à la compilation finale (lors de la génération de l'exécutable), je connais tout les types vu qu'il n'est pas possible de créer une nouvelle classe à l'exécution.
Mais ce n'est pas possible de faire ça en c++, par exemple, ce code ne compile pas :
J'ai vraiment du mal a comprendre ce que tu cherche a montrer ici...
Que le code que tu montre ne compile pas? Oui et? Que le C++ ne permet pas de faire une certaine chose? Dans ce cas il serait judicieux de mieux définir ce que tu cherches a obtenir. La mentalité j'ai essaye ça ne compile pas donc ce n'est pas possible me chiffonne un peu.
Par exemple a partir de ton code, j'ai pu faire ceci https://godbolt.org/z/YjdeMdcaG mais vu que je comprends mal ce que tu cherches a obtenir, impossible de savoir si c'est ce que tu veux ou non...
Si tu veux dynamiquement créer des classes et des méthodes lors de l'exécution, tu t'es trompé de langage.
Penche toi vers un langage interpreté si tu veux faire cela, ou l'exécution du code peut générer un nouveau code. (mais sache que très très tôt dans l'ère de l'informatique, on a vite séparé la partie code de la partie données car on se rendait compte que ça créait des complications phénoménales pour finalement pas trop de raisons valables).
Mais tu as un sacré soucis de méthodologie. J'espère qu'à un moment tu corrigeras ça.
> ce que je cherche à faire c'est quelque chose comme ceci : [...] Mais le problème ici c'est qu'il faut passer tout les types au holder, si il y en a quelques uns, ça va, mais si il y en a beaucoup, c'est lourd!!!
C'est toi qui a choisi de faire ça, et tu constates toi-même que l'idée est mauvaise. C'est pas la faute au langage (à qui on peut reprocher bien des choses par ailleurs).
Et si c'est la faute au langage, apprends-en un autre.
@fvritman très très tôt dans l'ère de l'informatique, on a vite séparé la partie code de la partie données car on se rendait compte que ça créait des complications phénoménales pour finalement pas trop de raisons valables
Affirmation discutable, très tôt dans l'informatique, LISP (1958) a montré qu'il était intéressant de pouvoir manipuler du code comme des données.
Ce code n'a absolument aucun sens en plus d'être comme à chacun de tes topics, ultra compliqué. Je t'invite fortement à lire certains projets opensource pour t'inspirer de choses plus simples.
Tu parle d'un système à entité et au final tu fais le gros classique du polymorphisme. Le but d'un ECS c'est justement d'éviter du polymorphisme et de l'héritage. Ce qui évite de faire des classes Oiseau, Humain, Dragon et ensuite une dernière classe OiseauHumainDragon qui hérite des trois précédentes.
Les templates sont aussi faites pour créer du code orthogonal « qui marche pour tout type distinct » pas pour savoir si une classe a une caractéristique. Certains le font et c'est ce qu'on appelait du SFINAE mais on évite autant que possible sauf cas de force majeur. Encore une fois dans ton cas c'est totalement useless. En plus on a les concepts maintenant.
- Edité par markand 5 juillet 2021 à 12:49:37
git is great because Linus did it, mercurial is better because he didn't.
Bon finalement j'ai réussi à faire ce que je voulais faire!
Là, je n'ai plus besoin de passer les types au holder donc je m'en fou si il y en a 1000 mais bon le chaînage de l'appel à la fonction add et le mot clé auto, ça va être compliqué d'implémenter cela dans une classe si je veux récupérer que les entités de la scène qui sont visible et aussi d'utiliser une boucle si je veux ajouter les entités au fur et à mesure.
C'est ça le problème du c++, pourtant cette solution est bien plus performante que les fonctions virtuelles et elle permet d'utiliser les avantages de l'héritage et la réutilisation données ou comportements similaire que l'on ne peux pas faire avec un système ECS.
Perso je ne comprends pas pourquoi tu veux essayer de stocker tous les types possibles et imaginables sous une même collection. C'est quoi le problème d'avoir une collection par type? Si je comprends bien ton projet consiste en un moteur de jeu. Si c'est bien ça tu dois savoir exactement quels types de données tu as besoin pour afficher ton model 3D sur l'écran. Pareil pour le son, tu dois savoir exactement de quel type représentera le concept de son, même l'extension du son change, la manière de jouer le son reste le même. Idem pour le moteur physique: tu dois savoir exactement quel type représente la position/rotation/... dans l'espace de ton objet. Au final tu auras certes un nombre important de types différents, mais ce nombre de type sera fini.
Tu crois qu'ils font comment chez Qt avec leurs 10000 classes?
Si c'est pour recoder un ECS comme le moteur de jeux Unity, je ne vois pas l'intérêt de faire un moteur de jeux, mais pour le polymorphisme statique, besoin de stocker tout les types, le c++ ne fourni aucun moyen de récupérer un type masqué en compilation sans utiliser de paramètres template. (hors on ne peut pas stocker des types différents dans un conteneur sans devoir utiliser un variant ou quelque chose du genre mais je pense pas que ça soit ce qui a de plus performant ça fonctionne un peu comme les fonctions virtuelles je crois)
En parlant de ECS je pensais en faire un mais plus évolué, du genre, en créant un conteneur par type de composant/d'entités et par type de systèmes et en le passant a plusieurs fonctions dans le coordinateurs et faire un genre à ceci :
int main(int argc, char* argv[]) {
EntityManagerArray ema;
auto em = ema.add(entity1).add(entity2).add(entity3);
ComponentManagerArray cma;
auto cm = cm.add(cm1).add(cm2).add(cm3);
EntitySystemArray esa;
auto es = esa.add(es1).add(es2).add(es3);
Coordinator c();
return c.exec(em, cm, es);
}
Comme ça si une entité, un composant ou un système, doit hériter des propriétés ou comportements d'un autre, je ne dois pas utiliser de fonctions virtuelles, ni dupliquer les propriétés ou les comportements avec une méthode clone ou je ne sais quoi d'autre.
J'ai trouvé un site qui parle justement d'un système ECS et il utilise une fonction virtuelle et une interface IComponentArray avec un système complexe pour mapper les ids des entités avec ceux des composants et une signature pour vérifier que les entités possèdent bien les types de composants requis pour pouvoir itérer sur les entités, bref, je n'ai strictement rien compris :
Je n'ai pas encore fait la fonction destroy par contre pour retiré une entité et un type qui n'est plus utilisé.
Ce qui aurait été bien c'est de pouvoir stocker le typeID de la variable, dans la classe Entity mais on ne peut pas le faire sans utiliser de paramètre template parce que on ne peut utiliser que des variables membres static constexpr size_t et donc elles doivent être initialisée au moment de la définition de la classe car on ne peut pas redéfinir un type en c++ parce que un type doit être constant en compilation, on ne peut pas le changer.
Et le RTTI, ou tout autre implémentation du même ordre (et il y en a un paquet), c'est du poulet.
Putain, @OmbreNoire, tu fais chier à dire autant de conneries.
D'après toi, l'interpréteur de ton langage "fétiche", il est écrit en quoi ? Bordel.
C'est pas parce que t'es pas débrouillard que les autres ne le sont pas. Et la plus belle fille du monde n'a qu'elle a offrir, et c'est déjà pas mal.
Tant que tu t'obstines à faire des jugements à l'emporte-pièce et que tu ne cherches pas à comprendre nos conseils (et des fois, on a l'impression que c'est fait exprès) t'avanceras pas.
On peut tout faire avec n'importe quel langage, c'est juste plus ou moins facile.
Sans objectifs précis, chiffrés, tu erreras comme un poulet décapité.
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
Ce qui aurait été bien c'est de pouvoir stocker le typeID de la variable, dans la classe Entity mais on ne peut pas le faire sans utiliser de paramètre template parce que on ne peut utiliser que des variables membres static constexpr size_t et donc elles doivent être initialisée au moment de la définition de la classe car on ne peut pas redéfinir un type en c++ parce que un type doit être constant en compilation, on ne peut pas le changer.
Il y a des moments où je te lis et j'ai l'impression de lire une page manuel de git tellement ça ne veut rien dire.
git is great because Linus did it, mercurial is better because he didn't.
Salut, RTTI ne permet pas de récupérer le type du pointeur en compilation, seulement à l'exécution.
Imagions ce cas-ci :
Je possède une classe transformable qui déplace des entités, remet à jour la transformation et appelle une méthode onMove définie dans une classe entity qui hérite de transformable, parce que je dois supposons remettre à jour des données comme la physique ou autre.
Cette même classe entity possède des entités enfants car on peut ça pourrait être une animation par exemple, ou un personnage contenant plusieurs animations.
J'ai trois classes (sphere, rectangle, convexshape) qui héritent de la classe entity.
Il y a un problème, on ne connaît pas le type des entités enfants dans la classe Entity, pour résoudre le problème.
Il y a deux solutions pour régler ce problème :
-On pourrait utiliser une fonction virtuelle mais ça a un surcoût à l'exécution et si l'entité possède beaucoup d'entités enfants comme une animation par exemple et qu'on la déplace souvent ce qui est le cas dans un jeux, c'est contre performant.
-On pourrait utiliser un système ECS mais dans ce cas là ça serait compliqué à gérer d'ailleurs je ne vois pas du tout comment faire. (Unity le fait mais je pense qu'il utilise un laguage interprété (le C#) donc c'est peut être plus simple à faire dans ce cas là)
On ne peut pas déclarer un EntityManager dans la classe Entity, car, les types des entités enfants peuvent être de n'importe quel type (si le personnage possède une arme par exemple ou des équipements.)
Il faudrait donc pouvoir faire quelque chose comme ceci :
struct entity {
auto children;
void addChild(Entity* entity) {
children = children.add(entity);
}
template<typename D>
void move() {
std::cout<<"move entity of instance : "<<id<<std::endl;
Transformable::move<D>();
children.move();
}
};
Rendre la classe Entity template poserait problème car le type du template ne peut pas changer dans la classe Entity.
De ce fait on est obligé d'utiliser une fonction template et de faire quelque chose comme ceci :
Ce qui est lourd, pour que ça soit performant il faut créer un contenaire EntityManagerArray qui contient tout les EntityManager de toutes les entités enfants pour chaque entité histoire de ne pas avoir à parcourir toutes les entités pour rechercher les entités enfants et les déplacer ce qui serait contre performant.
Hors que le compilateur pourrait redéduire le type de l'entity manager contenant les entités enfants.
Maintenant oui, en c++ on peut tout faire, mais, la manière de le faire est parfois bien compliquée.
Mais bon avec ce système, je bénéficie des avantages qu'offre l'héritage et un système ECS, en retirant les inconvénients. Le seul bémol est l'utilisation de la mémoire qui augmente un peu car ça occupe plus de place de créer un std::vector par type, plutôt qu'un std::vector pour tout les types à cause de la position du première élément pour chaque std::vector, mais bon, avec la taille des RAM de maintenant ça devrait passer.
Unity n'utilise pas de langage interprêté comme le C# pour son moteur. unity est codé en C++, en revanche, oui il utilise le C# (tout comme le javascript) comme langage de script mis a disposition a de l'utilisateur.
Edit : au temps pour moi, il utilise les deux, du C# et du C++ a priori.
C:\Users\Laurent\Windows\Demos\ODFAEGCREATOR\main.cpp|647|error: use of deleted function 'EntityManager<entity, convexshape*&>::EntityManager()'|
L'idée est de passer l'entity manager des entités enfants, ajouter l'entité enfant et retourner le nouveau type.
Je ne peux pas utiliser de référence ni de pointer sinon il me dit "auto must be followed by a simple declarator type".
Du coup il râle.
Si quelqu'un à une solution je suis preneur, j'aimerais même pouvoir stocker l'entity manager pour les entités enfants, dans la classe entity, mais je ne pense pas que cela soit possible.
N'en mais, depuis quand C# est un langage interprété ? Il se ne nomme comment cet "interpreter" ? "Le fantasme d'OmbreNoire" ? "La Vengeance du Poulet Masqué Décapité" ?
A part l'argument débile de "si c'est pour faire comme les autres, ça vaut pas la peine", pourquoi veux-tu faire cela ?
Donne nous un cas CONCRET d'utilisation de ton machin qui n'est pas avantageusement remplaçable par des mécanismes plus standards ?
Comme tu dis d'énormes conneries pour "invalider" les autres solutions, forcément "T'as raison".
Mais faut un peu se remettre en question de temps en temps.
>parce que je dois supposons remettre à jour des données comme la physique ou autre.
Bin non, il y a plein de moyens plus finauds que de bêtement tout recalculer sur un CPU pas fait pour ça. Tu les mets où les shaders dans ton usine à gaz ?
>Cette même classe entity possède des entités enfants car on peut ça pourrait être une animation par exemple, ou un personnage contenant plusieurs animations.
Mais on sent fout de ces relations enfants parents, dans les faits c'est juste un partage d'une matrice de base. Un simple bidule que les librairies graphiques collent dans un "state" à la con.
>Il y a un problème, on ne connaît pas le type des entités enfants dans la classe Entity,
Et tout ça à la compilation ??? C'est quoi ton univers ? Un endroit où rien ne change, une sphère restera une sphère jusqu'à la fin des temps ? Qu'elle se prenne une planète sur la tronche ou qu'elle est spaguetissée par un trou noir, c'est toujours une "sphère".
Non, "tout" n'est pas faisable ou pertinent à la compilation.
>Il y a deux solutions pour régler ce problème :
Débilité, oups sophisme habituel, "je connais tout sur tout et je peux donc évaluer de manière définitive tout sur tout".
Non, personne ne sait tout, et particulièrement toi, personnification du concept Dunning-Kruger.
C'est pour quand ton séjour dans la "vallée de l'humilité" ?
>On pourrait utiliser une fonction virtuelle mais ça a un surcoût à l'exécution
Peut-être, mais c'est peut-être acceptable, en fonction des contraintes et de la manière dont c'est implémenté et comment ça sera implémenté dans le futur.
Si sur une plateforme actuelle ou dans le futur, ou dans une situation donnée, l'approche "fonction virtuelle" est plus performante, tu fais quoi ? Tu recommences tout ?
Tu générales sans prendre la peine de restreindre les conclusions à tes connaissances actuelles (tu n'as pas, et nous non plus, la science infuse).
>On pourrait utiliser un système ECS mais dans ce cas là ça serait compliqué à gérer d'ailleurs je ne vois pas du tout comment faire
Renseignes-toi, BORDEL. Avant d'asséner tes conclusions débiles.
>Unity le fait mais je pense qu'il utilise un laguage interprété (le C#)
Sans commentaire, tant d'ignorance crasse.
Unity fonctionne sous iOS et Apple interdit l'exécution de bytecode. Tout le code IL de .NET est converti en CPP pour leur faire plaisir (IL2CPP).
Pas mal pour un langage pourri, LOL.
>Il faudrait donc pouvoir faire quelque chose comme ceci :
Non, mais, sérieux, t'as réfléchi 2 minutes avant de sortie une telle énormité ?
Non, c'est vrai, stocker la matrice de transformation pour que les mouvements soient relatifs au nœud parent, c'est trop "old school".
Quelles sont tes connaissances sur "l'état de l'art" des moteurs de jeu ? Parce que, pour faire mieux que les autres, faut au moins savoir ce que font les autres.
Ta solution, de ma fenêtre, c'est une réponse à un faux problème, à une question mal posée, c'est navrant.
P.S.: Comme les compositions des scènes ne doivent pas être dans le code (on recompile pas à chaque ajout/modification/suppression d'asset, et on ne demande pas à un Game Designer de toucher au code) mais dans des fichiers "fait pour", c'est quoi l'intérêt de ce machin au compile time ?
- Edité par bacelar 6 juillet 2021 à 13:02:43
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
Par contre, dans une fonction autre que la fonction qui la déclare, ça ne fonctionne plus parce que une fonction peut être appelée à l'exécution et donc dans ce cas là il râle parce que il ne connait pas le type en compilation du coup il met met cette erreur comme quoi le type est mal formé :
template <typename D, typename EntityManagerArray>
auto addChild(EntityManagerArray ema, D* entity) {
return ema.add(entity);
}
Je dois donc juste fournir tout les types dans une seule fonction et les passer à toutes les autres fonctions template, en fait c'est moi qui m'y prend mal.
Posez le besoin INITIAL avant de faire une usine à gaz.
C'est quoi votre besoin INITIAL (et pas "je veux pas faire comme les autres" SVP).
Je voudrais modifier le type de mes données à l'exécution et pas en compilation, mais je ne pense pas que c'est possible de faire cela en c++.
Y a t'il un autre langage qui permet de faire cela ?
Si par exemple je veux rajouter un type à un std::tuple mais à l'exécution.
le langage linotte possède cette fonctionnalité et le gaz m'a dit ceci :
Bonjour @Ornito ,
en effet, j'utilise le principe des prototypes pour attacher des méthodes aux instances des "objets" du langage. ça me permet d'ajouter des fonctionnalités au langage.
Mais j'ai l'impression que le langage est trop simple pour tes besoins ?
Mais le langage n'est pas assez poussé au niveau graphisme pour faire ce que je veux faire.
Posez le besoin INITIAL avant de faire une usine à gaz.
C'est quoi votre besoin INITIAL (et pas "je veux pas faire comme les autres" SVP).
Je voudrais modifier le type de mes données à l'exécution et pas en compilation, mais je ne pense pas que c'est possible de faire cela en c++.
Non "je voudrais modifier le type", c'est pas le besoin INITIAL. Je ne vois personne qui paierait 0,10 € pour avoir un programme qui modifie le type des données. Il faudrait un exemple _précis_ de situation où modifier le type de données (etc) serait _la_ solution à retenir.
Le problème XY est un problème de communication rencontré lors d'une demande d'assistance. La personne ayant un problème X imagine une solution Y, et au lieu de demander de l'aide pour X, cette personne demande de l'aide pour mettre en place la solution Y. Cependant, il arrive que résoudre le problème Y ne résolve que de manière partielle ou bancale le problème X. Ainsi, ne pas présenter le problème original et introduire un problème autre peut conduire à des difficultés de communication et à des solutions insatisfaisantes.
Ce problème est fréquemment rencontré par les centres et services d'assistance. L'utilisateur ayant déjà tenté de résoudre le problème X pense sa solution Y efficace mais n'arrive pas à la mettre en œuvre. L'incapacité de la structure d'assistance à résoudre le problème de base ou à en comprendre la nature conduit à des frustrations de l'utilisateur. La situation peut être découverte quand l'utilisateur pose des questions à propos de détails sans rapport avec le sujet. La solution pour les personnes chargées de l'assistance est de poser des questions sur ce qui motive la requête afin d'identifier le problème de base et de réorienter l'utilisateur vers la source réelle de ses ennuis.
Ici c'est encore mieux : l'utilisateur affirme simultanément
que Y est la solution à X
et que Y est impossible.
A part ça tout va bien ?
- Edité par michelbillaud 6 juillet 2021 à 15:42:27
>Je voudrais modifier le type de mes données à l'exécution et pas en compilation
Non, mais, tu rigoles ???
C'est quoi un constructeur d'une classe A qui prend une "référence gauche" sur une instance de classe B en paramètre dans la majorité des cas ?
Bon, @michelbillaud a bien résumé le problème, @OmbreNoire n'a toujours pas compris qu'il se pose un faux problème.
Quand on fait une scène avec des objets "hiérarchique", on ne modifie pas les coordonnées des enfants car ces coordonnées sont relatifs au référentiel que forme le nœud parent.
- Pas besoin de ce "move" à la con
- L'ensemble des changements de référentiel tout le long de l'arbre, ça se gère avec une simple pile de matrice
- les mécanismes d'optimisation de ce type de graphe sont légions (octree, etc...)
- ...
C'est quoi le VRAI besoin, putain !!
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
En fait je ne sais pas si vous avez remarqué mais on a absolument aucun effet sur YES, man. C'est à dire quoi qu'on dise il continue son roman. Un peu comme un stop pub sur une boite aux lettre de nos jours : inutile.
git is great because Linus did it, mercurial is better because he didn't.
En fait je ne sais pas si vous avez remarqué mais on a absolument aucun effet sur YES, man. C'est à dire quoi qu'on dise il continue son roman. Un peu comme un stop pub sur une boite aux lettre de nos jours : inutile.
Objection, dans mon village, les "stop pubs" sont plutôt bien respectés
Sinon, je partage totalement ton analyse. J'admire le temps et l'énergie (vaine) que met par exemple Bacelar pour lui répondre sur ce topic.
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
git is great because Linus did it, mercurial is better because he didn't.
git is great because Linus did it, mercurial is better because he didn't.
Eug
git is great because Linus did it, mercurial is better because he didn't.
git is great because Linus did it, mercurial is better because he didn't.
git is great because Linus did it, mercurial is better because he didn't.
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html