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