Partage
  • Partager sur Facebook
  • Partager sur Twitter

[pygame][mini-projet] Tetris

    3 novembre 2010 à 23:08:44

    A la demande générale, voilà le tetris ...
    Je ne suis vraiment pas doué pour expliquer les choses, je vais faire de mon mieux, je suis ouvert à toutes suggestions.
    Je pars du principe que tout le monde connais le jeu.

    Il y a 36 façons de coder un tetris. Je vais essayer de vous expliquer ma façon de faire; je ne sais pas si c'est la meilleure ou la pire, mais elle fonctionne.
    Comme ça fait assez longtemps que j'en ai pas coder un, je vais tout reprendre depuis la page blanche.

    c'est partie:
    • 1- observation du jeu:
      soit un objet qui chute dans un tableau, il est mobile et répond au clavier, il interagit avec le décor car il ne peut occuper une place déjà prise.
      sa vitesse de chute est constante, et répond donc à une temporisation.
      il y a donc 3 facteurs qui agissent de l'objet:
      - l'évènement clavier (gauche, droite, bas et rotation)
      - l'évènement temps (fait chuter à intervals réguliers)
      - le décor (empêche le déplacement)

      l'objet n'occupe que des espaces vides.
      si on considère l'objet comme un élément coloré, il ne peut occuper qu'un espace 'noir'.
      si on considère l'objet comme une densité égale à 1, il ne peut occuper qu'un espace de 'densité 0'.
      il y a donc une notion binaire ...

      on peut donc définir un tableau et un objet comme ceci:
      les '1' ne pouvant occuper le place d'autres '1', il suffit de limiter le tableau avec des '1' pour empêcher l'objet d'en sortir.

      tableau                   objet
         100000000001                000000000000
         100000000001                000001000000
         100000000001                000011100000
         100000000001                000000000000
         100000000001
         100000000001
         100000000001           autre objet
         100000000001                000000000000
         100000000001                000010000000
         100000000001                000011100000
         100000000001                000000000000
         100000000001
         100000000001
         100000000001
         100000000001
         111111111111


      et là ça semble évident, chaque ligne du tableau et des objets peut être codée sur un entier.

    • 2- opérateurs logiques et numériques:
      -comment savoir si un objet n'empiète pas sur un espace déjà occupé?
      on sait que:
      un '0' peut occuper la place d'un '0'
      un '0' peut occuper la place d'un '1'
      un '1' peut occuper la place d'un '0'
      mais
      un '1' ne peut occuper la place d'un '1'

      ce schéma correspond à un 'ET NON' logique.

      -comment l'objet se déplace à gauche ou à droite?
      c'est simple, il suffit de déplacer les '1'.
      si la ligne 2 d'un objet est codée '0000011000' soit 24 en décimal
      24 multiplié par 2 donne 48, soit '0000110000' en binaire
      et 24 divisé par 2 donne 12, soit '0000001100' en binaire

      les '1' semblent s'être déplacés ...
      en appliquant ceci aux 4 lignes de l'objet, tout l'objet se déplace.

      c'est pour cela que l'objet à la même largeur que le tableau, car 'supperposé' à celui-ci, opérateurs logiques et numériques s'appliqueront plus facilement.

      -ok, et la rotation alors?
      de même que l'on code l'objet en forme de 'L' sur 4 int (ou des bin ou hex, c'est vous qui voyez),
      on code ses 4 phases de rotation ainsi:
      (les chiffres sont bidons)
      objet_en_forme_de_L = (45,26,96,12) , (57,84,32,79) , (84,23,15,47) , (63,35,29,21)
      un index pointe l'objet en cours; il suffit de le décrémenter pour créer la rotation.
    • 3 -problèmes et solutions ...
      pb:
      admettons que le jeu sur déroule avec l'objet_en_forme_de_L[2]
      si je déplace celui-ci complètement à droite, au prochaine cycle où il sera utilisé, il apparaitra à droite et non plus au milieu du tableau...
      sl:
      on utilise une copie de l'objet_en_forme_de_L[2] que l'on pourra manipuler.

      pb:
      l'objet_en_forme_de_L[2] est complètement à droite du tableau
      si j'applique une rotation, l'objet_en_forme_de_L[1] sera, lui, au milieu du tableau ...
      sl:
      on utilise une copie de l'objet_en_forme_de_L pour palier au 1er problème, et, au lieu de déplacer que l'objet indexé, on déplace tout le groupe.

    • 4- les évènements:
      • 4.1- clavier

        les 4 touches 'arrow' sont utilisées.
        l'objet se déplace à gauche, droite et bas tant que les touches 'left','right' et 'down' sont maintenues enfoncées,
        mais ne 'tourne' qu'à l'enfoncement de la touche 'up'.
        pygame met à disposition plusieurs outils pour gérer le clavier ...
        Exercice:
        écrivez un 'mainloop' qui réagit de la façon expliquée ci-dessus; vérifiez le fonctionnement en 'printant' la touche enfoncée ('left','right','up' et 'down')
        from pygame import *
        
        screen = display.set_mode((200,200))
        
        key.set_repeat(50,50)
        
        k_up_is_up = False
        
        while True:
            ev = event.wait()
            if ev.type == QUIT: exit()
            elif ev.type == KEYDOWN:
                if ev.key == K_DOWN: print 'down'
                elif ev.key == K_LEFT: print 'left'
                elif ev.key == K_RIGHT: print 'right'
                elif ev.key == K_UP and not k_up_is_up:
                    print 'up'
                    k_up_is_up = True
            elif ev.type == KEYUP and ev.key == K_UP: k_up_is_up = False
        

      • 4.2- temps

        l'objet chute de lui-même à vitesse constante(par cycle),ce qui signifie qu'il répond à un timing; non bloquant évidement...
        la encore pygame dispose de plusieurs solutions pour gérer le temps.
        Exercice:
        modifiez le 'mainloop' de façon à ce que soit 'printé' 'down' toutes les 500ms.
        from pygame import *
        
        screen = display.set_mode((200,200))
        
        key.set_repeat(50,50)
        time.set_timer(KEYDOWN,500)
        #ici l'astuce est de simuler l'appuie d'une touche
        #time.set_timer() poste un evenement a interval regulier
        #mais il n'est pas possible de specifier des attributs
        #ainsi l'evenement KEYDOWN aura un attribut key egal a 0
        #0 ne correspondant a aucune touche du clavier il n'y a pas de conflict
        
        k_up_is_up = False
        
        while True:
            ev = event.wait()
            if ev.type == QUIT: exit()
            elif ev.type == KEYDOWN:
                if not ev.key or ev.key== K_DOWN: print 'down'
                elif ev.key == K_LEFT: print 'left'
                elif ev.key == K_RIGHT: print 'right'
                elif ev.key == K_UP and not k_up_is_up:
                    print 'up'
                    k_up_is_up = True
            elif ev.type == KEYUP and ev.key == K_UP: k_up_is_up = False
        
    • 5- interaction objet/décor:

      algo du jeu (un parmis d'autre :p):
      il est simple ...
      soit un tableau vide.
      tant que le tableau ne déborde pas d'objets:
      un nouvel objet est généré et fait sa vie d'objet. Il vit jusqu'à ce qu'il ne puisse plus chuter.
      si l'objet fraîchement généré ne peut chuter au moins 1 fois, c'est que le tableau déborde.

      cycle de jeu:
      un cycle est le temps de vie d'un objet.
      au début d'un cycle, l'objet apparait hors champs, au dessus du tableau visible. Comme il ne peut pas survivre dans le vide sidérale du out of range,
      il est nécessaire que le tableau s'étende de façon à contenir l'objet.
      un tableau visible fait 10 x 20 cases:

      en rouge la parie visible

      100000000001 <---ligne 0
      100000000001 <---ligne 1
      100001000001
      100011100001
      100000000001
      100000000001
      100000000001
      100000000001
      100000000001
      100000000001
      100000000001
      100000000001
      100000000001
      100000000001
      100000000001
      100000000001
      100000000001
      100000000001
      100000000001
      100000000001
      100000000001
      100000000001
      100000000001
      100000000001
      111111111111

      puis il chute, se pose et meurt.
      en mourrant il se pétrifie et fait partie du décor.
      la encore la magie des opérateurs logiques opère...
      si 100000000001 est un élément du décor
      et 000111000000 est un élément de l'objet
      100000000001 OU(logigue) 000111000000 donne 100111000001 comme nouvelle valeur à l'élément du décor.
      (étant donné que deux '1' ne peuvent se chevaucher, ça marhe aussi avec le 'OU EXCLUSIF')

      un nouveau cycle est généré ...

      interactions:

      Exercice:
      1-écrivez une fonction qui teste si un objet peut descendre d'une ligne où pas.
      il faut donc au préalable définir un tableau et au moins un objet dans une phase de rotation.
      démarrez de la ligne 0 du tableau et laisser, via le 'mainloop', chuter l'objet qui ne devra pas dépasse le bas du tableau.
      pour vérifiez le fonctionnement, ecriver une fonction qui affiche en console un truc de ce genre ...
      Image utilisateur

      2-pour empêcher l'objet de sortir du tableau on y a collé des bordures; ça vous l'aviez compris.
      modifiez la fonction test() et 'mainloop' pour tenir compte du déplacement lattéral de l'oblet.

      3-modifiez la fonction test() et 'mainloop' pour tenir compte de la rotation de l'objet.

      4-modifiez 'mainloop' pour générer des objets tant que le tableau ne déborde pas ...

      5-et pour finir, vous l'avez devinez ... (j'abrège car j'en ai marre :p )
      modifiez 'mainloop' pour supprimer les 'lignes pleines' et insérer des lignes vides.

      from pygame import *
      from random import choice
      
      empty_ligne = 2049
      all_set = 4095
      tableau = [empty_ligne]*24+[all_set]
      
      objet = (
      ((0, 0, 8, 14), (0, 12, 8, 8), (0, 0, 14, 2), (0, 4, 4, 12)),
      ((0, 0, 4, 14), (0, 4, 6, 4), (0, 0, 14, 4), (0, 2, 6, 2)),
      ((0, 0, 6, 12), (0, 4, 6, 2), (0, 0, 6, 12), (0, 4, 6, 2)),
      ((0, 0, 12, 6), (0, 2, 6, 4), (0, 0, 12, 6), (0, 2, 6, 4)),
      ((0, 0, 2, 14), (0, 4, 4, 6), (0, 0, 14, 2), (0, 6, 4, 4)),
      ((0, 0, 6, 6), (0, 0, 6, 6), (0, 0, 6, 6), (0, 0, 6, 6)),
      ((0, 0, 0, 15), (4, 4, 4, 4), (0, 0, 0, 15), (2, 2, 2, 2))
      )
      
      screen = display.set_mode((200,400))
      key.set_repeat(50,50)
      time.set_timer(KEYDOWN,500)
      
      k_up_is_up = False
      
      test = lambda shift,down,rotation: not any([int(i*shift)&tableau[e] for e,i in enumerate(obj[(one+rotation)%4],ligne+down)])
      
      def affiche():
          t = tableau[:]
          for i in range(4): t[ligne+i] = t[ligne+i]|obj[one][i]    
          for i in t[4:]:
              for j in bin(i)[2:]: print 'X' if int(j) else ' ',
              print
      
      ligne = 1
      while ligne:
          ligne = 0
          obj = choice(objet)[:]
          one = choice((0,1,2,3))
          while True:
              ev = event.wait()
              if ev.type == KEYDOWN:
                  if not ev.key or ev.key== K_DOWN:
                      if test(1,1,0): ligne+=1
                      else:
                          for e,i in enumerate(obj[one],ligne):
                              tableau[e] = tableau[e]|i
                              if tableau[e] == all_set:
                                  del(tableau[e])
                                  tableau.insert(0,empty_ligne)
                          break
                  elif ev.key == K_LEFT:
                      if test(2,0,0): obj = [[j<<1 for j in i]for i in obj]
                  elif ev.key == K_RIGHT:
                      if test(0.5,0,0): obj = [[j>>1 for j in i]for i in obj]
                  elif ev.key == K_UP and not k_up_is_up:
                      k_up_is_up = True
                      if test(1,0,1): one = (one+1)%4
              elif ev.type == KEYUP and ev.key == K_UP: k_up_is_up = False
              elif ev.type == QUIT: exit()
              affiche()
      


    Prochaine étape ... le rendu.
    • Partager sur Facebook
    • Partager sur Twitter
      4 novembre 2010 à 17:55:35

      Salut,

      Je trouve ton explication fort intéressante et certains points assez astucieux.

      J'ai commencé ce projet (peut-être pas par là où il aurait fallu), j'y travaille.
      A l'issue de ce développement, je penserai avoir tout ce qu'il me faut pour lancer mon projet.

      Bon courage à tous,
      • Partager sur Facebook
      • Partager sur Twitter
        4 novembre 2010 à 18:01:05

        J'avais écrit un Tetris, il y a un bout de temps, pour m'entrainer avec Pygame, avec quelques features sympa (hard-fall, ombre de la pièce, passage au niveau supérieur passé un certain score, tout ça) mais le code n'est vraiment pas très joli à voir.

        S'il faut, j'essayerai de le reprendre et le programmer de façon plus élégante pour le publier ici. :)
        • Partager sur Facebook
        • Partager sur Twitter
        Zeste de Savoir, le site qui en a dans le citron !
          5 novembre 2010 à 21:50:07

          voilà, le noyau est fait.
          on va donc attaquer le rendu et les autres options du jeu, comme le comptage des points, le design, etc ...

          la 1ere chose que je vous propose c'est modifier le code pour pouvoir initialiser des tableaux de tailles variables.
          pas que ce soit essentiel, mais on ne sais pas encore à quoi ça ressemblera à la fin, et s'il faut modifier des valeurs, autant modifier quelques variables et ne pas se taper toutes les constantes du code.


          Citation : NoHaR

          J'avais écrit un Tetris, il y a un bout de temps, pour m'entrainer avec Pygame, avec quelques features sympa (hard-fall, ombre de la pièce, passage au niveau supérieur passé un certain score, tout ça)



          oui, faites des propositions comme ça, et postez aussi de zoulis dessins parce que niveau design je suis super nul :p
          • Partager sur Facebook
          • Partager sur Twitter
            6 novembre 2010 à 23:12:04

            Salut!

            Citation : Josmiley


            Je ne suis vraiment pas doué pour expliquer les choses


            Bah, c'est plutôt bien! :)

            Perso il y a un truc qui me gène...
            J'ai déjà codé un tétris, et ta méthode me séduit(j'ai jamais pensé à ça...).
            Mais, comment gères tu les différentes couleurs, justes avec les bits?o_O

            Ton explication me plait, mais là, je bloque...
            je connais 3, 4 méthodes pour représenter les figures dans un tétris.
            Ce que tu proposes est original, mais je pense qu'il y a blocage, ou alors je suis à coté de la plaque(c'est fort possible! :-° )
            • Partager sur Facebook
            • Partager sur Twitter
            Zeste de Savoir, le site qui en a dans le citron !
              7 novembre 2010 à 0:36:48

              Citation : GurneyH

              Salut!
              Perso il y a un truc qui me gène...
              J'ai déjà codé un tétris, et ta méthode me séduit(j'ai jamais pensé à ça...).
              Mais, comment gères tu les différentes couleurs, justes avec les bits?o_O



              c'est vrai que cette méthode ne permet pas de gérer les combos de couleurs, du moins proprement; si c'est ce dont tu veux parler.
              il est toujours possible de lire la/les couleur/s d'une ligne en lisant la couleur des pixels.
              • Partager sur Facebook
              • Partager sur Twitter
                7 novembre 2010 à 10:24:29

                En principe, dans Tetris, on ne fait pas de combos avec les couleurs, chaque pièce a une couleur donnée, point.

                Ceci dit, c'est vrai que ça parait problématique. Mais ce genre de chose peut se régler une fois que l'on décide de gérer l'affichage avec des groupes de sprites et de dirtysprites.

                Comprendre par là : une fois qu'une pièce est posée, l'objet qui la modélise n'a plus besoin des mêmes propriétés, et il devient plus simple d'enregistrer chaque bloc séparément, avec sa couleur dans la matrice qui représente le plateau.

                De même, entre deux affichages, souvent, on n'a pas besoin de raffraichir tout l'écran, mais juste la zone couverte par la pièce (et éventuellement son ombre) à l'instant t et celle couverte par la pièce (et éventuellement son nombre) à l'instant t+1 (sauf, évidemment, quand on fait une ligne, et qu'il faut la faire disparaître et tout faire tomber au-dessus)…

                C'est pour cette raison que je voudrais recoder mon Tetris avant de le soumettre ici. En l'état, il ne gère pas les couleurs des blocs, et le raffraichissement de l'écran est complet à chaque fois.
                • Partager sur Facebook
                • Partager sur Twitter
                Zeste de Savoir, le site qui en a dans le citron !
                  7 novembre 2010 à 10:33:15

                  Citation : NoHaR


                  Ceci dit, c'est vrai que ça parait problématique. Mais ce genre de chose peut se régler une fois que l'on décide de gérer l'affichage avec des groupes de sprites et de dirtysprites.

                  Comprendre par là : une fois qu'une pièce est posée, l'objet qui la modélise n'a plus besoin des mêmes propriétés, et il devient plus simple d'enregistrer chaque bloc séparément, avec sa couleur dans la matrice qui représente le plateau.



                  ha, j'avais pas compris ça comme ça ...
                  nul besoin de connaitre la couleur d'une pièce posée, puisqu'elle n'existe plus; elle fait partie du décor. Voyez-vous ... ;)

                  c'est vrai que je vous ai donné un code où le plateau est entièrement 'retracé', mais c'est une contrainte dû au mode console.
                  • Partager sur Facebook
                  • Partager sur Twitter
                    7 novembre 2010 à 10:36:17

                    Attention quand même parce que le décor est destructible. ;)
                    • Partager sur Facebook
                    • Partager sur Twitter
                    Zeste de Savoir, le site qui en a dans le citron !
                      7 novembre 2010 à 10:37:38

                      Citation : NoHaR

                      Attention quand même parce que le décor est destructible. ;)


                      disons qu'il est gommable ^^
                      • Partager sur Facebook
                      • Partager sur Twitter
                        8 novembre 2010 à 18:00:31

                        finalement j'ai fixé une taille de 10x20.

                        le fichier masktetris.pngImage utilisateur ou le zip

                        from pygame import *
                        from random import randint
                        
                        font.init()
                        
                        empty_ligne = 2049
                        all_set = 4095
                        tableau = [empty_ligne]*(24)+[all_set]
                        
                        mask = image.load('masktetris.png')
                        red = Surface((300,30),SRCALPHA)
                        red.fill((255,0,0,100))
                        font0 = font.Font('FreeMonoBold.ttf',20)
                        
                        objet = [
                                [[0, 0, 128, 224], [0, 192, 128, 128], [0, 0, 224, 32], [0, 64, 64, 192],(255,0,0)],
                                [[0, 0, 64, 224], [0, 64, 96, 64], [0, 0, 224, 64], [0, 32, 96, 32],(100,100,0)],
                                [[0, 0, 96, 192], [0, 64, 96, 32], [0, 0, 96, 192], [0, 64, 96, 32],(0,100,100)],
                                [[0, 0, 192, 96], [0, 32, 96, 64], [0, 0, 192, 96], [0, 32, 96, 64],(0,0,255)],
                                [[0, 0, 32, 224], [0, 64, 64, 96], [0, 0, 112, 64], [0, 96, 32, 32],(0,255,0)],
                                [[0, 0, 96, 96], [0, 0, 96, 96], [0, 0, 96, 96], [0, 0, 96, 96],(100,255,100)],
                                [[0, 0, 0, 240], [64, 64, 64, 64], [0, 0, 0, 240], [32, 32, 32, 32],(100,0,100)]
                                ]
                        
                        screen = display.set_mode((480,600))
                        bgcolor = 0xd0d0d0
                        bg = Surface((300,720)); bg.fill(bgcolor)
                        key.set_repeat(50,50)
                        
                        score = 0
                        speed = 30
                        S = 0
                        
                        time.set_timer(KEYDOWN,speed)
                        screen.blit(font0.render('score: '+str(score),1,(200,200,200)),(330,300))
                        screen.blit(font0.render('speed: '+str(0),1,(200,200,200)),(330,330))
                        
                        k_up_is_up = False
                        k_space_is_up = False
                        
                        test = lambda shift,down,rotation: not any([int(i*shift)&tableau[e] for e,i in enumerate(obj[(one+rotation)%4],ligne+down)])
                        
                        def make_surf(index,one):
                            img = Surface([120]*2,SRCALPHA)
                            img.fill((0,0,0,0))
                            shadow = img.copy()
                            color = objet[index][-1]
                            for y,i in enumerate(objet[index][one]):
                                i /= 16
                                for x in 90,60,30,0:
                                    if i&1:
                                        img.blit(mask,img.fill(color,(x,y*30,30,30)))
                                        shadow.fill(color+(50,)if shadow_set else bgcolor,(x,y*30,30,30))
                                    i /= 2
                            return img,shadow
                        
                        def YShadowUpdate():
                            global ligne,Yshadow
                            C = ligne
                            while test(1,1,0): ligne+=1
                            Yshadow = (ligne-4)*30
                            ligne = C
                        
                        Yshadow = ligne = 1
                        shadow_set = True
                        next_index = randint(0,6)
                        next_one = randint(0,3)
                        next_imgs = make_surf(next_index,next_one)
                        while ligne:
                            event.clear()
                            Y = -120
                            X = 90
                            ligne = 0
                            index = next_index
                            one = next_one
                            img,shadow = next_imgs
                            obj = objet[index]
                            next_index = randint(0,6)
                            next_one = randint(0,3)
                            next_imgs = make_surf(next_index,next_one)
                            screen.blit(transform.scale(next_imgs[0],(60,60)),screen.fill(0,(30*12,60,60,60)))
                            YShadowUpdate()
                            while True:
                                ev = event.wait()
                                if ev.type == KEYDOWN:
                                    if not ev.key or ev.key== K_DOWN:
                                        if not Y%30:
                                            if test(1,1,0): ligne+=1
                                            else:
                                                bg.blit(img,(X,ligne*30))
                                                s = 0
                                                for e,i in enumerate(obj[one],ligne):
                                                    tableau[e] = tableau[e]|i
                                                    if tableau[e] == all_set:
                                                        S += 1
                                                        if not S%10: speed -= 1; time.set_timer(KEYDOWN,speed)
                                                        s += 1
                                                        score += s**2
                                                        del(tableau[e]); tableau.insert(0,empty_ligne)
                                                        display.update(screen.blit(red,(0,(e-4)*30)))
                                                        time.wait(300)
                                                        bg.blit(bg,(0,30),(0,0,300,(e)*30))
                                                        bg.fill(bgcolor,(0,0,30*10,30))
                                                        screen.fill(0,(330,300,120,60))
                                                        screen.blit(font0.render('score: '+str(score),1,(200,200,200)),(330,300))
                                                        screen.blit(font0.render('speed: '+str(30-speed),1,(200,200,200)),(330,330))
                                                        screen.blit(bg,(0,0),(0,120,300,(e)*30))
                                                        display.flip()
                                                break
                                        if not ev.key: Y += 3
                                        else: Y = (ligne-4)*30
                                        screen.blit(bg,(0,-120))
                                        screen.blit(shadow,(X,Yshadow))
                                        screen.blit(img,(X,Y))
                                        display.flip(); continue
                                    elif ev.key == K_LEFT:
                                        if test(2,0,0): obj = [[j<<1 for j in i]for i in obj]; X -= 30; YShadowUpdate(); continue
                                    elif ev.key == K_RIGHT:
                                        if test(0.5,0,0): obj = [[j>>1 for j in i]for i in obj]; X += 30; YShadowUpdate(); continue
                                    elif ev.key == K_UP and not k_up_is_up:
                                        k_up_is_up = True
                                        if test(1,0,1): one = (one+1)%4; img,shadow = make_surf(index,one); YShadowUpdate(); continue
                                    elif ev.key == K_SPACE and not k_space_is_up:
                                        display.update((screen.blit(bg,(X,Y),(X,Y,120,120)),screen.blit(img,(X,Yshadow))))
                                        Y = Yshadow; ligne = Yshadow/30+4; k_space_is_up = True; continue
                                elif ev.type == KEYUP:
                                    if ev.key == K_UP: k_up_is_up = False; continue
                                    elif ev.key == K_SPACE: k_space_is_up = False; continue
                                    elif ev.key == K_p:
                                        while event.wait().type != KEYUP: pass
                                        continue
                                    elif ev.key == K_s:
                                        shadow_set = not shadow_set
                                        img,shadow = make_surf(index,one)
                                        continue
                                elif ev.type == QUIT: exit()
                        while event.wait().type != QUIT: pass
                        

                        Image utilisateur
                        • Partager sur Facebook
                        • Partager sur Twitter
                          10 novembre 2010 à 9:58:07

                          Alors une première ébauche en mode bourrin. :lol:

                          import pygame
                          import random
                          
                          BLOCK_SIZE = 16
                          GRID_WIDTH, GRID_HEIGHT = 10, 22
                          RESOLUTION = (BLOCK_SIZE * (GRID_WIDTH + 20) , BLOCK_SIZE * GRID_HEIGHT)
                          
                          COLORS =    (128, 128, 128),    \
                                      (255,   0,   0),    \
                                      (  0,   0, 255),    \
                                      (255, 255,   0),    \
                                      (139,  69,  19),    \
                                      (255,   0, 255),    \
                                      (255, 255, 255),    \
                                      (0  , 255,   0),    \
                                      (0  , 255, 255)
                                      
                          # -----------------------------------------------------------------------------
                          class Block:
                              def __init__(self, x, y, id):
                                  self.x, self.y = x, y
                                  self.color = COLORS[id]
                              
                              def display(self, ox, oy):
                                  screen = pygame.display.get_surface()
                                  x, y = ox + self.x, oy + self.y
                                  screen.fill(self.color, (x * BLOCK_SIZE, y * BLOCK_SIZE, \
                                                                  BLOCK_SIZE, BLOCK_SIZE))
                                  
                          # -----------------------------------------------------------------------------
                          class Figure:
                              tetriminos =    (( 0,  0), ( 0,  0), ( 0,  0), ( 0,  0)),           \
                                              ((-2,  0), (-1,  0), ( 0,  0), ( 1,  0)),           \
                                              ((-1, -1), ( 0, -1), (-1,  0), ( 0,  0)),           \
                                              ((-1,  0), ( 0,  0), ( 1,  0), ( 0,  1)),           \
                                              ((-1,  0), ( 0,  0), ( 1,  0), ( 1,  1)),           \
                                              ((-1,  0), ( 0,  0), ( 1,  0), (-1,  1)),           \
                                              ((-1,  0), ( 0,  0), ( 0,  1), ( 1,  1)),           \
                                              (( 0,  0), ( 1,  0), (-1,  1), ( 0,  1))
                              
                              def __init__(self, id):
                                  self.x, self.y = GRID_WIDTH / 2, 0
                                  self.id = id
                                  self.blocks = [Block(b[0], b[1], id) for b in Figure.tetriminos[id]]
                              
                              def display(self):
                                  for b in self.blocks:
                                      b.display(self.x, self.y)
                              
                              def checkPos(self, x, y, grid):
                                  for b in self.blocks:
                                      nxtX, nxtY = x + b.x, y + b.y 
                                      if nxtX < 0 or nxtX >= GRID_WIDTH or nxtY >= GRID_HEIGHT or grid[nxtY][nxtX]:
                                          return False
                                  return True
                              
                              def setPos(self, x, y):
                                  self.x, self.y = x, y
                                     
                              def checkRotate(self, grid):
                                  for b in self.blocks:
                                      nxtX, nxtY = self.x + b.y, self.y - b.x
                                      if nxtX < 0 or nxtX >= GRID_WIDTH or nxtY >= GRID_HEIGHT \
                                                                          or grid[nxtY][nxtX]:
                                          return False
                                  return True
                              
                              def rotate(self):
                                  for b in self.blocks:
                                      b.x, b.y = b.y, -b.x
                          
                          # ----------------------------------------------------------------------------
                          class Playfield:
                              def __init__(self):
                                  self.grid = [[0 for i in xrange(GRID_WIDTH)] \
                                                      for j in xrange(GRID_HEIGHT)]
                                  self.nxtFigure = Figure(random.randrange(1, 8))
                                  self.crtFigure = Figure(random.randrange(1, 8))
                                  self.nxtTime = pygame.time.get_ticks() + 700
                                  
                              def update(self, dx, dy, rotate):
                                  if rotate:
                                      self.updateRotate()
                                  if dx or dy:
                                      self.updateMove(dx, dy)
                                  
                                  crtTime = pygame.time.get_ticks()
                                  if crtTime > self.nxtTime:
                                      x, y = self.crtFigure.x, self.crtFigure.y + 1
                                      if self.crtFigure.checkPos(x, y, self.grid):
                                          self.crtFigure.setPos(x, y)
                                      else :
                                          self.storeFigure()
                                          if self.checkGameOver():
                                              return True
                                          self.crtFigure = self.nxtFigure
                                          self.nxtFigure = Figure(random.randrange(1, 8))
                                      self.nxtTime = crtTime + 700
                                       
                                      return False
                              
                              def updateRotate(self):
                                  if self.crtFigure.checkRotate(self.grid):
                                          self.crtFigure.rotate()
                              
                              def updateMove(self, dx, dy):
                                  x, y = self.crtFigure.x + dx, self.crtFigure.y + dy
                                  if self.crtFigure.checkPos(x, y, self.grid):
                                      self.crtFigure.setPos(x, y)
                                          
                              def storeFigure(self):
                                  for b in self.crtFigure.blocks:
                                      x, y = self.crtFigure.x + b.x, self.crtFigure.y + b.y
                                      self.grid[y][x] = self.crtFigure.id
                                  self.checkLines()
                                  
                              def checkLines(self):
                                  for i, row in enumerate(self.grid):
                                      full = True
                                      for j, case in enumerate(row):
                                          if not case:
                                              full = False
                                              break
                                      if full:
                                          self.deleteLine(i)
                                          
                              def deleteLine(self, row):
                                  for i in range(row, 1, -1):
                                      self.grid[i] = self.grid[i - 1]
                              
                              def checkGameOver(self):
                                  for case in self.grid[0]:
                                      if case:
                                          return True
                                  return False
                              
                              def display(self):
                                  screen = pygame.display.get_surface()
                                  screen.fill(0)
                                 
                                  for i, row in enumerate(self.grid):
                                      for j, case in enumerate(row):
                                          screen.fill(COLORS[self.grid[i][j]], (                                     \
                                                                                  j * BLOCK_SIZE,       \
                                                                                  i * BLOCK_SIZE,       \
                                                                                  BLOCK_SIZE,           \
                                                                                  BLOCK_SIZE            \
                                                                              ))
                                  self.crtFigure.display()
                                  self.nxtFigure.setPos(GRID_WIDTH + 3, 1)
                                  self.nxtFigure.display()
                                  self.nxtFigure.setPos(GRID_WIDTH / 2, 0)
                          
                          # -----------------------------------------------------------------------------
                          class Game:
                              def __init__(self):
                                  pygame.init()
                                  pygame.display.set_mode(RESOLUTION)
                                  self.playfield = Playfield()
                                  
                              def run(self):
                                  done = False
                                  while not done:
                                      dx, dy = 0, 0
                                      rotate = False
                                      for event in pygame.event.get():
                                          if event.type == pygame.QUIT:
                                              done = True
                                      if not done:
                                          keys = pygame.key.get_pressed()
                                          if keys[pygame.K_LEFT]:
                                              dx = -1
                                          elif keys[pygame.K_RIGHT]:
                                               dx = 1
                                          elif keys[pygame.K_DOWN]:
                                              dy = 1
                                          elif keys[pygame.K_UP]:
                                              rotate = True
                                      
                                          done = self.playfield.update(dx, dy, rotate)
                                          self.playfield.display()
                                
                                          pygame.time.delay(100)
                                          pygame.display.flip()
                          
                          game = Game()
                          game.run()
                          


                          Hum, je fais nettement plus long que Josmiley et avec moins de fonctionnalités(pas de score et pas de niveau encore.
                          On va essayer de rendre ça plus joli. :)
                          • Partager sur Facebook
                          • Partager sur Twitter
                          Zeste de Savoir, le site qui en a dans le citron !
                            10 novembre 2010 à 11:38:25

                            @GurneyH:
                            pygame.key.get_pressed() n'est pas une bonne solution pour tester les touches car un appuie bref n'est pas forcément détecté s'il se produit entre 2 pygame.key.get_pressed()
                            • Partager sur Facebook
                            • Partager sur Twitter
                              10 novembre 2010 à 14:13:46

                              Citation : josmiley

                              @GurneyH:
                              pygame.key.get_pressed() n'est pas une bonne solution pour tester les touches car un appuie bref n'est pas forcément détecté s'il se produit entre 2 pygame.key.get_pressed()


                              Sauf erreur de ma part, on va récupèrer le dernier event KEY_DOWN ou KEY_UP de la file.

                              Alors en effet, on loupe certaines actions, mais en pratique pour des jeux de ce style, je demande à voir la perte réelle.
                              Sinon, si on utilise le polling il faut une variable supplémentaire, pour éviter au joueur de marteler la touche pour déplacer la figure.
                              En pratique je n'ai jamais constater de perte(notable pour le joueur), avec le mapping...
                              Après, pygame.key.get_pressed(), n'est peut-être pas ce que je crois, (l'équivalent de SDl_GetKeyState)?
                              Mais pour un jeu de ce style, ce ne sera pas ma première priorité.
                              ;)

                              J'ai d'ailleurs un débordement de tableau plus grave que je vais devoir corriger. :lol:
                              • Partager sur Facebook
                              • Partager sur Twitter
                              Zeste de Savoir, le site qui en a dans le citron !
                                10 novembre 2010 à 22:09:47

                                Citation

                                Alors en effet, on loupe certaines actions, mais en pratique pour des jeux de ce style, je demande à voir la perte réelle.


                                Y a quand même un manque flagrant de réactivité et c'est un jeu de rapidité ... non ? o_O
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  11 novembre 2010 à 5:03:08

                                  Citation : Josmiley


                                  Y a quand même un manque flagrant de réactivité et c'est un jeu de rapidité ... non ? o_O


                                  C'est vrai.
                                  Mais je pense, que c'est à cause de la tempo de 100ms que j'ai collé avant le flip dans la boucle principale, justement pour que ne soit pas trop réactif.
                                  C'est un peu du bricolage, mais ce n'est pas la faute du mapping.

                                  Par contre j'ai un bug sévère qui se produit de manière alétoire, il me semble, et qui rempli la figure courante jusqu'en haut du plateau de jeu. Je n'arrive pas à trouver l'erreur. :colere2:
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                  Zeste de Savoir, le site qui en a dans le citron !
                                    11 novembre 2010 à 8:00:06

                                    Citation : GurneyH


                                    Mais je pense, que c'est à cause de la tempo de 100ms que j'ai collé avant le flip dans la boucle principale, justement pour que ne soit pas trop réactif.
                                    C'est un peu du bricolage, mais ce n'est pas la faute du mapping.



                                    ben oui, ça oblige à maintenir la touche au moins 100ms, mais bon, si c'est fait exprès ^^
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      11 novembre 2010 à 8:40:46

                                      Citation : Josmiley


                                      ben oui, ça oblige à maintenir la touche au moins 100ms, mais bon, si c'est fait exprès ^^


                                      Si je ne met pas de tempo c'est injouable en fait. :p(les rotations vont bien trop vite).
                                      Je vais rejouer à un "vrai tetris", il ne me semble pas qu'on était obligé d'appuyer plusieurs fois pour se déplacer de 2 cases par exemple.

                                      edit: Je viens de vérifier, sur la snes, on se déplace en maintenant appuyer, pour les rotations, il faut appuyer plusieurs fois.
                                      Je vais pouvoir virer ma tempo!
                                      :)
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                      Zeste de Savoir, le site qui en a dans le citron !
                                        11 novembre 2010 à 14:46:31

                                        Bravo à GurneyH et josmiley, très bons vos petits jeux ! Et des jeux comme ça c'est une super pub pour Python !
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          11 novembre 2010 à 15:29:33

                                          Bon, désolé, je n'ai pas eu le temps de corriger mon design (dont je ne suis pas fier), mais mon tetris ("loltriz") se trouve ici. Il s'agit d'un de mes premiers projets en python.

                                          pour le lancer, il suffit de lancer python 2.x sur le fichier "loltriz.py"

                                          Voici un screenshot :
                                          Image utilisateur
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                          Zeste de Savoir, le site qui en a dans le citron !
                                            11 novembre 2010 à 16:46:27

                                            Citation : NoHaR

                                            Bon, désolé, je n'ai pas eu le temps de corriger mon design (dont je ne suis pas fier), mais mon tetris ("loltriz") se trouve ici. Il s'agit d'un de mes premiers projets en python.




                                            Joli projet !

                                            En tant que joueur, voici mon avis : jeu fluide et qui se joue très bien. Je trouve très bonne l'idée de mettre une image de la cible (j'aurais juste mis une couleur plus claire peut-être). Je trouve par contre assez gênant le contour non bien rectiligne ainsi que la police peu lisible ainsi aussi que l'absence de couleurs (ça reste des détails car le jeu est très bon).


                                            Du point de vue du code, je ne suis pas assez connaisseur pour pouvoir juger de façon compétente. J'ai l'impression que les concepts OO de ton code sont assez simples, tu crées des classes ok mais tu utilises à peine l'héritage (class OptionToggler). Sinon, il y a quand même quelque chose qui me gêne : c'est que par exemple ton moteur de jeu appelle Pygame. Ce que je trouve dommage -- mais ce n'était sans doute pas dans ton projet initial, -- c'est que ton code implémente un Tétris mais ne me semble pas du tout réutilisable si on veut coder un Tétris avec Tkinter ou PyQt. Or, un Tétris reste un Tétris, le principe du jeu ne change pas quelle que soit le GUI utilisé et je trouve qu'il est dommage d'avoir à coder plusieurs fois la même chose. Maintenant, peut-être que ce dont je parle là est difficile à implémenter, je serais curieux d'avoir ton avis.
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              12 novembre 2010 à 9:36:02

                                              Citation : NoHaR

                                              Bon, désolé, je n'ai pas eu le temps de corriger mon design (dont je ne suis pas fier), mais mon tetris ("loltriz") se trouve ici. Il s'agit d'un de mes premiers projets en python.

                                              pour le lancer, il suffit de lancer python 2.x sur le fichier "loltriz.py"

                                              Voici un screenshot :
                                              Image utilisateur



                                              Je trouve le design excellent.
                                              j'vais essayer d'intégrer le 'shadow' à mon code, tiens ...

                                              Citation : candide

                                              <citation rid="5595737">
                                              Du point de vue du code, je ne suis pas assez connaisseur pour pouvoir juger de façon compétente. J'ai l'impression que les concepts OO de ton code sont assez simples, tu crées des classes ok mais tu utilises à peine l'héritage (class OptionToggler). Sinon, il y a quand même quelque chose qui me gêne : c'est que par exemple ton moteur de jeu appelle Pygame. Ce que je trouve dommage -- mais ce n'était sans doute pas dans ton projet initial, -- c'est que ton code implémente un Tétris mais ne me semble pas du tout réutilisable si on veut coder un Tétris avec Tkinter ou PyQt. Or, un Tétris reste un Tétris, le principe du jeu ne change pas quelle que soit le GUI utilisé et je trouve qu'il est dommage d'avoir à coder plusieurs fois la même chose. Maintenant, peut-être que ce dont je parle là est difficile à implémenter, je serais curieux d'avoir ton avis.



                                              je suis assez d'accord avec candide au sujet du OO; j'essaie souvent de créer des class dont les objets peuvent évoluer indépendament de l'environnement. Mais en graphique, ces objets devraient se tenir informé de l'environnement dans lequel ils évoluent, ne serait-ce que pour afficher un truc au bon endroit. Et là, la 'généralisation' de la class compliquerait plus le code qu'autre chose, amha.

                                              Par contre, en séparant le 'calcul' du 'rendu' ...
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                12 novembre 2010 à 13:06:48

                                                Merci Candide et josmiley.

                                                Bon étant donné que c'est moi qui ai commis réalisé ce code, je vais me permettre d'être très critique dessus.

                                                L'intention


                                                Comme je l'ai dit, il s'agit de l'un des tous premiers projets que j'ai réalisés avec Python pour me faire la main dessus.

                                                Le but était d'obtenir un jeu avec un design visuel rigolo style "dessiné au marqueur sur un tableau blanc", d'où les lignes non-rectilignes (mais un peu quand même) et la police difficile à lire. Je suis d'accord sur le manque de couleur, et c'est un problème très difficile à régler en l'état à cause de certains problèmes de conception. J'ai mis pas mal l'accent sur la jouabilité, cependant, parce que j'avais pour ce jeu un client direct et très exigeant : ma copine. :p

                                                La conception et ses lourdeurs


                                                Pour résumer, je qualifierais cette conception d'intermédiaire. L'accent n'a pas du tout été mis dessus, mais quelques éléments ont été faits avec un certain soucis de réutilisabilité (comme le menu, que je voulais utilisable "un peu comme dans n'importe quelle lib graphique", et pour lequel j'ai essayé de jouer avec le "tout-est-objet" de Python — le OptionToggler en est un bon exemple, quoi que très perfectible avec le recul —).

                                                Pour ce qui est des concepts OO que je n'utilise pas beaucoup (ou qui ne sont pas très respectés), je dirais que le problème ne vient pas nécessairement du manque d'héritage, mais qu'il est plus "bas" encore conceptuellement : mes classes ne sont pas toutes à responsabilité unique (beaucoup sont des do-it-all classes, très difficiles à re-factoriser et maintenir en l'état), et je n'ai pas assez eu le soucis de définir une interface publique (ou classe "virtuelle") pour chaque composant, implémentée par la suite par des classes filles. En conséquence, on se retrouve avec un moteur peu hiérarchisé, qui dépend effectivement de Pygame : le couplage entre l'abstraction et l'implémentation est beaucoup trop fort (d'autant plus que les mécanismes que j'utilise pour l'affichage ne sont vraiment, vraiment pas performants, bien que cela ne se sente pas du tout à l'utilisation).

                                                Si j'avais à recoder ce jeu avec l'intention que son code soit "visible", je pense que j'aurais une conception plus claire :
                                                * Les abstractions (le "moteur de jeu" actuel) seraient bien séparées du reste (plus qu'actuellement).
                                                * Le système d'affichage serait plus optimisé, notamment en dérivant les classes pièces et en utilisant des "dirty sprites", afin d'éviter de redessiner tout l'écran à chaque fois.

                                                Pour ce qui est du moteur, par contre, dans un jeu comme celui-ci, il est nécessairement beaucoup plus simple de le faire dépendre de la bibliothèque : si le but était de créer un moteur générique pour un Tetris, il faudrait le spécifier à la base, et ça demande de créer beaucoup plus d'abstractions : dans un cas simple comme ici (le système du jeu n'étant vraiment pas complexe), on peut raisonnablement dépendre de Pygame, c'est un choix qui me semble acceptable pour trouver l'équilibre entre la modularité du design (qui demande de créer plein de petites classes hiérarchisées à responsabilité unique, typiquement) et la simplicité du code.
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                Zeste de Savoir, le site qui en a dans le citron !
                                                  12 novembre 2010 à 20:24:56

                                                  Je viens juste de regarder le screenshot du jeu de NoHar.

                                                  C'est sympa, il va falloir que j'essaye le jeu.

                                                  Sinon, coder un Tétris, ça intéresse 3 personnes? o_O
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                  Zeste de Savoir, le site qui en a dans le citron !
                                                    12 novembre 2010 à 23:02:03

                                                    merci pour les feedback que vous allez poster :p
                                                    Pitêtre modifer les couleurs...
                                                    http://joel-murielle.perso.sfr.fr/tetrisdz.zip
                                                    from pygame import *
                                                    from random import randint
                                                    
                                                    font.init()
                                                    
                                                    empty_ligne = 2049
                                                    all_set = 4095
                                                    tableau = [empty_ligne]*(24)+[all_set]
                                                    
                                                    mask = image.load('masktetris.png')
                                                    red = Surface((300,30),SRCALPHA)
                                                    red.fill((255,0,0,100))
                                                    font0 = font.Font('FreeMonoBold.ttf',20)
                                                    
                                                    objet = [
                                                            [[0, 0, 128, 224], [0, 192, 128, 128], [0, 0, 224, 32], [0, 64, 64, 192],(255,0,0)],
                                                            [[0, 0, 64, 224], [0, 64, 96, 64], [0, 0, 224, 64], [0, 32, 96, 32],(100,100,0)],
                                                            [[0, 0, 96, 192], [0, 64, 96, 32], [0, 0, 96, 192], [0, 64, 96, 32],(0,100,100)],
                                                            [[0, 0, 192, 96], [0, 32, 96, 64], [0, 0, 192, 96], [0, 32, 96, 64],(0,0,255)],
                                                            [[0, 0, 32, 224], [0, 64, 64, 96], [0, 0, 112, 64], [0, 96, 32, 32],(0,255,0)],
                                                            [[0, 0, 96, 96], [0, 0, 96, 96], [0, 0, 96, 96], [0, 0, 96, 96],(100,255,100)],
                                                            [[0, 0, 0, 240], [64, 64, 64, 64], [0, 0, 0, 240], [32, 32, 32, 32],(100,0,100)]
                                                            ]
                                                    
                                                    screen = display.set_mode((480,600))
                                                    bgcolor = 0xd0d0d0
                                                    bg = Surface((300,720)); bg.fill(bgcolor)
                                                    key.set_repeat(50,50)
                                                    
                                                    score = 0
                                                    speed = 30
                                                    S = 0
                                                    
                                                    time.set_timer(KEYDOWN,speed)
                                                    screen.blit(font0.render('score: '+str(score),1,(200,200,200)),(330,300))
                                                    screen.blit(font0.render('speed: '+str(0),1,(200,200,200)),(330,330))
                                                    
                                                    k_up_is_up = False
                                                    k_space_is_up = False
                                                    
                                                    test = lambda shift,down,rotation: not any([int(i*shift)&tableau[e] for e,i in enumerate(obj[(one+rotation)%4],ligne+down)])
                                                    
                                                    def make_surf(index,one):
                                                        img = Surface([120]*2,SRCALPHA)
                                                        img.fill((0,0,0,0))
                                                        shadow = img.copy()
                                                        color = objet[index][-1]
                                                        for y,i in enumerate(objet[index][one]):
                                                            i /= 16
                                                            for x in 90,60,30,0:
                                                                if i&1:
                                                                    img.blit(mask,img.fill(color,(x,y*30,30,30)))
                                                                    shadow.fill(color+(50,)if shadow_set else bgcolor,(x,y*30,30,30))
                                                                i /= 2
                                                        return img,shadow
                                                    
                                                    def YShadowUpdate():
                                                        global ligne,Yshadow
                                                        C = ligne
                                                        while test(1,1,0): ligne+=1
                                                        Yshadow = (ligne-4)*30
                                                        ligne = C
                                                    
                                                    Yshadow = ligne = 1
                                                    shadow_set = False
                                                    next_index = randint(0,6)
                                                    next_one = randint(0,3)
                                                    next_imgs = make_surf(next_index,next_one)
                                                    while ligne:
                                                        event.clear()
                                                        Y = -120
                                                        X = 90
                                                        ligne = 0
                                                        index = next_index
                                                        one = next_one
                                                        img,shadow = next_imgs
                                                        obj = objet[index]
                                                        next_index = randint(0,6)
                                                        next_one = randint(0,3)
                                                        next_imgs = make_surf(next_index,next_one)
                                                        screen.blit(transform.scale(next_imgs[0],(60,60)),screen.fill(0,(30*12,60,60,60)))
                                                        YShadowUpdate()
                                                        while True:
                                                            ev = event.wait()
                                                            if ev.type == KEYDOWN:
                                                                if not ev.key or ev.key== K_DOWN:
                                                                    if not Y%30:
                                                                        if test(1,1,0): ligne+=1
                                                                        else:
                                                                            bg.blit(img,(X,ligne*30))
                                                                            s = 0
                                                                            for e,i in enumerate(obj[one],ligne):
                                                                                tableau[e] = tableau[e]|i
                                                                                if tableau[e] == all_set:
                                                                                    S += 1
                                                                                    if not S%10: speed -= 1; time.set_timer(KEYDOWN,speed)
                                                                                    s += 1
                                                                                    score += s**2
                                                                                    del(tableau[e]); tableau.insert(0,empty_ligne)
                                                                                    display.update(screen.blit(red,(0,(e-4)*30)))
                                                                                    time.wait(300)
                                                                                    bg.blit(bg,(0,30),(0,0,300,(e)*30))
                                                                                    bg.fill(bgcolor,(0,0,30*10,30))
                                                                                    screen.fill(0,(330,300,120,60))
                                                                                    screen.blit(font0.render('score: '+str(score),1,(200,200,200)),(330,300))
                                                                                    screen.blit(font0.render('speed: '+str(30-speed),1,(200,200,200)),(330,330))
                                                                                    screen.blit(bg,(0,0),(0,120,300,(e)*30))
                                                                                    display.flip()
                                                                            break
                                                                    if not ev.key: Y += 3
                                                                    else: Y = (ligne-4)*30
                                                                    screen.blit(bg,(0,-120))
                                                                    screen.blit(shadow,(X,Yshadow))
                                                                    screen.blit(img,(X,Y))
                                                                    display.flip(); continue
                                                                elif ev.key == K_LEFT:
                                                                    if test(2,0,0): obj = [[j<<1 for j in i]for i in obj]; X -= 30; YShadowUpdate(); continue
                                                                elif ev.key == K_RIGHT:
                                                                    if test(0.5,0,0): obj = [[j>>1 for j in i]for i in obj]; X += 30; YShadowUpdate(); continue
                                                                elif ev.key == K_UP and not k_up_is_up:
                                                                    k_up_is_up = True
                                                                    if test(1,0,1): one = (one+1)%4; img,shadow = make_surf(index,one); YShadowUpdate(); continue
                                                                elif ev.key == K_SPACE and not k_space_is_up:
                                                                    display.update((screen.blit(bg,(X,Y),(X,Y,120,120)),screen.blit(img,(X,Yshadow))))
                                                                    Y = Yshadow; ligne = Yshadow/30+4; k_space_is_up = True; continue
                                                            elif ev.type == KEYUP:
                                                                if ev.key == K_UP: k_up_is_up = False; continue
                                                                elif ev.key == K_SPACE: k_space_is_up = False; continue
                                                                elif ev.key == K_p:
                                                                    while event.wait().type != KEYUP: pass
                                                                    continue
                                                                elif ev.key == K_s:
                                                                    shadow_set = not shadow_set
                                                                    img,shadow = make_surf(index,one)
                                                                    continue
                                                            elif ev.type == QUIT: exit()
                                                    while event.wait().type != QUIT: pass
                                                    

                                                    touches classiques
                                                    'p' pour pause
                                                    's' pour shadow on/off
                                                    Image utilisateur
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      13 novembre 2010 à 12:06:42

                                                      Pareil pour moi, une deuxième version du Tétris.

                                                      import pygame
                                                      import random
                                                      import os
                                                       
                                                      BLOCK_SIZE = 16
                                                      GRID_WIDTH, GRID_HEIGHT = 10, 20
                                                      RESOLUTION = (352, 352)
                                                      TICK_INTERVAL  = 50
                                                      EMPTY = -1
                                                      ROTL, ROTR = 1, 2
                                                      # -----------------------------------------------------------------------------
                                                      class TTFont:
                                                          def __init__(self, path, sz = 16):
                                                              self.font = pygame.font.Font(path, sz)
                                                             
                                                          def displayBlended(self, str, x, y, color = (255, 255, 255)):
                                                              screen = pygame.display.get_surface()
                                                              srf = self.font.render(str, True, (0, 0, 0))
                                                              screen.blit(srf, (x + 1, y + 1, 0, 0))
                                                              srf = self.font.render(str, True, color)
                                                              screen.blit(srf, (x, y, 0, 0))
                                                             
                                                      # -----------------------------------------------------------------------------
                                                      class Input:
                                                          def __init__(self):
                                                              self.quit = False
                                                              self.up = False
                                                              self.down = False
                                                              self.left = False
                                                              self.right = False
                                                              self.w = False
                                                              self.x = False
                                                              self.s = False
                                                              
                                                          def update(self):
                                                               for event in pygame.event.get():
                                                                  if event.type == pygame.QUIT:
                                                                      self.quit = True
                                                                      
                                                                  if event.type == pygame.KEYDOWN:
                                                                      if event.key == pygame.K_LEFT:
                                                                          self.left = True
                                                                      if event.key == pygame.K_RIGHT:
                                                                          self.right = True
                                                                      if event.key == pygame.K_UP:
                                                                          self.up = True
                                                                      if event.key == pygame.K_DOWN:
                                                                          self.down = True
                                                                      if event.key == pygame.K_w:
                                                                          self.w = True
                                                                      if event.key == pygame.K_x:
                                                                          self.x = True
                                                                      if event.key == pygame.K_s:
                                                                          self.s = True
                                                                  if event.type == pygame.KEYUP:
                                                                      if event.key == pygame.K_LEFT:
                                                                          self.left = False
                                                                      if event.key == pygame.K_RIGHT:
                                                                          self.right = False
                                                                      if event.key == pygame.K_UP:
                                                                          self.up = False
                                                                      if event.key == pygame.K_DOWN:
                                                                          self.down = False
                                                                      if event.key == pygame.K_w:
                                                                          self.w = False
                                                                      if event.key == pygame.K_x:
                                                                          self.x = False
                                                                      if event.key == pygame.K_s:
                                                                          self.s = False
                                                      # -------------------------------------------------------------
                                                      class Figure:
                                                          tetriminos =    ((-2,  0), (-1,  0), ( 0,  0), ( 1,  0)),           \
                                                                          ((-1,  1), ( 0,  1), (-1,  0), ( 0,  0)),           \
                                                                          ((-1,  0), ( 0,  0), ( 1,  0), ( 0,  1)),           \
                                                                          ((-1,  0), ( 0,  0), ( 1,  0), ( 1,  1)),           \
                                                                          ((-1,  0), ( 0,  0), ( 1,  0), (-1,  1)),           \
                                                                          ((-1,  0), ( 0,  0), ( 0,  1), ( 1,  1)),           \
                                                                          (( 0,  0), ( 1,  0), (-1,  1), ( 0,  1))
                                                          
                                                          def __init__(self, id):
                                                              self.x, self.y = GRID_WIDTH / 2, 0
                                                              self.id = id
                                                              self.blocks = [[b[0], b[1]] for b in Figure.tetriminos[id]]
                                                              
                                                          def checkPos(self, x, y, grid):
                                                              for b in self.blocks:
                                                                  nxtX, nxtY = x + b[0], y + b[1] 
                                                                  if nxtX < 0 or nxtX >= GRID_WIDTH or nxtY >= GRID_HEIGHT or grid[nxtY][nxtX] != EMPTY:
                                                                      return False
                                                              return True
                                                          
                                                          def setPos(self, x, y):
                                                              self.x, self.y = x, y
                                                                 
                                                          def checkRotate(self, grid, rot):
                                                              for b in self.blocks:
                                                                  if rot == ROTL:
                                                                      nxtX, nxtY = self.x + b[1], self.y - b[0]
                                                                  else:
                                                                      nxtX, nxtY = self.x - b[1], self.y + b[0]
                                                                  if nxtX < 0 or nxtX >= GRID_WIDTH or nxtY >= GRID_HEIGHT \
                                                                                                      or grid[nxtY][nxtX] != EMPTY:
                                                                      return False
                                                              return True
                                                          
                                                          def rotate(self, rot):
                                                              for b in self.blocks:
                                                                  if rot == ROTL:
                                                                      b[0], b[1] = b[1], -b[0]
                                                                  else:
                                                                      b[0], b[1] = -b[1], b[0]
                                                                      
                                                          def display(self, srf, id):
                                                              screen = pygame.display.get_surface()
                                                              for b in self.blocks:
                                                                  x, y = self.x + b[0], self.y + b[1]
                                                                  if y >= 0:
                                                                      srcRect = (id * BLOCK_SIZE, 0, BLOCK_SIZE, BLOCK_SIZE)
                                                                      dstRect = (16 + x * BLOCK_SIZE, 16 + y * BLOCK_SIZE, 0, 0)
                                                                      screen.blit(srf, dstRect, srcRect)
                                                                        
                                                      # ----------------------------------------------------------------------------
                                                      class Playfield:
                                                          scoreLines = (0, 40, 100, 300, 1200)
                                                          def __init__(self):
                                                              self.grid = [[EMPTY for i in xrange(GRID_WIDTH)] \
                                                                                  for j in xrange(GRID_HEIGHT)]
                                                              self.nxtFigure = Figure(random.randrange(7))
                                                              self.crtFigure = Figure(random.randrange(7))
                                                              self.shadow = Figure(self.crtFigure.id)
                                                              self.shadowActivate = True
                                                              self.speed = 750
                                                              self.nxtTime = pygame.time.get_ticks() + self.speed
                                                              self.dropped = 0
                                                              self.score = 0
                                                              self.lines = 0
                                                              self.totalLines = 0
                                                              self.level = 1
                                                              self.statistics = 7 * [0]
                                                              self.srfBackground = pygame.image.load("background1.png")
                                                              self.srfBlocks = pygame.image.load("blocks.png")
                                                              self.font = TTFont("arial.ttf")
                                                          
                                                          def toogleShadow(self):
                                                              self.shadowActivate = 1 - self.shadowActivate
                                                              
                                                          def update(self, dx, dy, rot, hardDrop):
                                                              if rot:
                                                                  self.updateRotate(rot)
                                                              if hardDrop:
                                                                  while self.updateMove(self.crtFigure, 0, 1):
                                                                      pass
                                                              if dx or dy:
                                                                  self.updateMove(self.crtFigure, dx, dy)
                                                              
                                                              self.shadow.blocks = self.crtFigure.blocks
                                                              self.shadow.setPos(self.crtFigure.x, self.crtFigure.y)
                                                              while self.updateMove(self.shadow, 0, 1):
                                                                  pass
                                                              
                                                              crtTime = pygame.time.get_ticks()
                                                              if crtTime > self.nxtTime:
                                                                  x, y = self.crtFigure.x, self.crtFigure.y + 1
                                                                  if self.crtFigure.checkPos(x, y, self.grid):
                                                                      self.crtFigure.setPos(x, y)
                                                                  else :
                                                                      self.storeFigure()
                                                                      if self.checkGameOver():
                                                                          return true
                                                                      self.crtFigure = self.nxtFigure
                                                                      self.nxtFigure = Figure(random.randrange(7))
                                                                      self.shadow = Figure(self.crtFigure.id)
                                                                      self.dropped = 0
                                                                      self.lines = 0
                                                                  self.nxtTime = crtTime + self.speed
                                                                   
                                                                  return False
                                                          
                                                          def updateRotate(self, rot):
                                                              if self.crtFigure.checkRotate(self.grid, rot):
                                                                      self.crtFigure.rotate(rot)
                                                          
                                                          def updateMove(self, fg, dx, dy):
                                                              x, y = fg.x + dx, fg.y + dy
                                                              if not fg.checkPos(x, y, self.grid):
                                                                  return False
                                                              else :
                                                                  fg.setPos(x, y)
                                                                  if dy:
                                                                      self.dropped += 1
                                                              return True
                                                          
                                                          def storeFigure(self):
                                                              for b in self.crtFigure.blocks:
                                                                  x, y = self.crtFigure.x + b[0], self.crtFigure.y + b[1]
                                                                  self.grid[y][x] = self.crtFigure.id
                                                              self.checkLines()
                                                              self.score += self.dropped
                                                              self.score += Playfield.scoreLines[self.lines] * (self.level + 1)
                                                              self.totalLines += self.lines
                                                              self.level = (self.totalLines / 10) + 1
                                                              self.speed = 800 - self.level * 50   
                                                              self.statistics[self.crtFigure.id] += 1
                                                              
                                                          def checkLines(self):
                                                              for i, row in enumerate(self.grid):
                                                                  full = True
                                                                  for j, case in enumerate(row):
                                                                      if case < 0:
                                                                          full = False
                                                                          break
                                                                  if full:
                                                                      self.deleteLine(i)
                                                                      self.lines += 1
                                                                      
                                                          def deleteLine(self, row):
                                                              for i in range(row, 1, -1):
                                                                  self.grid[i] = self.grid[i - 1] 
                                                                  self.grid[i - 1] = GRID_WIDTH * [EMPTY]
                                                              
                                                          def checkGameOver(self):
                                                              for case in self.grid[0]:
                                                                  if case != EMPTY:
                                                                      return True
                                                              return False
                                                          
                                                          def display(self):
                                                              screen = pygame.display.get_surface()
                                                              screen.blit(self.srfBackground, (0, 0, 0, 0))
                                                             
                                                              for i, row in enumerate(self.grid):
                                                                  for j, case in enumerate(row):
                                                                      if self.grid[i][j] >= 0:
                                                                          srcRect = (self.grid[i][j] * BLOCK_SIZE, 0, 16, 16)
                                                                          dstRect = (16 + j * BLOCK_SIZE, 16 + i * BLOCK_SIZE, 0, 0)
                                                                          screen.blit(self.srfBlocks, dstRect, srcRect)
                                                              
                                                              if self.shadowActivate:
                                                                  self.shadow.display(self.srfBlocks, 7)
                                                              self.crtFigure.display(self.srfBlocks, self.crtFigure.id)
                                                              self.nxtFigure.setPos(GRID_WIDTH + 5, 1)
                                                              self.nxtFigure.display(self.srfBlocks, self.nxtFigure.id)
                                                              self.nxtFigure.setPos(GRID_WIDTH / 2, 0)
                                                          
                                                              self.font.displayBlended("Score : " + str(self.score), 204, 108)
                                                              self.font.displayBlended("Level : " + str(self.level), 204, 125)
                                                              self.font.displayBlended("Lines : " + str(self.totalLines), 204, 142)
                                                              
                                                              for i in xrange(7):
                                                                  srcRect = (i * BLOCK_SIZE, 0, BLOCK_SIZE, BLOCK_SIZE)
                                                                  dstRect = (214, 165 + i * 25, 0, 0)
                                                                  screen.blit(self.srfBlocks, dstRect, srcRect)
                                                                  self.font.displayBlended(str(self.statistics[i]), 235, 160 + i * 25)
                                                      # -----------------------------------------------------------------------------
                                                      class Game:
                                                          def __init__(self):
                                                              pygame.init()
                                                              pygame.font.init()
                                                              pygame.display.set_mode(RESOLUTION)
                                                              pygame.display.set_caption("ZTris !!!")
                                                              self.input = Input()
                                                              self.playfield = Playfield()
                                                              
                                                          def timeLeft(self):
                                                              now = pygame.time.get_ticks()
                                                              if self.nxtTime <= now:
                                                                  return 0
                                                              else:
                                                                  return self.nxtTime - now;
                                                      
                                                          def run(self):
                                                              gameOver = False
                                                              self.nxtTime = pygame.time.get_ticks() 
                                                              while not self.input.quit and not gameOver:
                                                                  dx, dy = 0, 0
                                                                  rotate = False
                                                                  hardDrop = False
                                                                  self.input.update()
                                                                  if self.input.left:
                                                                      dx = -1
                                                                  if self.input.right:
                                                                      dx = 1
                                                                  if self.input.down:
                                                                      dy = 1
                                                                  if self.input.up:
                                                                      self.input.up = False
                                                                      hardDrop = True
                                                                  if self.input.w:
                                                                      self.input.w = False
                                                                      rotate = ROTL
                                                                  if self.input.x:
                                                                      self.input.x = False
                                                                      rotate = ROTR
                                                                  if self.input.s:
                                                                      self.input.s = False
                                                                      self.playfield.toogleShadow()
                                                                      
                                                                  gameOver = self.playfield.update(dx, dy, rotate, hardDrop)
                                                                  self.playfield.display()
                                                                  
                                                                  pygame.time.delay(self.timeLeft())
                                                                  self.nxtTime += TICK_INTERVAL
                                                      
                                                                  pygame.display.flip()
                                                      
                                                      game = Game()
                                                      game.run()
                                                      


                                                      J'ai rajouté Level, scores, statistiques, hard drop et shadow.
                                                      Et... Le code est de pire en pire :honte:

                                                      Un screen
                                                      Image utilisateur


                                                      les images nécessaires.

                                                      background1.png
                                                      Image utilisateur

                                                      blocks.png
                                                      Image utilisateur


                                                      Ces images sont à mettre dans le même répertoire que le code.
                                                      Il faut aussi placer arial.ttf dans ce répertoire.

                                                      Go snake, alors. :p

                                                      edit:
                                                      les touches :
                                                      w et x pour les rotations.
                                                      haut pour hard drop
                                                      bas pour soft drop
                                                      s pour activer/désactiver l'ombre.
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                      Zeste de Savoir, le site qui en a dans le citron !
                                                        13 novembre 2010 à 12:16:20

                                                        Josmiley et GurneyH : joli !

                                                        Ah oui j'ai oublié de préciser les touches pour le mien :

                                                        gauche-droite pour bouger
                                                        haut pour une rotation
                                                        bas pour soft drop
                                                        espace pour hard drop

                                                        :D
                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                        Zeste de Savoir, le site qui en a dans le citron !
                                                          13 novembre 2010 à 13:40:10

                                                          Punaise, en voyant mon screen avec un score de 5602, au level 1 avec 0 lignes, j'ai un gros doute! :honte:

                                                          En tout cas merci, Josmiley! ;)
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                          Zeste de Savoir, le site qui en a dans le citron !
                                                            13 novembre 2010 à 20:25:11

                                                            heu ... si j'avais mis un lien ça l'aurait mieux fait non ? :phttp://joel-murielle.perso.sfr.fr/tetrisdz.zip


                                                            Citation : GurneyH


                                                            En tout cas merci, Josmiley! ;)


                                                            de quoi ? o_O
                                                            • Partager sur Facebook
                                                            • Partager sur Twitter
                                                              13 novembre 2010 à 20:33:59

                                                              Au hasard, pour tes initiatives intéressantes et ton implication dans la communauté Pygamienne du SdZ ?
                                                              • Partager sur Facebook
                                                              • Partager sur Twitter
                                                              Zeste de Savoir, le site qui en a dans le citron !

                                                              [pygame][mini-projet] Tetris

                                                              × 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