Questions conceptuelles, organiser mon moteur de jeu

Réalisation d'un moteur de jeu dans une optique d'apprentissage

a marqué ce sujet comme résolu.

Bonsoir :)

J’ai récemment débuté un projet de moteur de jeu 2D utilisant la librairie SFML dans l’optique de m’améliorer dans ce langage et dans la conception 2D. Je n’ai pas de réels soucis techniques pour le moment mais, au fil de l’avancement du projet je me rends compte que je ne sais pas vraiment comment je devrais organiser mon projet et hiérarchiser mes différentes classes.

Plus précisément, j’ai l’infime conviction de bafouer moult règles de la programmation orientée objet et si je souhaite que mon moteur soit réutilisable et un minimum décent cela ne sera pas tenable sur le long terme.

Voici donc les questions conceptuelles (mais pas seulement) que je me pose :

1) J’ai conçu une classe TileMap, qui hérite d’une classe Map. Au début, j’étais parti sur une utilisation d’un std::vector à 2 dimensions, néanmoins j’ai lu dans un livre qu’il était préférable de travailler en interne sur un objet matriciel à une dimension et ainsi linéariser le tableau 2D.

J’ai alors une architecture proche de :

class TileMap : public Map{
public:
TileMap(SpriteSheet const& spriteSheet, std::vector<std::vector<int>> mapVector); // L'un des constructeur de ma classe TileMap

private:
   SpriteSheet spriteSheet_{};
   Matrix mapMatrix_ {};
};

Puis lors dans le corps de ce constructeur je remplis ma matrice avec les éléments du std::vector passé en paramètre.

Je me demande si il est logique de procéder ainsi ou si il serait préférable de forcer l’utilisateur à utiliser lui-même un objet de type Matrix lors de l’utilisation de la classe TileMap ? Le principe de Demeter ne le permettrait à priori pas ?

2) Toujours dans cette classe TileMap, j’ai rencontré la problématique suivante : où la logique (j’entends ce qui touche aux collisions de tuiles) devrait-elle se trouver ? Qu’est-ce qui devrait gérer tout cela ?

Pour le moment ma class TileMap propose de nombreuses méthodes telles que

makeSolid(int value);

qui prend en argument un entier censé représenter la valeur de la tile dans la TileMap et qui ajoute cet entier à un tableau qui liste toutes les tiles solides. Une telle méthode a-t-elle sa place ici ? J’ai de plus des méthodes qui me semblent pas mal alourdir ma classe telles que isSolid(Vector2u const& index) qui renvoie un bool si la position en indice (en terme de tiles, (1,1) étant la toute première à l’écran) est solide.

2) - Suite - J’ai une fonction dans un fichier totalement à part nommé collision.hpp

template<typename T>
bool collisionSolid(T const& A, TileMap const& map);

Qui grossièrement me dit si mon objet de type T touche une tuile solide.

De nombreuses autres fonctions sont présentes dans ce fichier comme des tests de collision avec les bordures d’un objet Window en argument, ou des tests de collisions avec la méthode des boites englobantes.

Est-ce la bonne façon de procéder ?

3) (Dernière question promis :ange: ) Je me demande si il serait judicieux de concevoir une classe abstraite PhysicEntity avec en attributs une masse, une vitesse etc, et dont hériteront les principaux objets sur lesquels je pourrai tester des collisions et appliquer des lois physiques plus tard avec une autre classe Physic. Cette idée serait-t-elle viable sur le long terme ?

Je me demande aussi si il est logique qu’un Sprite hérite directement de PhysicEntity ?

De plus, je pourrais dans une telle situation songer à modifier mes fonctions de tests de collision, par exemple :

bool collisionSolid(PhysicEntity*  A, TileMap const& map);

Voilà voilà, désolé pour la longueur du message et un grand merci à ceux qui m’auront lu jusqu’au bout,

Bonne soirée à tous/toutes :)

+0 -0

Salut ! :)

Je ne suis clairement pas un expert dans le domaine, je te donne juste de mon avis basé sur des expériences personnelles et des codes de jeu réalisé par d’autres développeurs !

1) Je pense que tu devrais avoir un générateur de sprites qui te permettrait d’avoir la certitude de ne charger qu’une seule fois chaque sprite.

Et dans ta classe TileMap, d’avoir une référence constante vers ce SpriteSheet. Je ne vois pas l’intérêt de les stocker par copie non constante.

Mais sinon oui, l’utilisation d’une matrice à une dimension est bien plus facile à utiliser que le vector de vector. :)

2) Peut être penser à l’utilisation d’une struct Tile avec deux variables : un entier identifiant qui représente le sprite et un booléen qui représente l’état de la tuile.

Ta matrice, c’est juste une matrice d’entier ?

2’) Dans la plupart des codes que j’ai déjà pu voir, les collisions en 2D sont souvent gérées à partir d’un gestionnaire de physique 2D (donc comme tu l’as fait :))

Pour t’inspirer : https://github.com/DigitalPulseSoftware/NazaraEngine/tree/master/src/Nazara/Physics2D

3) Oui c’est exactement ce qu’il faut faire. :)

Une nouvelle fois, ne prend pas comme acquis mes réponses, et attend peut être des avis de gens plus expérimentés. :)

+0 -0

Salut merci beaucoup pour ta réponse détaillée. Concernant ma matrice, c’est une classe template en fait mais en interne attribut de ma classe TileMap j’utilise une matrice d’entiers.

En tout cas ta réponse éclaire plusieurs points et je vais m’inspirer grandement des codes de Nazara dont j’ai déjà entendu parler, merci encore :)

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte