Cette fois, j'ai fait un jeu de style Tetris en utilisant tkinter de Python. Le programme étant devenu assez long, j'omettrai l'explication de manière significative, mais je n'expliquerai que les points.
Il y avait 4 types dans le programme du site auquel je faisais référence, mais j'ai essayé d'en faire 7 types avec un peu d'ingéniosité.
Tetrimino comprend les éléments suivants.
  Tミノ    
  Zミノ      
  Iミノ        
  Lミノ
  Jミノ     
  Oミノ      
  Sミノ
  
L'écran de jeu a 20 carrés verticalement et 10 carrés horizontalement.
Si vous appuyez sur le bouton Démarrer sur le côté droit, Tetrimino descendra et le jeu commencera.
Semblable au Tetris original, si une ligne horizontale est alignée, une ligne disparaît et si Tetrimino est empilé vers le haut, le jeu est terminé.
←ゲームオーバー時の表示
Cependant, il convient de noter que contrairement au Tetris original, Tetrimino ne peut pas être tourné. Par conséquent, la difficulté de survivre pendant longtemps a considérablement augmenté. Au fait, j'ai aussi essayé le jeu de test, mais j'ai eu du mal.
# -*- coding:utf-8 -*-
import tkinter as tk
import random      
#constant
BLOCK_SIZE = 25  #Taille verticale et horizontale du bloc px
FIELD_WIDTH = 10  #Largeur du champ
FIELD_HEIGHT = 20  #Hauteur du champ
MOVE_LEFT = 0  #Constante indiquant de déplacer le bloc vers la gauche
MOVE_RIGHT = 1  #Constante indiquant de déplacer le bloc vers la droite
MOVE_DOWN = 2  #Constante indiquant de déplacer le bloc vers le bas
#Classe carrée qui compose le bloc
class TetrisSquare():
    def __init__(self, x=0, y=0, color="gray"):
        'Créer un carré'
        self.x = x
        self.y = y
        self.color = color
    def set_cord(self, x, y):
        'Définissez les coordonnées du carré'
        self.x = x
        self.y = y
    def get_cord(self):
        'Obtenez les coordonnées du carré'
        return int(self.x), int(self.y)
    def set_color(self, color):
        'Définir la couleur du carré'
        self.color = color
    def get_color(self):
        'Obtenez la couleur du carré'
        return self.color
    def get_moved_cord(self, direction):
        'Obtenez les coordonnées du carré après le déplacement'
        #Obtenez les coordonnées du carré avant de vous déplacer
        x, y = self.get_cord()
        #Calculez les coordonnées après le déplacement en tenant compte de la direction du déplacement
        if direction == MOVE_LEFT:
            return x - 1, y
        elif direction == MOVE_RIGHT:
            return x + 1, y
        elif direction == MOVE_DOWN:
            return x, y + 1
        else:
            return x, y
#Classe de toile pour dessiner l'écran Tetris
class TetrisCanvas(tk.Canvas):
    def __init__(self, master, field):
        'Créez une toile pour dessiner Tetris'
        canvas_width = field.get_width() * BLOCK_SIZE
        canvas_height = field.get_height() * BLOCK_SIZE
        # tk.Initiation à la classe de toile
        super().__init__(master, width=canvas_width, height=canvas_height, bg="white")
        #Placez la toile sur l'écran
        self.place(x=25, y=25)
        #Créez un écran Tetris en dessinant des carrés de 10 x 20
        for y in range(field.get_height()):
            for x in range(field.get_width()):
                square = field.get_square(x, y)
                x1 = x * BLOCK_SIZE
                x2 = (x + 1) * BLOCK_SIZE
                y1 = y * BLOCK_SIZE
                y2 = (y + 1) * BLOCK_SIZE
                self.create_rectangle(
                    x1, y1, x2, y2,
                    outline="white", width=1,
                    fill=square.get_color()
                )
        #Définir le champ précédemment dessiné
        self.before_field = field
    def update(self, field, block):
        'Mettre à jour l'écran Tetris'
        #Créer un champ de dessin (champ + bloc)
        new_field = TetrisField()
        for y in range(field.get_height()):
            for x in range(field.get_width()):
                square = field.get_square(x, y)
                color = square.get_color()
                new_square = new_field.get_square(x, y)
                new_square.set_color(color)
        #Combiner les informations de carré de bloc avec le champ
        if block is not None:
            block_squares = block.get_squares()
            for block_square in block_squares:
                #Obtenez les coordonnées et la couleur du carré du bloc
                x, y = block_square.get_cord()
                color = block_square.get_color()
                #Mettre à jour la couleur du carré sur le champ des coordonnées acquises
                new_field_square = new_field.get_square(x, y)
                new_field_square.set_color(color)
        #Dessiner sur un canevas à l'aide de champs de dessin
        for y in range(field.get_height()):
            for x in range(field.get_width()):
                # (x,y)Obtenir la couleur du champ de coordonnées
                new_square = new_field.get_square(x, y)
                new_color = new_square.get_color()
                # (x,y)Ne dessinez pas si les coordonnées n'ont pas changé depuis le dernier dessin
                before_square = self.before_field.get_square(x, y)
                before_color = before_square.get_color()
                if(new_color == before_color):
                    continue
                x1 = x * BLOCK_SIZE
                x2 = (x + 1) * BLOCK_SIZE
                y1 = y * BLOCK_SIZE
                y2 = (y + 1) * BLOCK_SIZE
                #Dessinez un rectangle avec la couleur de chaque position dans le champ
                self.create_rectangle(
                    x1, y1, x2, y2,
                    outline="white", width=1, fill=new_color
                )
        #Mettre à jour les informations du champ dessiné la dernière fois
        self.before_field = new_field
#Classe de champ qui gère les informations des blocs empilés
class TetrisField():
    def __init__(self):
        self.width = FIELD_WIDTH
        self.height = FIELD_HEIGHT
        #Champ Initialiser
        self.squares = []
        for y in range(self.height):
            for x in range(self.width):
                #Gérez les champs sous forme de liste d'instances carrées
                self.squares.append(TetrisSquare(x, y, "gray"))
    def get_width(self):
        'Obtenez le nombre de carrés dans le champ (horizontal)'
        return self.width
    def get_height(self):
        'Obtenez le nombre de carrés dans le champ (vertical)'
        return self.height
    def get_squares(self):
        'Obtenez une liste des carrés qui composent le champ'
        return self.squares
    def get_square(self, x, y):
        'Obtenez le carré aux coordonnées spécifiées'
        return self.squares[y * self.width + x]
    def judge_game_over(self, block):
        'Déterminez si le jeu est terminé'
        #Créer un ensemble de coordonnées déjà renseignées sur le terrain
        no_empty_cord = set(square.get_cord() for square
                            in self.get_squares() if square.get_color() != "gray")
        #Créer un ensemble de coordonnées avec des blocs
        block_cord = set(square.get_cord() for square
                         in block.get_squares())
        #Avec un ensemble de coordonnées de bloc
        #Créer un ensemble de produits d'ensembles de coordonnées déjà renseignés dans le champ
        collision_set = no_empty_cord & block_cord
        #Si l'ensemble de produits est vide, le jeu n'est pas terminé
        if len(collision_set) == 0:
            ret = False
        else:
            ret = True
        return ret
    def judge_can_move(self, block, direction):
        'Déterminer si le bloc peut être déplacé dans la direction spécifiée'
        #Créer un ensemble de coordonnées déjà renseignées sur le terrain
        no_empty_cord = set(square.get_cord() for square
                            in self.get_squares() if square.get_color() != "gray")
        #Création d'un ensemble de coordonnées avec le bloc déplacé
        move_block_cord = set(square.get_moved_cord(direction) for square
                              in block.get_squares())
        #Déterminez s'il est hors du terrain
        for x, y in move_block_cord:
            #Ne peut pas bouger s'il dépasse
            if x < 0 or x >= self.width or \
                    y < 0 or y >= self.height:
                return False
        #Avec l'ensemble des coordonnées du bloc après le déplacement
        #Créer un ensemble de produits d'ensembles de coordonnées déjà renseignés dans le champ
        collision_set = no_empty_cord & move_block_cord
        #Mobile si l'ensemble de produits est vide
        if len(collision_set) == 0:
            ret = True
        else:
            ret = False
        return ret
    def fix_block(self, block):
        'Fixer le bloc et ajouter au champ'
        for square in block.get_squares():
            #Obtenez les coordonnées et les couleurs des carrés contenus dans le bloc
            x, y = square.get_cord()
            color = square.get_color()
            #Refléter les coordonnées et la couleur dans le champ
            field_square = self.get_square(x, y)
            field_square.set_color(color)
    def delete_line(self):
        'Supprimer une ligne'
        #Vérifiez si toutes les lignes peuvent être supprimées
        for y in range(self.height):
            for x in range(self.width):
                #Il ne peut pas être effacé s'il y en a même un vide dans la ligne
                square = self.get_square(x, y)
                if(square.get_color() == "gray"):
                    #À la ligne suivante
                    break
            else:
                #Si elle n'est pas interrompue, la ligne est pleine
                #Supprimez cette ligne et déplacez la ligne au-dessus de cette ligne d'une ligne vers le bas
                for down_y in range(y, 0, -1):
                    for x in range(self.width):
                        src_square = self.get_square(x, down_y - 1)
                        dst_square = self.get_square(x, down_y)
                        dst_square.set_color(src_square.get_color())
                #La ligne du haut est toujours vide
                for x in range(self.width):
                    square = self.get_square(x, 0)
                    square.set_color("gray")
