Partage
  • Partager sur Facebook
  • Partager sur Twitter

Bomberman

Prologue

Sujet résolu
    15 juillet 2010 à 17:06:49

    :D Bonjour tout le monde,

    comme indiqué dans le titre, je veux faire un bomberman en Python, une fois les tutoriels [Python/Pygame] finient. J'ai donc décidé de m'avancer en créant le cahier des charges, les diférentes fonctions présentes ainsi qu'un pseudo-Code.

    Je voulais juste vous demander quelque conseils au niveau des fonctions à incorporer, la façon de faire, comment s'y prendre etc etc...

    1) Le cahier des charges:



    - Ce que le joueur peut ou doit faire:



    * Ne rien faire
    * Marcher sur des case vides ou sur des Powers Up
    * Aller sur la même case qu'un autre joueur
    * Poser une ou plusieurs bombes (Une bombe est posée sur soi)
    * Se suicider avec un bombe
    * Editer/créer des map


    - Ce que les bombes peuvent/doivent faire:



    * Exploser au bout de X secondes
    * Peuvent provoquer une réaction en chaîne (s'il y a plusieurs bombes à coter par exemple)
    * Tuer un ou plusieurs joueurs
    * Casser des murs "cassable"


    - Ce que le joueur ne peut pas faire:



    * Sortir de la carte
    * Traverser des obstacles
    * Poser une bombe s'il n'en a pas ou pas assez
    * Marcher sur une bombe déjà existente
    * Avoir plus d'un "bonus" en même temps (vitesse, poison...)
    * Poser plusieurs bombes sur une même case
    * Jouer une fois mort


    - Ce que les bombes ne peuvent pas faire:



    * Exploser des murs incassable
    * Etre traversable


    - Environnement:



    * Système de score en 5 parties ou plus
    * Présence d'un temps (une partie = 3 minutes)
    * Présence du nombre de bombes et de puissances
    * Présence de "bonus"
    * Editeur de map


    Une partie est gagnée lorsque qu' il ne reste plus qu'un joueur ou bien si le temps est écoulé.
    Une partie = 4-3 joueurs, sur 3 minutes

    Dans un premier temps: Une partie = 1 joueur pour les teste, puis deux joueurs, et ensuite implémentation des IA (Si ce n'est pas trop trop dure)


    2) Les diférentes fonctions & classes:



    - deplacementJoueur:
    - reperageElements : Repère la position des éléments sur la carte (Joueurs, murs ...)
    - colisionJoueurs : Regarde s'il y a colision des joueurs sur les éléments
    - poserBombes : Permet de voir suivant les variables si on peut poser des bombes
    - puissanceBombes : Verifie la puissance des bombes suivant les Power-Up prit
    - colisionBombes : Regarde si une bombe touche un mur cassable ou non, + joueurs
    - directionJoueur :
    - chargerCarte :
    - saveCarte :
    - editeurDeNiveau :
    - intelArtifi(IA) :
    - gestionScore :

    Classes:


    - joueur
    - mur
    - bombe
    - flamme
    - bonus
    - mur


    Voici les fonctions principales, bien entendu ce n'est pas encore complet, j'en rajouterais au fur et à mesure que je/vous les trouverai/rez.


    3) Pseudo-Code



    Ce n'est pas ma priorité (pour l'instant), je le commencerai une fois que j'aurais terminé le cahier des charges & si il y a des fonctions qui me vienne à l'esprit (Ou bien demain :D ).


    Questions:

    Manque t'il quelquechose au cahier des charges ?
    Avez-vous des fonctions que j'ai oublié qui vous vienne à l'esprit ?

    Comment implémenter un tel jeu ?
    Est-ce si difficile que ça ?


    Merci :)



    • Partager sur Facebook
    • Partager sur Twitter
      15 juillet 2010 à 21:24:48

      Une question que tu pourrais aborder dans ton cahier de charges serait l'utilisation de python pour faire ce jeu.

      Pour les fonctions il y a

      DessinerGrid(grid)
      Grid serait une classe qui contiendrait tous les obstacles ainsi que le joueur (sa position).

      J'avais fait un jeu avec un système de grid ça fait quand même assez longtemps avec SDL en C++ bordélique.
      http://www.youtube.com/watch?v=rGP1IVkI6og

      La plus dure partie était les collisions ainsi que la structure générale du programme. Un conseil: les variables globales sont le mal! Évites les quand c'est possible. :)
      • Partager sur Facebook
      • Partager sur Twitter
        15 juillet 2010 à 21:38:35

        Tout dabord merci pour ta réponse, ça fait plaisir :) .

        Je n'ai pas encore vu les classes mais j'ai regardé ce que c'était en c++ tout à l'heure. (parce que j'avais déjà fait du C avant d'attaquer Python :p )
        En tout cas je prends note pour la class 'grid'.

        Je pense aussi faire une class 'personnage' voir même une class 'bombe' mais je m'avance beaucoup en disant cela. J'attends avec impatience la suite du/des tutoriel(s) Python, plus précisement sur les 'class'.

        J'espère ne pas trop m'embêter avec les colisions *Siflote* ... sachant que ça va être très dure. :-°
        • Partager sur Facebook
        • Partager sur Twitter
          15 juillet 2010 à 21:59:04

          Citation : realmagma

          Tout dabord merci pour ta réponse, ça fait plaisir :) .

          Je n'ai pas encore vu les classes mais j'ai regardé ce que c'était en c++ tout à l'heure. (parce que j'avais déjà fait du C avant d'attaquer Python :p )
          En tout cas je prends note pour la class 'grid'.

          Je pense aussi faire une class 'personnage' voir même une class 'bombe' mais je m'avance beaucoup en disant cela. J'attends avec impatience la suite du/des tutoriel(s) Python, plus précisement sur les 'class'.

          J'espère ne pas trop m'embêter avec les colisions *Siflote* ... sachant que ça va être très dure. :-°


          Si tu as fait le TP du Sokoban en C (vu que tu as fait du C :p ), ou si tu ne l'as pas fait tu peux regarder la correction, ça t'aidera pour les collision vu que tout comme bomberman, c'est du déplacement case par case.
          • Partager sur Facebook
          • Partager sur Twitter
            15 juillet 2010 à 22:13:26

            Je me suis déjà inspiré du sokoban pour mes fonctions, et je compte bien faire de même pour les colisions ;) .

            Ce qui me fait peur, se sont les classes.
            Par exemple il y avait une question qui portait sur le terme 'self' dans un des topic sur le langage Python. J'ai lu les explications mais je n'ai toujours rien compris :D.

            De plus, cette histoire de tout englober, séparer en private, public etc me fait vrément peur.
            Après la lecture du chapitre sur les classes en C++ j'étais un peu comme ça :waw: (Je tiens à préciser que se sont les seuls chapitres C++ que j'ai lu).
            • Partager sur Facebook
            • Partager sur Twitter
              15 juillet 2010 à 22:43:07

              Si tu cherches à en apprendre plus sur les classes en Python, regarde le tuto de Swinnen sur developpez.com ainsi que le tuto officiel de Python (quand je dis « officiel » c'est par rapport à la Python Software Foundation, pas au SdZ). Le premier n'est pas forcément très très accessible, le deuxième est désorganisé, laconique et en anglais. Mais en utilisant les deux à la fois, tu devrais t'en sortir. ;)

              Je n'ai abordé les classes que très récemment, mais il me semble bien qu'il n'y a aucune histoire de séparation entre private et public en Python. Tu as juste les variables globales et celles dont la portée est locale, et prolixe aborde ce sujet dans ce chapitre. :)

              Quant à self, c'est juste un paramètre envoyé par défaut à chaque méthode de classe, afin qu'elle puisse manipuler les attributs (les variables) de sa classe. Enfin rien de compliqué, ne t'inquiète pas.

              Au fait, dans ton Bomberman il n'y a aucun ennemi : le joueur doit-il absolument affronter d'autres joueurs humains ?

              Bonne chance !
              • Partager sur Facebook
              • Partager sur Twitter
                16 juillet 2010 à 8:42:39

                @Rastagong:

                Merci de m'avoir répondu toi aussi (ainsi que les autres ;) ). Pour ce qui est du Private/public c'est en C++ et en Java, j'ai donc pensé qu'il y en avait en Python.
                Comme tu l'as dit prédédement il n'y en a pas en Python (ouf?) ce qui me remonte le morale.

                Je vais lire les deux tutoriels que tu m'as donné, et attaquer les nouveaux chapitres ajoutés que je n'avais pas vu sur le SDZ :-°
                Quant a 'self', que se passe t'il s'il on l'omet ? Pourra t'on toujours manipuler les attributs ?

                Pour en revenir au bomberman :D , au départ je vais commencer par un joueur tout seul, pour faire des teste ect, ensuite à deux joueurs sur un même ordinateur, et pour finir 1 et/ou deux humains + des IA dont je ne sais absolument pas comment les programmer, mais ça viendra (etant le dernier de mes soucis en ce moment)


                Merci.
                • Partager sur Facebook
                • Partager sur Twitter
                  16 juillet 2010 à 11:44:14

                  Merci pour tous vos liens, avec ça j'ai de quoi faire ;) .

                  Voici un aperçu de mes sprites crée par moi même pixels par pixels sous paint ! ;) (Je suis très nul en dessin, donc aucuns commentaires là-dessus :p )
                  J'ai juste copier/coller les sprites sous paint pour voir comment ça serai, au niveau du rendu sous en pygame.


                  Image utilisateur

                  Si vous ne voyez pas l'image voici le lien directe:


                  Qu'en pensez-vous ?
                  • Partager sur Facebook
                  • Partager sur Twitter
                    16 juillet 2010 à 16:34:44

                    C'est un jpeg que tu montres donc la qualité de l'image est très médiocre. Essaies d'utiliser .png.

                    Pour ce qui est des tiles, c'est correct pour de l'art de programmeur. XD
                    • Partager sur Facebook
                    • Partager sur Twitter
                      21 juillet 2010 à 1:22:19

                      Bonsoir,

                      Héhé, mais c'est cool, je suis aussi en train de coder un bomberman mais j'ai pas le cahier des charges :-°
                      Je vais pouvoir m'inspirer du tien, si tu n'y vois pas d'inconvénient
                      ;)

                      Quelques conseils:
                      - Ne te lances pas dans la création d'un jeu sans savoir utiliser les classes, ton code n'en sera que bordélique (je me rappelle de mon snake, premier jeu que j'ai fait en python, c'est pas fameux :euh: )
                      - Divises bien chaque chose en objet, je te proposes quelques classes (celles que j'ai déjà codé):
                      - joueur
                      - mur
                      - bombe
                      - flamme
                      - bonus
                      - mur

                      Après avec l'héritage tu peux faire plusieurs types de mur avec différentes caractéristiques facilement.

                      Ensuite l'idée, que des joueurs puissent se marcher dessus me paraît bizarre :-°
                      Tu peux rajouter dans ton cahier des charges, que les flammes ne doivent pas traverser plusieurs murs cassables.
                      Un truc qui peut être sympa, serait de pouvoir avoir un bonus et un malus en même temps.

                      Pour l'IA, j'ai trouvé ce tuto qui a l'air plutôt intéressant. Mais le bot est bien la dernière chose à faire, dans ton cahier des charges.

                      Voilou, bonne soirée et bonne continuation ;)
                      • Partager sur Facebook
                      • Partager sur Twitter
                        21 juillet 2010 à 2:48:09

                        Salut.

                        Tu sembles faire une sorte de complexe sur les classes à créer parce que tu débutes dans la POO.

                        Pour t'aider (sans te rediriger vers des tutos que tu devras lire de toute façon), voici quelques conseils :

                        une classe, c'est un type d'objets qui a des responsabilités et un état.

                        L'état est en général donné par ses attributs (ses "variables"), et ses responsabilités remplies par des actions qui sont effectués au moyenvde méthodes (ses "fonctions").

                        Un moyen très efficace de savoir comment découper tes classes est de procéder à une analyse textuelle.

                        Par exemple :
                        "je dois implémenter une chattière automatique qui fonctionne de la manière suivante :
                        mon chat
                        miaule, la chattière s'ouvre, mon chat sort pour aller faire ses besoins

                        Les noms redondants (que j'ai mis en gras) correspondent en général à des classes différentes, et les verbes (en vert) sont leurs méthodes.

                        En procédant ainsi, tu es à peu près sûr d'avoir une conception qui tient la route, quitte à l'améliorer avec l'expérience.
                        • Partager sur Facebook
                        • Partager sur Twitter
                        Zeste de Savoir, le site qui en a dans le citron !
                          21 juillet 2010 à 15:11:48

                          Citation : W3YZOH0RTH

                          Bonsoir,

                          Héhé, mais c'est cool, je suis aussi en train de coder un bomberman mais j'ai pas le cahier des charges :-°
                          Je vais pouvoir m'inspirer du tien, si tu n'y vois pas d'inconvénient



                          Aucun problème, si mon post peut servir à d'autres :).
                          J'ai aussi rajouter les classes dans mon premier post et regardé ton lien qui est pas mal.

                          Citation : NoHaR

                          Salut.

                          Tu sembles faire une sorte de complexe sur les classes à créer parce que tu débutes dans la POO.

                          Pour t'aider (sans te rediriger vers des tutos que tu devras lire de toute façon), voici quelques conseils :

                          une classe, c'est un type d'objets qui a des responsabilités et un état.

                          L'état est en général donné par ses attributs (ses "variables"), et ses responsabilités remplies par des actions qui sont effectués au moyenvde méthodes (ses "fonctions").

                          Un moyen très efficace de savoir comment découper tes classes est de procéder à une analyse textuelle.

                          Par exemple :
                          "je dois implémenter une chattière automatique qui fonctionne de la manière suivante :
                          mon chat
                          miaule, la chattière s'ouvre, mon chat sort pour aller faire ses besoins

                          Les noms redondants (que j'ai mis en gras) correspondent en général à des classes différentes, et les verbes (en vert) sont leurs méthodes.

                          En procédant ainsi, tu es à peu près sûr d'avoir une conception qui tient la route, quitte à l'améliorer avec l'expérience.




                          Pas mal la technique, je m'en souviendrai, soyez en sûr :D .

                          Le tutoriel sur python (non-officiel) parle des classes, je n'ai pas compris à quoi servent les accesseurs et les mutateurs. (Les exemples ne sont pas faciles à comprendre non plus :-° )Je vais donc lire et re-lire ce chapitre jusqu'a ce qu'il soit acquis.

                          Encore merci à vous de prendre un peu de votre temps pour m'aider. :)
                          • Partager sur Facebook
                          • Partager sur Twitter
                            21 juillet 2010 à 19:11:34

                            Citation : realmagma

                            Le tutoriel sur python (non-officiel) parle des classes, je n'ai pas compris à quoi servent les accesseurs et les mutateurs. (Les exemples ne sont pas faciles à comprendre non plus :-° )Je vais donc lire et re-lire ce chapitre jusqu'a ce qu'il soit acquis.

                            Encore merci à vous de prendre un peu de votre temps pour m'aider. :)


                            Un accesseur est tout simplement une méthode (fonction spécifique à un objet) qui te permet d'accéder à un attribut de l'objet (variable contenue dans l'objet). En théorie tu as tout à fait le droit de faire ceci :
                            class test(object):
                                def __init__(self,var):
                                    self.var = var
                            
                            a = test(3)
                            print(a.var)
                            
                            mais cela ne respecte pas le principe d'encapsulation (qui dit que l'ont ne dois pas avoir accès aux attributs en dehors des méthode d'une classe). On crée donc une méthode qui va renvoyer la valeur de self.var :
                            # a mettre à l'intèrieur de la classe précédente (comme une méthode)
                            def get_var(self):
                                return self.var # en général les accésseurs sont des méthodes qui n'ont qu'un return
                            

                            Pour les mutateurs c'est exactement pareil :
                            # je pourrais faire ceci :
                            a = test(3)
                            a.var = 6 # je change la valeur d'un attribut de a, cela ne respecte pas le principe d'encapsulation
                            
                            Je crée donc une méthode qui va modifier pour moi la valeur de a (en faisant des test supplémentaires) :
                            def set_var(self,nouvelle_valeur):
                                # ici des tests pour vérifier que 'nouvelle_valeur' n'est pas une valeur stupide
                                self.var = nouvelle_valeur
                            

                            Les tests sont là pour éviter à l'utilisateur de faire n'importe quoi avec la classe. Par exemple supposons que la classe est un attribut 'longueur' et que je lui envoies une longueur négative, il y a un problème... (qui ne serait pas détecté sans l'accesseur set_longueur)
                            • Partager sur Facebook
                            • Partager sur Twitter
                            Anonyme
                              21 juillet 2010 à 20:15:03

                              Holt >>> Très bien expliqué merci, je suis moi aussi en train de voir la programmation orienté objet, et je ne savais pas qu'en Python il fallait aussi utiliser les getters et setters, que j'avais étudié rapidement en Java.
                              Apparemment la POO est une convention, une norme pour codé proprement donc ca doit être pour ca que c'est pareil, avec quelque petites différences entre langages :D
                              • Partager sur Facebook
                              • Partager sur Twitter
                                27 juillet 2010 à 11:16:51

                                Merci pour ces explications,

                                donc si j'ai bien compris, pour chaque méthode, il y aura un accesseur et un mutateur.

                                Avec les accesseurs, nous pouvons accéder aux attributs et avec les mutateurs nous pouvons en quelques sorte modifier ces valeurs.
                                Il est donc impossible de modifier des attributs avec un accesseur, mais uniquement avec un mutateur.

                                Dites moi si je me trompe :)


                                Je vais reprendre ton exemple Nohar.

                                "Mon joueur marche et pose une bombe, ma bombe explose, les murs et mes bonus se cassent."

                                Est-ce utile de mettre "mon explosion" (dans les 4 directions) comme étant une classe ?


                                Bonne fin de matinée.
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  27 juillet 2010 à 12:03:16

                                  Citation : realmagma

                                  donc si j'ai bien compris, pour chaque méthode, il y aura un accesseur et un mutateur.

                                  Tu veux certainement dire pour chaque attribut. ^^

                                  A part ça, tu as bien compris. Dans ton cas, on pourrait par exemple avoir :
                                  class Joueur:
                                      """Classe représentant le joueur et permettant de le déplacer"""
                                  
                                      def setNom(self, nom):
                                          """Renomme le joueur en <nom> (type : str)"""
                                          self.nom = nom
                                  
                                      def getNom(self):
                                          """Retourne le nom du joueur"""
                                          return self.nom
                                  
                                      def deplacerJoueur(self, positionJoueur, directionJoueur):
                                          """Déplace le joueur d'une case de <positionJoueur> vers <directionJoueur>"""
                                  

                                  On a ici un mutateur qui change l'attribut nom, un accesseur qui retourne cet attribut et une méthode qui agit sur le joueur (je crois que ça a un nom, mais je ne le connais pas). Bien entendu, cet exemple est (très) minimaliste, mais il est révélateur du fonctionnement d'une classe.

                                  Citation : realmagma

                                  Est-ce utile de mettre "mon explosion" (dans les 4 directions) comme étant une classe ?

                                  Ça dépend, personnellement, je ne pourrais pas te donner une réponse comme ça. A priori, je dirais non, je dirais qu'une méthode appartenant à la classe Joueur peut très bien se charger d'afficher une explosion et de générer des dégâts. Cependant, si tu trouves qu'il y a beaucoup de données relatives à l'explosion à gérer, qu'une seule méthode ne suffit pas à la créer, alors pourquoi pas. Pose-toi des questions : que doit faire l'explosion ? De quelles données a-t-elle besoin pour avoir lieu ?

                                  Bonne chance. ;)
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                  Anonyme
                                    27 juillet 2010 à 12:04:28

                                    Citation

                                    Est-ce utile de mettre "mon explosion" (dans les 4 directions) comme étant une classe ?



                                    Je mettrais plutôt une classe bombe avec une méthode exploser, poser, etc...
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      27 juillet 2010 à 12:42:11

                                      Il y a 2 écoles en Python pour contrôler ce que fait l'utilisateur de la classe :
                                      La première (dont l'explication de Holt fait partie) est d'utiliser Python comme tous les autres langages de POO (créer des getter/setter pour tous les attributs que l'on souhaite rendre publique).
                                      La seconde, peut-être plus Pythonique (du moins à mon goût) est de créer ce que l'on appelle des propriétés.
                                      Les deux ne sont d'ailleurs pas incompatibles (du moment que l'on connait les limites des propriétés). :p

                                      Voici un exemple détaillé.
                                      Je crée une classe Rectangle qui possède 3 "attributs publics". Hauteur, largeur, aire.

                                      Première implémentation :
                                      class Rectangle(object):
                                          def __init__(self, hauteur, largeur):
                                              self.hauteur = hauteur
                                              self.largeur = largeur
                                      
                                          def get_hauteur(self):
                                              return self.hauteur
                                      
                                          def get_largeur(self):
                                              return self.largeur
                                      
                                          def get_aire(self):
                                              return self.hauteur * self.largeur
                                      
                                          def set_hauteur(self, hauteur):
                                              if hauteur > 0:
                                                  self.hauteur = hauteur
                                              else:
                                                  raise ValueError, 'hauteur <= 0'
                                      
                                          def set_largeur(self, largeur):
                                              if largeur > 0:
                                                  self.largeur = largeur
                                              else:
                                                  raise ValueError, 'largeur <= 0'
                                      


                                      Évidemment, on ne crée pas de setter pour l'aire... on ne peux pas décider de la hauteur et la largeur d'un rectangle simplement à partir de l'aire.

                                      Voilà un exemple d'utilisation qui en illustre les limites:

                                      >>> mon_rect = Rectangle(3, 4)
                                      >>> mon_rect.get_aire()
                                      12
                                      >>> mon_rect.set_hauteur(5)
                                      >>> mon_rect.get_aire()
                                      20
                                      >>> mon_rect.set_largeur(-1)
                                      Traceback (most recent call last):
                                        File "<stdin>", line 1, in <module>
                                        File "rectangle.py", line 28, in set_largeur
                                          raise ValueError, 'largeur <= 0'
                                      >>> mon_rect.get_aire()
                                      20
                                      Jusqu'ici tout va bien... sauf que :
                                      >>> mon_rect.largeur = -1
                                      >>> mon_rect.get_aire()
                                      -5


                                      Et boum ! L'utilisateur a décidé d'accéder directement à l'attribut, ce qui engendre un comportement totalement imprévu de l'objet.
                                      Un bon moyen, en Python, d'éviter ça, est de déclarer les attributs "privés" (ils ne le sont pas vraiment dans la réalité, on peut toujours y accéder directement, mais la convention les montre comme tels), en précédant leur nom de 2 underscores :

                                      class Rectangle(object):
                                          def __init__(self, hauteur, largeur):
                                              self.__hauteur = hauteur
                                              self.__largeur = largeur
                                      
                                          def get_hauteur(self):
                                              return self.__hauteur
                                      
                                          def get_largeur(self):
                                              return self.__largeur
                                      
                                          def get_aire(self):
                                              return self.__hauteur * self.__largeur
                                      
                                          def set_hauteur(self, hauteur):
                                              if hauteur > 0:
                                                  self.__hauteur = hauteur
                                              else:
                                                  raise ValueError, 'hauteur <= 0'
                                      
                                          def set_largeur(self, largeur):
                                              if largeur > 0:
                                                  self.__largeur = largeur
                                              else:
                                                  raise ValueError, 'largeur <= 0'
                                      


                                      Cette pratique, appelée "name mangling", crée en fait des attributs aux noms à rallonge lorsque le module est précompilé, et permet de protéger, dans une certaine mesure, de l'accès direct.

                                      >>> from rectangle import Rectangle
                                      >>> mon_rect = Rectangle(3, 4)
                                      >>> mon_rect.get_aire()
                                      12
                                      >>> mon_rect.set_largeur(-1)
                                      Traceback (most recent call last):
                                        File "<stdin>", line 1, in <module>
                                        File "rectangle.py", line 28, in set_largeur
                                          raise ValueError, 'largeur <= 0'
                                      ValueError: largeur <= 0
                                      >>> mon_rect.__largeur = -1
                                      >>> mon_rect.get_aire()
                                      12


                                      Mais le problème, c'est que les codeur Python sont fainéants, raison pour laquelle on a inventé les propriétés :

                                      class Rectangle(object):
                                          def __init__(self, hauteur, largeur):
                                              self.__hauteur = hauteur
                                              self.__largeur = largeur
                                      
                                          def _get_hauteur(self):
                                              return self.__hauteur
                                      
                                          def _get_largeur(self):
                                              return self.__largeur
                                      
                                          def _get_aire(self):
                                              return self.__hauteur * self.__largeur
                                      
                                          def _set_hauteur(self, val):
                                              if val > 0:
                                                  self.__hauteur = val
                                              else:
                                                  raise ValueError, 'hauteur <= 0'
                                      
                                          def _set_largeur(self, val):
                                              if val > 0:
                                                  self.__largeur = val
                                              else:
                                                  raise ValueError, 'largeur <= 0'
                                      
                                          hauteur = property(fget=_get_hauteur, fset=_set_hauteur)
                                          largeur = property(fget=_get_largeur, fset=_set_largeur)
                                          aire = property(fget=_get_aire)
                                      


                                      Comme vous le voyez, j'ai donné des noms un peu alambiqués pour les getters/setters, et j'ai créé à la fin ce que l'on appelle les propriétés : en gros, ce sont de "faux attributs", qui s'utilisent comme tels, mais qui appellent les méthodes adéquates lorsque l'on cherche à y accéder/les modifier

                                      Comme le montre l'exemple suivant, cela permet d'utiliser beaucoup plus naturellement les objets de la classe Rectangle :
                                      >>> from rectangle import Rectangle
                                      >>> mon_rect = Rectangle(3,4)
                                      >>> mon_rect.aire
                                      12
                                      >>> mon_rect.hauteur = 5
                                      >>> mon_rect.aire
                                      20
                                      >>> mon_rect.hauteur = -1
                                      Traceback (most recent call last):
                                        File "<stdin>", line 1, in <module>
                                        File "rectangle.py", line 19, in _set_hauteur
                                          raise ValueError, 'hauteur <= 0'
                                      ValueError: hauteur <= 0
                                      >>> mon_rect.aire = 12
                                      Traceback (most recent call last):
                                        File "<stdin>", line 1, in <module>
                                      AttributeError: can't set attribute
                                      >>>


                                      La seule réelle limite à leur utilisation, c'est qu'il vaut mieux éviter de passer des usines à gaz comme méthodes pour ces propriétés, de manière à garder pour la classe un comportement "attendu", c'est-à-dire "rapide" si l'utilisateur cherche simplement à affecter une valeur entière à un attribut.

                                      En bref, cela permet de préserver le principe de l'encapsulation tout en autorisant une utilisation beaucoup plus naturelle et "Pythonique" des classes.

                                      Plus d'infos sur les propriétés sur cette page de la doc de python.


                                      Citation : realmagma


                                      Est-ce utile de mettre "mon explosion" (dans les 4 directions) comme étant une classe ?



                                      Tel que tu l'as posé dans ton exemple, pour l'instant non : il n'y a pas de nom "explosion" en gras mais bien un verbe "exploser" en vert, c'est donc ta classe "bombe" qui aura une méthode "exploser" dans ton modèle.

                                      Ceci dit, il ne sera pas forcément bête (au bout d'un certain temps de développement, si ça s'avérait utile...) de créer une classe "explosion" pour l'affichage, qui serait chargée de gérer l'animation de la bombe qui explose... mais dans un premier temps, il est peut-être un peu tôt pour penser à la manière dont ton jeu va s'afficher/s'animer, et probablement plus urgent de te concentrer sur un modèle solide (pour contenir la "logique" du jeu). ;)
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                      Zeste de Savoir, le site qui en a dans le citron !
                                        27 juillet 2010 à 16:49:18

                                        Les explosions ou du moins les flammes, sont une classe à part entière (l'explosion est une méthode de la bombe).
                                        Une bombe explose en créant des flammes. Les flammes grandissent, brulent les joueurs, cassent les murs cassables et les bonus et font exploser les bombes.

                                        Voilou ;)
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          27 juillet 2010 à 16:58:02

                                          Citation : W3YZOH0RTH

                                          Les explosions ou du moins les flammes, sont une classe à part entière (l'explosion est une méthode de la bombe).
                                          Une bombe explose en créant des flammes. Les flammes grandissent, brulent les joueurs, cassent les murs cassables et les bonus et font exploser les bombes.

                                          Voilou ;)



                                          C'est une autre manière de concevoir le jeu... mais on peut aussi considérer que dans la méthode "exploser" de la classe bombe, on appelle la méthode "bruler()" de tous les objets autour d'elle, et que l'on ne montre les flammes que lors de l'affichage, pour donner un aperçu visuel de la portée de la bombe qui vient de péter...
                                          Ça évite de compliquer le modèle avec des objets éphémères.

                                          Les deux se discutent.
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                          Zeste de Savoir, le site qui en a dans le citron !
                                            27 juillet 2010 à 17:52:41

                                            Yep, je comprends. Mais après si on préfère faire tel que je l'ai dit avec des flammes qui grandissent et non juste qu'elles apparaissent *Tadam* et disparaissent, les objets sont plus pratiques ;)
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              28 juillet 2010 à 15:01:20

                                              Bonjour,

                                              très bon mini-tuto sur les classes Nohar (tu devrais en faire un à part, histoire de) :)
                                              Avec cette histoire de setter/getter, on va se retrouver avec une multitude de méthodes :-°

                                              hauteur = property(fget=_get_hauteur, fset=_set_hauteur)
                                              largeur = property(fget=_get_largeur, fset=_set_largeur)
                                              aire = property(fget=_get_aire)
                                              


                                              D'ou vient le 'fget' / 'fset' ?
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                28 juillet 2010 à 15:15:29

                                                Ce sont les paramètres arguments de la fonction "property".
                                                Tu devrais jeter un oeil au lien sur la doc que j'ai donné.

                                                Edit : vocabulaire
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                Zeste de Savoir, le site qui en a dans le citron !
                                                  28 juillet 2010 à 18:12:06

                                                  Citation : NoHaR

                                                  Ce sont les paramètres arguments de la fonction "property".
                                                  Tu devrais jeter un oeil au lien sur la doc que j'ai donné.
                                                  Edit : vocabulaire



                                                  En effet, je n'avais pas vu le lien. :-°

                                                  Pour m'entraîner sur Pygame, j'ai crée une fenêtre ou un personnage se deplace et regarde dans les 4 directions, suivant la touche up,down,right,left appuyée.

                                                  J'ai crée une classe (et oui il faut bien s'entraîner ^^ ) 'Perso(object)'.
                                                  Si un joueur appuie sur une des 4 touches, l'image se déplace de 3 pixels dans la direction voulu. Les coordonées de mon perso (x;y) sont automatiquement calculés.

                                                  Cependant j'ai un petit problème. Mon perso ne se deplace... qu'en haut :o !
                                                  J'aimerais que vous y jettiez un oeil si vous le voulez bien. J'ai commencé cela ce matin.

                                                  """
                                                  Petit programme gerant les deplacements
                                                  d'un personnage a partir d'une classe
                                                  'Perso'sous Pygame.
                                                  """
                                                  
                                                  ################################
                                                  ## Les Modules Importés:  (2) ##
                                                  #
                                                  import pygame, os
                                                  
                                                  
                                                  ################################
                                                  ## Les classes & fonctions:   ##
                                                  #
                                                  class Perso(object):
                                                      """
                                                      Tout ce qui concerne le perso:
                                                      - Retiens la posistion (x;y), \
                                                        la distance et le fait avancer.
                                                      - Retiens le nom du personnage
                                                      """
                                                      def __init__(self, distanceX = 3, distanceY = 3):
                                                          """
                                                          Les attributs du constructeur
                                                          """
                                                          self.posX = 0
                                                          self.posY = 0
                                                  
                                                          self.distanceX = distanceX
                                                          self.distanceY = distanceY
                                                  
                                                          self.nom = "Pseudo_1"
                                                          
                                                      #
                                                      ##Les Getters (accesseurs)
                                                      #
                                                      def g_distanceX(self):
                                                          """
                                                          Combien de pixels avance/recule
                                                          le personnage en abcisse?
                                                          """
                                                          return self.distanceX
                                                      
                                                      def g_distanceY(self):
                                                          """
                                                          Combien de pixels avance/recule
                                                          le personnage en ordonnee?
                                                          """
                                                          return self.distanceY
                                                  
                                                  
                                                      def g_posX(self):
                                                          """
                                                          Ou est le perso
                                                          en abcisse ?
                                                          """
                                                          return self.posX
                                                      
                                                      def g_posY(self):
                                                          """
                                                          Ou est le perso
                                                          en ordonnee ?
                                                          """
                                                          return self.posY
                                                  
                                                  
                                                      def g_nom(self):
                                                          """
                                                          Quel est le nom
                                                          du personnage ?
                                                          """
                                                          return self.nom
                                                      #
                                                      ##Les Setters (Mutateurs)
                                                      #
                                                      def s_distanceX(self, newDistanceX):
                                                          """
                                                          Pour faire avancer/reculer
                                                          le personnage en abcisse
                                                          """
                                                          self.posX += newDistanceX
                                                      
                                                      def s_distanceY(self, newDistanceY):
                                                          """
                                                          Pour faire avancer/reculer
                                                          le personnage en ordonnee?
                                                          """
                                                          self.posY += newDistanceY
                                                  
                                                  
                                                      def s_nom(self, newNom):
                                                          """
                                                          Quel sera le nouveau
                                                          nom du personnage ?
                                                          """
                                                          self.nom = newNom
                                                  
                                                      
                                                  ################################
                                                  ## Les diférrentes variables: ##
                                                  #
                                                  hauteur = 200                 #Pour la-
                                                  largeur = 200                 #-fenetre
                                                  continuer = True              
                                                  
                                                  distance = 3
                                                  p = Perso(3, 3)
                                                  
                                                  
                                                  ################################
                                                  ## Programme Principale:      ##
                                                  #
                                                  pygame.init()
                                                  
                                                  #On cree la surface de l'ecran
                                                  screen = pygame.display.set_mode((hauteur, largeur))
                                                  pygame.display.set_caption("Acka Boum-Boum")
                                                  screen.fill((255, 255, 255))  #En blanc pour faire jolie
                                                  
                                                  #Preciser ou est l'image et les associer dans mes variables
                                                  chemin = os.path.join("C:", "Documents\\Logiciels\\Python\\fichier\\gui\\")
                                                  monImageB = pygame.image.load(chemin + "teteB.PNG") #Tete bas
                                                  monImageH = pygame.image.load(chemin + "teteH.PNG") #Tete Haut
                                                  monImageG = pygame.image.load(chemin + "teteG.PNG") #Tete Gauche
                                                  monImageD = pygame.image.load(chemin + "teteD.PNG") #Tete Droit
                                                  
                                                  #Enlever les contours inutiles. Ici blanc
                                                  monImageB.set_colorkey((255, 255, 255))
                                                  monImageH.set_colorkey((255, 255, 255))
                                                  monImageG.set_colorkey((255, 255, 255))
                                                  monImageD.set_colorkey((255, 255, 255))
                                                  
                                                  #Transparence: monImageB.set_alpha(255)
                                                  #Premier blit sur l'ecran dans la memoire
                                                  screen.blit(monImageB, (35, 35))
                                                  pygame.display.flip()
                                                  
                                                  
                                                  while(continuer):
                                                      
                                                      for event in pygame.event.get():
                                                          if(event.type == pygame.QUIT): #So on clique sur la croix, on ferme
                                                             continuer = False
                                                             
                                                          elif(event.type is pygame.KEYDOWN):
                                                              
                                                              if(pygame.key.name(pygame.K_UP)):   #Pour le Haut
                                                                  p.s_distanceY(-distance)
                                                                  
                                                                  screen.fill((255, 255, 255))
                                                                  screen.blit(monImageH, (p.g_posX(), p.g_posY())) #On blit a la pos
                                                                  pygame.display.flip()
                                                                  print(p.g_posX(), p.g_posY()) #Essai
                                                                  
                                                              elif(pygame.key.name(pygame.K_DOWN)): #Pour le Bas
                                                                  p.s_distanceY(distance)
                                                                  
                                                                  screen.fill((255, 255, 255))
                                                                  screen.blit(monImageB, (p.g_posX(), p.g_posY())) 
                                                                  pygame.display.flip()
                                                  
                                                              elif(pygame.key.name(pygame.K_RIGHT)): #Pour la droite
                                                                  p.s_distanceX(distance)
                                                                  
                                                                  screen.fill((255, 255, 255))
                                                                  screen.blit(monImageD, (p.g_posX(), p.g_posY())) 
                                                                  pygame.display.flip()
                                                  
                                                              elif(pygame.key.name(pygame.K_LEFT)):  #Pour la gauche
                                                                  p.s_distanceX(-distance)
                                                                  
                                                                  screen.fill((255, 255, 255))
                                                                  screen.blit(monImageG, (p.g_posX(), p.g_posY())) 
                                                                  pygame.display.flip()
                                                  


                                                  Je vous remercie d'avance.
                                                  P.S: Il y a beaucoup de comentaires (mes comentaires 'types' comme je les nomme sont mes rectangles que je n'effacerais jamais :lol: . Les autres sont là pour ne pas oublier ce que fait telle ou telle ligne et quelques un pour vous.
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    28 juillet 2010 à 18:58:41

                                                    Je n'ai pas testé ton code, mais je me demande si ton problème ne pourrait pas être résolu en nettoyant la pile d'évènements à chaque appui de touche. Je crois avoir eu un problème de ce genre quand j'avais essayé Pygame.

                                                    Sinon, tes accesseurs et mutateurs sont superflus : en Python, tous les attributs sont publics. On peut éventuellement rendre leur accès de l'extérieur moins évident (en les précédant de __), mais ils seront toujours modifiables et consultables. L'idée derrière, c'est que celui qui modifie ça est responsable de ce qu'il fait : "nous sommes tous entre adultes consentants". Si tu veux quand même faire ça de façon "propre" (le mot est discutable), tu peux utiliser les méthodes setattr et getattr, qui font ce que tu veux, sans que tu aies besoin de surcharger ton code.
                                                    Note que les fonctions comme le déplacement peuvent toujours avoir leur place, parce que ça deviendra vite plus compliqué que "modifier un attribut avec la valeur passée en second argument".
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      28 juillet 2010 à 19:09:09

                                                      Je n'ai pas regardé en détails, mais j'ai vu que tu utilises ton propre système de coordonnées. Or Pygame utilise une classe pour ça : Rect (le lien mène vers la doc).

                                                      Tu as juste à créer un Rect en attribut de la classe Joueur, à utiliser la méthode Rect.move pour pour changer sa position, et à le passer en argument à la fonction screen.blit (en lieu et place de ton tuple de coordonnées). Autant utiliser les outils mis à ta disposition quand ils te facilitent la vie. ;)

                                                      Une dernière chose, qui n'est pas très importante pour le moment, mais qui pourra te poser de gros problèmes par la suite. Dans ton code, à chaque fois que le joueur bouge le personnage, tu utilises screen.fill pour remplir la totalité de l'écran avec une couleur. L'utilité est bien sûr de « cacher » l'image du joueur posée à son ancienne position. Mais remplir la totalité de l'écran d'une couleur alors qu'une minuscule parcelle de celui-ci doit être effacée est un peu stupide : ça utilise beaucoup trop de ressources.

                                                      Il existe un moyen très simple pour contourner ce problème. Tu peux passer en second argument à la fonction screen.fill un Rect qui désigne la zone à remplir. Tu n'as qu'à lui donner l'ancienne position de ton perso, et seule cette partie sera remplie. Tu verras que ton personnage se déplacera bien plus rapidement. ^^

                                                      Edit :
                                                      Je sais que cette technique peut paraître totalement inutile au début, mais dès que tu te lances dans un projet où il y a beaucoup de choses à afficher, elle devient primordiale.
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        28 juillet 2010 à 20:01:51

                                                        Citation : Maxibolt

                                                        Je n'ai pas testé ton code, mais je me demande si ton problème ne pourrait pas être résolu en nettoyant la pile d'évènements à chaque appui de touche. Je crois avoir eu un problème de ce genre quand j'avais essayé Pygame.

                                                        Sinon, tes accesseurs et mutateurs sont superflus : en Python, tous les attributs sont publics. On peut éventuellement rendre leur accès de l'extérieur moins évident (en les précédant de __), mais ils seront toujours modifiables et consultables. L'idée derrière, c'est que celui qui modifie ça est responsable de ce qu'il fait : "nous sommes tous entre adultes consentants". Si tu veux quand même faire ça de façon "propre" (le mot est discutable), tu peux utiliser les méthodes setattr et getattr, qui font ce que tu veux, sans que tu aies besoin de surcharger ton code.
                                                        Note que les fonctions comme le déplacement peuvent toujours avoir leur place, parce que ça deviendra vite plus compliqué que "modifier un attribut avec la valeur passée en second argument".



                                                        Alors là je me demande à quoi servent les accesseurs et les mutateurs s'ils peuvent toujours être modifiable....

                                                        A quoi bon respecter le principe d'encapsulation ?
                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          28 juillet 2010 à 20:10:22

                                                          Tout le secret de la pratique de la POO en Python est de trouver un équilibre confortable dans une situation où tu as le cul entre deux chaises.

                                                          Par définition, Python part du principe que l'on est tous "entre adultes consentants" comme l'a dit Maxibolt (c'est le cas d'autres langages du même style que Python, comme Ruby pour ne pas le citer). Cela permet de coder plus vite et plus souplement lorsque l'on sait ce que l'on fait.

                                                          Seulement pour bien comprendre les mécanismes qui se cachent derrière l'utilisation des objets, utiliser des pratiques "propres" de la POO et essayer de les appliquer (sans chercher à savoir s'ils sont vraiment utiles ou pas au cas par cas) en Python dans tes premiers codes est aussi une bonne chose. Le principe des propriétés que j'ai expliqué est une forme d'équilibre entre l'encapsulation et le confort de Python. Il y en a d'autres... tu trouveras probablement le tien avec l'habitude et la pratique.
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                          Zeste de Savoir, le site qui en a dans le citron !
                                                            28 juillet 2010 à 20:43:11

                                                            Je crois que la POO restera toujours et à jamais abstraite pour moi :colere2: .
                                                            J'ai de terrible soucis avec les surfaces du types Rect:

                                                            -Impossible de les initialiser dans ma classe
                                                            -impossible de leur faire prendre une valeur x et y
                                                            -Impossible de voir comment l'appeler en dehors de ma classe.

                                                            Et même avec la Doc (qui ne m'aide pas beaucoup en faite :-° )

                                                            Quelqu' un pourrait m'expliquer avec un exemple 'quelconque' comment marche ces surfaces du type Rect() s'il vous plaît ?

                                                            Merci d'avance.

                                                            • Partager sur Facebook
                                                            • Partager sur Twitter

                                                            Bomberman

                                                            × 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.
                                                            • Editeur
                                                            • Markdown