Une n'y a pas UNE bonne manière faire de la conception objet.
C'est énormément fonction de ce que vous cherchez à faire.
Il est assez peu probable que l'objet "ascenseur" soit la bonne classe pour implémenter son affichage.
Dans votre simulateur d'ascenseur, l'ascenseur n'est pas là que pour afficher un ascenseur mais bien plus pour gérer son comportement.
Comme la manière d'afficher un ascenseur varie en fonction que la bibliothèque graphique (SFML, Qt, lib natives, console, etc...) et que le comportement de l'ascenseur ne varie pas en fonction de la bibliothèque graphique, autant ne pas mettre un le code d'affichage dans la classe "ascenseur".
Le plus simple, et le plus naturel pour une personne comme vous (et nous dans la majorité des cas), c'est de faire une fonction libre (dans aucune classe), qui prend en paramètre votre objet "ascenseur" et qui fait tout le sale boulot pour utiliser la bibliothèque graphique pour afficher un rectangle dans SFML pour afficher l'ascenseur.
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
ok je vois parceque j'ai choisi les rectangle pour representer l'ascenceur, la porte, les etages et du coup je me suis dis que je pouvais faire une classe pour chacun d'eux.
et pour commencer j'ai creer une etage comme ceci mais j'ai beaucoup d'erreur de compilation
#ifdef SFML_STATIC
#endif //SFML_STATIC
#include <SFML/Graphics.hpp>
using namespace sf;
class Etage
{
private:
int numero;
int posX;
int posY;
int largeur;
int hauteur;
int bordure;
public:
Etage(int=0, int=0, int=0, int=0, int=0, int=0);
~Etage();
sf::RectangleShape PB_Rect(int, int, int, int, int)
};
Etage::Etage(int num, int X, int Y, int l, int h, int bord)
{
numero = num;
posX = X;
posY = Y;
largeur = l;
hauteur = h;
bordure = bord;
cout<<"contruction de l'etage N°: "<<numero<<endl;
//on desine le rectangle
sf::RectangleShape rectangle(sf::Vector2f(largeur,hauteur));
//on donne une position
rectangle.setPosition(posX, posY);
//la couleur de rempplissage
rectangle.setFillColor(sf::Color(255,0,0,255));
rectangle.setOutlineColor(sf::Color::White);// Couleur de la bordure
rectangle.setOutlineThickness(bordure); // Epaisseur de la borrdure
}
Etage::~Etage()
{
}
Bon, vous n'avez clairement pas suivi mes conseils.
Je ne dis pas que vous allez vous prendre un mur, mais clairement, votre code ne résistera pas à des refactoring nécessaire à plus ou moins long terme.
Votre "Etage" n'a pas besoin, pour la simulation (à moins de simuler le monde des pixels, dans un univers 2D à discrétisation de coordonnée entière "équivalent à l'hypothétique distance de Plank" de "notre" univers, chelou), ni des coordonnées à l'écran (mais plutôt sa position dans l'univers de la simulation), ni la largeur et la hauteur sur l'écran (mais plutôt la largeur et la hauteur dans l'univers de la simulation), ni de sa bordure à l'écran.
Votre "Etage" ne devrait non plus gérer son numéro, c'est plutôt le rôle de l'immeuble.
etc...
Pour savoir quoi mettre dans votre classe "Etage", il faut savoir quels services il est sensé vous offrir dans la simulation.
Pour l'affichage des Etages :
void AfficherEtage(const Etage& etage)
{
int largeur = FacteurDEchelleSelonX(etage.largeur);
int hauteur= FacteurDEchelleSelonY(etage.hauteur);
sf::RectangleShape rectangle(sf::Vector2f(largeur,hauteur));
//on donne une position
int x{0};
int y{0};
std::tie(x,y) = TranslationSimulationToSceen(etage);
rectangle.setPosition(x, y);
//la couleur de rempplissage
rectangle.setFillColor(sf::Color(255,0,0,255));
rectangle.setOutlineColor(sf::Color::White);// Couleur de la bordure
rectangle.setOutlineThickness(CalculDeLaTailleDeLaBordurePourUneMeilleureVisibiliteEnFonctionDesReglagesGraphiquesDeLUtilisateur()); // Epaisseur de la borrdure
...
}
...
for(auto &etage : monImmeuble.Etages)
{
AfficherEtage(etage);
}
...
- Edité par bacelar 9 novembre 2018 à 16:48:07
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
De nombreux cours de POO mettent en avant l'encapsulation de données. C'est d'une connerie sans nom. Le principe N°1 de la POO c'est le service. Je fais une classe pour qu'elle ait un rôle dans mon programme (et un seul si je fais bien les choses). Comment la classe remplit le rôle, on s'en fout, l'essentiel est qu'elle le remplisse. Comme l'a très justement dit bacelar, ce n'est pas à ta classe Ascenceur de gérer son affichage, ça doit marcher aussi bien sur un moniteur de supervision à la résolution délirante que sur l'écran de mon vieux téléphone tout pourri.
bonjour les gars ce que vous ne comprenez pas c'est que je suis debutant avec la sfml et jedois faire ce programme graphiquement
et s'il vous plait si quelqu'un peut bien a partir du code que j'ai joins m'aider a tracer en exemple un rectangle avec la methode orientee objet, pour me mettre au pied
Ce que tu ne comprends pas, et c'est bien normal, c'est que ce n'est pas un niveau de "complexité" qui te bloque.
Ce que je propose, c'est justement de rendre ton système plus simple, en ne gérant qu'une chose à la fois.
On a tous tendance à prendre la première source d'information "compréhensible" comme parole d'évangile, mais ici vous appliquez trop à la lettre des préceptes qui se sont bien affinées au cours du temps.
Moi, je vous propose une chose : faire un ensemble de classe qui fonctionne correctement pour gérer les ascenseurs, et un "ensemble de classes" qui gère l'affichage des ascenseurs à l'écran.
Vous êtes capables, selon vous-même, d'afficher "un rectangle dans le main", vous avez donc assez de connaissance pour faire le "second ensemble de classe" : une simple fonction qui prend en paramètre un objet "ascenseur" et qui est capable de dessiner un rectangle à sa place.
Pour le premier ensemble de classe, c'est le cœur de projet autre que l'affichage, à vous de le faire. Mais affichage graphique ou pas, c'est la même chose.
Vous voulez tout faire en même temps, c'est peut-être gérable sur de tout petit projet, mais pourquoi faire mal un truc pour le rendre plus complexe ?
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
je comprends en effet comme vous dites j'ai toujours tendance a partir du premier comme si c'etait la fin. merci je vais appliquer votre conseil et je vous tiendrai au courant des evolutions. merci vraimment a vous
Il faudrait peut être reprendre toute la conception depuis le début
Voyons voir :
Nous avons la notion d'immeuble, au sujet de laquelle nous espérons pouvoir disposer des services suivants:
lui demander de combien d'étages il est composé
lui demander les informations relatives (altitude, hauteur "utile", auteur du vide technique) à un étage spécifique
lui demander sa superficie au sol (éventuellement sa longueur et sa largeur)
lui demander son adresse spécifique
lui demander sa hauteur totale
lui demander le nombre d'étage "sous-terrains" dont il est composé
Il y a d'autres services dont nous pourrions avoir besoin, mais nous allons déjà commencer par ceci, parce que nous nous rendons compte que nous avons besoin de deux notions supplémentaires, à savoir : la notion d'étage et la notion d'ascenseur.
Un étage, c'est --typiquement -- une superficie dans un plan horizontal, qui se trouve à une certaine distance (verticale) du sol, et qui dispose "d'un certaine espace" vertical (la "hauteur")
Le fait est que, a priori, tous les étages d'un immeuble présenteront exactement la même superficie (longueur et largeur) que l'immeuble, et la même hauteur disponible, à laquelle il faut ajouter l'éventuel "vide technique" qui prend place entre le plafond d'un étage et le sol de l'étage supérieur
Cette notion aura fondamentalement sémantique de valeur, et nous voudrons essentiellement lui poser trois questions particulières
quelle est ton altitude (par rapport au sol)?
quelle est ton hauteur utilisable (l'espace qui sépare le plancher du plafond)
quelle est la hauteur de ton "vide technique"?
Si bien que cette notion pourrait être représentée sous une forme proche de
class Floor{
public:
/* Dans bien des immeubles, la "hauteur disponible"
* d'un étage est d'environ 2.50 m et le vide technique
* est de 0.5 m j'utilise ces valeurs par défaut
*/
Floor(double altitude,
double height = 2.50,
double technical = 0.50): altitude_{altitude},
height_{height}
technical_{technical}{
}
double altitude() const {
return altitude_;
}
double height const{
return height_;
}
double technichalVoid () const{
return technical_;
}
double totalHeight() const{
return height_ + technical_;
}
private:
double altitude_;
double height_;
double technical_;
};
quant à la notion d'ascenseur, nous nous attendrons à disposer de quelques services sympa de sa part, à savoir être en mesure
de lui demander à quel étage il se trouve
de lui demander dans quelle direction il se déplace (vers le haut ou vers le bas)
de lui demander son status (en mouvement, portes ouvertes, en attente d'appel)
de lui demander l'étage le plus proche (par rapport à l'étage où il se trouve à un instant T) auquel on lui a demandé de s'arrêter, en tenant compte de son sens de déplacement (*)
Lui demander le temps restant avant qu'il n'atteigne le prochain étage auquel il passera (sans s'inquiéter de savoir s'il doit ou non s'y arrêter)
lui demander de s'arrêter à un étage donné (indépendamment de son sens de déplacement actuel)
lui demander s'il peut s'arrêter à un étage donné (**)
de lui demander quel est l'étage le plus haut auquel il a accès
de lui demander quel est l'étage le plus bas auquel il a accès
(**)Cette dernière question est importante, car plusieurs situations pourraient faire en sorte qu'un ascenseur donné ne puisse pas s'arrêter à un étage particulier. Par exemple, il se peut:
qu'il y ait une série d'ascenseurs qui désservent la première moitié de l'immeuble (des étages 0 à 45) et une autre qui désserve la seconde moitié des immeubles (des étages 40 à 90)
que certains étages "privatifs" ne soient accessible que par certains ascenseurs bien particuliers
va savoir ce qui pourrait arriver d'autre
Et, bien sur, il faudra un "gestionnaire des appels" (bien que j'ai horreur du terme "gestionnaire") de l'ascenceur qui s'occupera de gérer le fait que les gens puissent appeler un ascenseur quand ils se trouvent à un étage particulier (pour monter, ou pour descendre)
A priori, nous nous attendrons à pouvoir
appeler un ascenseur (depuis un étage donné pour aller dans une direction donnée)
l'interroger pour savoir si un ascenseur a été appelé (à un étage donné, pour aller dans une direction donnée)
de lui demander l'étage le plus proche (par rapport à l'étage où l'ascenseur se trouve à un instant T) auquel on a fait appel à l'ascenseur pour aller dans le même sens que l'ascenseur (*)
lui indiquer que l'ascenseur s'est arrêté à un étage donné lors de son déplacement dans une direction donnée (pour "annuler" l'appel correspondant éventuel)
(*) A priori, ces deux questions devraient permettre de déterminer à quel étage l'ascenseur devra s'arrêter en premier, en fonction de l'étage auquel il se trouve à un instant T et de son sens de déplacement
Cependant, toutes mes explications ont mis en évidence des notions purement business dont nous voudrons disposer, à savoir:
la direction du déplacement (vers le haut ou vers le bas)
la notion d'état de l'ascenseur (se déplace, porte ouverte, attend l'appel, avec une boucle entre se déplace et porte ouverte)
Nous devrions donc avoir des données basiques telles que
Accessoirement, nous pourrions envisager de définir une notion représentant un appel spécifique de l'ascenseur sous une forme proche de
struct LiftCall{
int floor;
MoveDirection direction;
};
Mais le fait est que cette notion est "typiquement interne" à la notion de gestionnaire des appels
Grace à cela, nous pourrons représenter le "gestionnaire d'appels" des ascenseurs sous une forme proche de
class LiftCallManager{
public:
/* il garder en mémoire le numéro
* de l'étage le plus bas et de l'étage le plus
* haut auquel on puisse faire appel à l'acscenseur
*/
LiftCallManager(int min, int max):min_{min},
max_{max}{
}
void call(int floor, MoveDirection dir){
/* il sera plus facile de traiter chaque direction de manière séparée
if(dir == toUpper)
callForUpper(floor);
else
callForDowner(floor);
}
int nearestFloor(int from, MoveDirection dir)const{
/* bien que la logique soit sensiblement identique
* il semble plus facile de traiter les deux
* directions possibles séparément
*/
if(dir == toUpper)
return nearestUpperFloor(from);
return nearestLowerFloor(from);
}
void liftStopped(int floor, MoveDirection dir);
bool liftCalled(int floor, MoveDirectionDir) const{
if(dir == toUpper)
return liftCalledForUpper(floor);
return liftCalledForDowner(floor);
}
private:
int min_;
int max_;
int nearestUpperFloor(int floor) const;
int nearestLowerFloor(int floor) const;
bool liftCalledForUpper(floor) const;
bool liftCalledForLower(floor) const;
void callForUpper(int floor);
void callForLower(int floor);
/* par facilité, il semble préférable de
* maintenir les appels "pour monter" et
* les appels "pour descendre" de manière séparée
*/
std::set<int> upperCalls_;
std::set<int> downerCalls_;
};
NOTA: le gros de la logique sera pris en charge par les fonctions privées... Comme il faut bien que tu aies quelque chose à faire, je te laisse réfléchir à leur implémentation
Je vais te laisser réfléchir un peut à la manière dont tu va implémenter la classe Lift (pour ascenseur) et la class Building (immeuble) sur base des services que j'ai exprimer plus haut (je ne vais pas tout faire pour toi, non plus :D)
Tu remarqueras que, bien que les différentes classes dont j'ai parlé aient régulièrement besoin d'informations accessibles depuis d'autres classes, elle devraient pour ainsi dire toutes pouvoir travailler de manière strictement indépendantes!
TIP : idéalement, la classe Lift devrait pouvoir émettre un signal de type "je suis arrivé à tel étage en me déplacant dans telle direction" auquel pourront se connecter ... tous les gestionnaires d'appels susceptibles de s'intéresser à un ascenseur particulier
De plus, toutes les classes dont j'ai parlé ici représentent des données strictement business (métier) : elles contiennent des informations "réelles".
L'affichage se fait de manière séparée, ne serait-ce que parce que tu as choisi d'utiliser SFML, alors que d'autres pourraient choisir d'utiliser Qt, OpenGL, DirectX ou encore vulain.
Si les deux premiers défis que je te lance sont d'implémenter la classe Lift et la classe Building sur base des informations que je t'ai fournies, le troisième défi sera de mettre en place "tout ce qu'il faut" pour pouvoir adapter les valeurs "réelles" aux besoins de ton affichage
Mais, a priori, tu disposera de "tout ce dont tu as besoin"
Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
bonjour, merci pour votre reponse M. koala01 , en effet je suis entrain de repasser en vue la modelisation de ce probleme, en tenant compte de vos propositions et je penses que dans votre reponse ya pas mal de choses qui m'echappaient ou que j'avais minimaliser et dont je devrais revoir, je reviens a vous tres bientot en attendant je dois relever le defis que vous m'avez lance ou du moins essayer , ca me mets vraimment au travail et j'aime ca .
pour ma position dans le projet, j'ai concu trois classes dont une pour la construction des etages, une pour le fonctionnement de l'ascenseur et l'autre pour lle personnage et entre temps c'est tout ca que je dois revoir en tenant compte de vos suggestions , mais je voudrais savoir si je pouvais gerer le fonctionnement de l'asssenceur donc les appels, et autres dans une classe autre que la classe ascenseur unpeu comme dans les collision ou on a une classe qui gere le personnage une classe qui gere parexemple le mur et une autre qui gere les collisions entre le personnage et les murs ?
On n'a pas tout le code (Classe Etage ? etc...) mais surtout, vous n'avez pas appliqué nos conseils.
Vous mélangez l'affichage et les règles "métier", ça rend le code peu claire, des valeurs magiques dans tous les coins, utilisation de VLA (n'existant pas en C++ standard et maintenant obsolète en C), de l'allocation dynamique en-veux-tu-en-voilà, de variables globales, etc...
Pour votre question de blocage, il vous dit quoi le débogueur, en pas à pas ?
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
EN effet ce sont ces trois fichiers la qui constituent le code , certains fichiers ont ete inclus juste pour des test et j'ai oublier de les retirer apres et le personnage est une sprite 4*4, la pluspart de mes images sont en .tga un format qui conserve la transparence et la plateforme ne supporte ces fichiers comment puis je vous faire part de ces dernieres?
pour la classe etages c'est juste un nom et il faut aussi comprendre mon code c'est de la jonglerie pure, mais en bref le probleme est au niveau de la definition de la trajectoire complete du personnage,
le programme compile et fonctionne bien mais concernant la methode que vous m'avez apprise je l'appliquerai en entrainnement pour bien comprendre car le temps
Vous ne nous avez pas suivi, votre code est compliqué, on va pas faire votre travail.
Utilisez le débogueur pour voir où votre code dysfonctionne.
Vous avez fait un très mauvais calcul avec votre "temps", maintenant, vous êtes en train de le perdre dans du déboguing. C'est le métier qui rentre : ne pas partir bille en tête.
Votre code ne compile pas avec un compilateur correctement configuré, on va pas niquer nos environnement juste parce que vous ne voulez pas utiliser un débogueur.
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
SFML et C++
× 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.
...