#Classe de bloc Tetris
class TetrisBlock():
    def __init__(self):
        'Créer un bloc de Tetris'
        #Liste des carrés qui composent le bloc
        self.squares = []
        #Déterminez aléatoirement la forme du bloc
        block_type = random.randint(1, 7)
        #Déterminez les coordonnées et les couleurs des quatre carrés en fonction de la forme du bloc
        if block_type == 1:
            color = "aqua"
            cords = [
                [FIELD_WIDTH / 2, 0],
                [FIELD_WIDTH / 2, 1],
                [FIELD_WIDTH / 2, 2],
                [FIELD_WIDTH / 2, 3],
            ]
        elif block_type == 2:
            color = "yellow"
            cords = [
                [FIELD_WIDTH / 2, 0],
                [FIELD_WIDTH / 2, 1],
                [FIELD_WIDTH / 2 - 1, 0],
                [FIELD_WIDTH / 2 - 1, 1],
            ]
        elif block_type == 3:
            color = "orange"
            cords = [
                [FIELD_WIDTH / 2 - 1, 0],
                [FIELD_WIDTH / 2, 0],
                [FIELD_WIDTH / 2, 1],
                [FIELD_WIDTH / 2, 2],
            ]
        elif block_type == 4:
            color = "blue"
            cords = [
                [FIELD_WIDTH / 2, 0],
                [FIELD_WIDTH / 2 - 1, 0],
                [FIELD_WIDTH / 2 - 1, 1],
                [FIELD_WIDTH / 2 - 1, 2],
            ] 
        elif block_type == 5:
            color = "red"
            cords = [
                [FIELD_WIDTH / 2, 0],
                [FIELD_WIDTH / 2, 1],
                [FIELD_WIDTH / 2 - 1, 1],
                [FIELD_WIDTH / 2 - 1, 2],
            ]     
        elif block_type == 6:
            color = "green"
            cords = [
                [FIELD_WIDTH / 2 - 1, 0],
                [FIELD_WIDTH / 2 - 1, 1],
                [FIELD_WIDTH / 2, 2],
                [FIELD_WIDTH / 2, 1],
            ]      
        elif block_type == 7:
            color = "purple"
            cords = [
                [FIELD_WIDTH / 2, 1],
                [FIELD_WIDTH / 2 - 1, 0],
                [FIELD_WIDTH / 2 - 1, 1],
                [FIELD_WIDTH / 2 - 1, 2],
            ]     
        #Créez un carré avec la couleur et les coordonnées déterminées et ajoutez-le à la liste
        for cord in cords:
            self.squares.append(TetrisSquare(cord[0], cord[1], color))
    def get_squares(self):
        'Obtenez les carrés qui composent le bloc'
        # return [square for square in self.squares]
        return self.squares
    def move(self, direction):
        'Déplacer les blocs'
        #Déplacez les carrés qui composent le bloc
        for square in self.squares:
            x, y = square.get_moved_cord(direction)
            square.set_cord(x, y)
#Classe qui contrôle le jeu Tetris
class TetrisGame():
    def __init__(self, master):
        'Instanciation de Tetris'
        #Initialiser la liste de gestion des blocs
        self.field = TetrisField()
        #Réglez le bloc de chute
        self.block = None
        #Définir l'écran Tetris
        self.canvas = TetrisCanvas(master, self.field)
        #Mise à jour de l'écran Tetris
        self.canvas.update(self.field, self.block)
    def start(self, func):
        'Démarrez Tetris'
        #Définir la fonction à appeler à la fin
        self.end_func = func
        #Initialiser la liste de gestion des blocs
        self.field = TetrisField()
        #Nouveau bloc d'automne ajouté
        self.new_block()
    def new_block(self):
        'Ajouter un nouveau bloc'
        #Créer une instance de bloc tombant
        self.block = TetrisBlock()
        if self.field.judge_game_over(self.block):
           self.end_func()
           print("Game Over!")
            #Mettre à jour l'écran Tetris
        self.canvas.update(self.field, self.block)
        
    def move_block(self, direction):
        'Déplacer les blocs'
        #Bouge seulement si tu peux bouger
        if self.field.judge_can_move(self.block, direction):
            #Déplacer les blocs
            self.block.move(direction)
            #Écran de mise à jour
            self.canvas.update(self.field, self.block)
        else:
            #Si le bloc ne peut pas descendre
            if direction == MOVE_DOWN:
                #Réparez le bloc
                self.field.fix_block(self.block)
                self.field.delete_line()
                self.new_block()
#Une classe qui accepte les événements et contrôle Tetris en fonction des événements
class EventHandller():
    def __init__(self, master, game):
        self.master = master
        #Jeu à contrôler
        self.game = game
        #Minuterie qui publie régulièrement des événements
        self.timer = None
        #Installer le bouton de démarrage du jeu
        button = tk.Button(master, text='START', command=self.start_event)
        button.place(x=25 + BLOCK_SIZE * FIELD_WIDTH + 25, y=30)
    def start_event(self):
        'Traitement lorsque le bouton de démarrage du jeu est enfoncé'
        #Démarrez Tetris
        self.game.start(self.end_event)
        self.running = True
        #Jeu de minuterie
        self.timer_start()
        #Commencer à accepter l'entrée d'opération de touche
        self.master.bind("<Left>", self.left_key_event)
        self.master.bind("<Right>", self.right_key_event)
        self.master.bind("<Down>", self.down_key_event)
    def end_event(self):
        'Traitement en fin de partie'
        self.running = False
        #Arrêtez d'accepter des événements
        self.timer_end()
        self.master.unbind("<Left>")
        self.master.unbind("<Right>")
        self.master.unbind("<Down>")
    def timer_end(self):
        'Minuterie de fin'
        if self.timer is not None:
            self.master.after_cancel(self.timer)
            self.timer = None
    def timer_start(self):
        'Démarrer la minuterie'
        if self.timer is not None:
            #Annuler la minuterie une fois
            self.master.after_cancel(self.timer)
        #Le minuteur démarre uniquement lorsque Tetris est en cours d'exécution
        if self.running:
            #Démarrer la minuterie
            self.timer = self.master.after(1000, self.timer_event)
    def left_key_event(self, event):
        'Traitement lors de l'acceptation de l'entrée de la touche gauche'
        #Déplacez le bloc vers la gauche
        self.game.move_block(MOVE_LEFT)
    def right_key_event(self, event):
        'Traitement lors de l'acceptation de l'entrée de la touche droite'
        #Déplacez le bloc vers la droite
        self.game.move_block(MOVE_RIGHT)
    def down_key_event(self, event):
        'Traitement lors de l'acceptation de l'entrée de la touche inférieure'
        #Déplacer le bloc vers le bas
        self.game.move_block(MOVE_DOWN)
        #Redémarrez la minuterie d'automne
        self.timer_start()
    def timer_event(self):
        'Traitement à l'expiration du minuteur'
        #Effectue le même traitement que lors de l'acceptation de l'entrée de la touche bas
        self.down_key_event(None)
class Application(tk.Tk):
    def __init__(self):
        super().__init__()
        #Paramètres de la fenêtre de l'application
        self.geometry("400x600")
        self.title("Tetris")
        #Génération Tetris
        game = TetrisGame(self)
        #Génération de gestionnaire d'événements
        EventHandller(self, game)
def main():
    'fonction principale'
    #Génération d'applications GUI
    app = Application()
    app.mainloop()
if __name__ == "__main__":
    main()
C'est dommage que nous n'ayons pas pu reproduire la rotation de Tetrimino, qui est le vrai frisson de Tetris, mais je pense que c'est un jeu que tout le monde peut apprécier. J'ai créé un jeu en utilisant Python pour la première fois, et quand je l'ai fait, le sentiment d'accomplissement était merveilleux. Ensuite, nous nous vengerons pour pouvoir fabriquer un Tetris rotatif!
https://daeudaeu.com/programming/python/tkinter/tetris/
Recommended Posts