Dieses Mal habe ich ein Spiel im Tetris-Stil mit tkinter of Python erstellt. Da das Programm ziemlich lang geworden ist, werde ich die Erklärung deutlich weglassen, aber ich werde nur die Punkte erklären.
Es gab 4 Typen im Programm der Site, auf die ich mich bezog, aber ich habe versucht, 7 Typen mit ein wenig Einfallsreichtum daraus zu machen. Tetrimino enthält Folgendes. Tミノ Zミノ Iミノ Lミノ Jミノ Oミノ Sミノ
Der Spielbildschirm hat 20 Felder vertikal und 10 Felder horizontal. Wenn Sie die Start-Taste auf der rechten Seite drücken, wird Tetrimino heruntergefahren und das Spiel gestartet. Ähnlich wie beim ursprünglichen Tetris verschwindet das Spiel, wenn eine horizontale Reihe ausgerichtet ist, eine Reihe verschwindet und wenn Tetrimino nach oben gestapelt ist. ←ゲームオーバー時の表示
Es ist jedoch zu beachten, dass Tetrimino im Gegensatz zum ursprünglichen Tetris nicht gedreht werden kann. Daher hat die Schwierigkeit, lange zu überleben, erheblich zugenommen. Übrigens habe ich auch Testspiele ausprobiert, aber es fiel mir schwer.
# -*- coding:utf-8 -*-
import tkinter as tk
import random
#Konstante
BLOCK_SIZE = 25 #Vertikale und horizontale Größe des Blocks px
FIELD_WIDTH = 10 #Feldbreite
FIELD_HEIGHT = 20 #Feldhöhe
MOVE_LEFT = 0 #Konstante Anzeige, um den Block nach links zu verschieben
MOVE_RIGHT = 1 #Konstante Anzeige, um den Block nach rechts zu verschieben
MOVE_DOWN = 2 #Konstante Anzeige, um den Block nach unten zu bewegen
#Quadratische Klasse, aus der der Block besteht
class TetrisSquare():
def __init__(self, x=0, y=0, color="gray"):
'Erstellen Sie ein Quadrat'
self.x = x
self.y = y
self.color = color
def set_cord(self, x, y):
'Stellen Sie die Koordinaten des Quadrats ein'
self.x = x
self.y = y
def get_cord(self):
'Holen Sie sich die Koordinaten des Quadrats'
return int(self.x), int(self.y)
def set_color(self, color):
'Stellen Sie die Farbe des Quadrats ein'
self.color = color
def get_color(self):
'Holen Sie sich die Farbe des Quadrats'
return self.color
def get_moved_cord(self, direction):
'Holen Sie sich die Koordinaten des Quadrats nach dem Verschieben'
#Holen Sie sich die Koordinaten des Quadrats, bevor Sie sich bewegen
x, y = self.get_cord()
#Berechnen Sie die Koordinaten nach dem Bewegen unter Berücksichtigung der Bewegungsrichtung
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
#Canvas-Klasse zum Zeichnen des Tetris-Bildschirms
class TetrisCanvas(tk.Canvas):
def __init__(self, master, field):
'Erstellen Sie eine Leinwand, um Tetris zu zeichnen'
canvas_width = field.get_width() * BLOCK_SIZE
canvas_height = field.get_height() * BLOCK_SIZE
# tk.Canvas-Klasse init
super().__init__(master, width=canvas_width, height=canvas_height, bg="white")
#Platziere die Leinwand auf dem Bildschirm
self.place(x=25, y=25)
#Erstellen Sie einen Tetris-Bildschirm, indem Sie 10 x 20 Quadrate zeichnen
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()
)
#Stellen Sie das zuvor gezeichnete Feld ein
self.before_field = field
def update(self, field, block):
'Aktualisieren Sie den Tetris-Bildschirm'
#Erstellen Sie ein Zeichenfeld (Feld + Block)
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)
#Kombinieren Sie Blockquadratinformationen mit Feld
if block is not None:
block_squares = block.get_squares()
for block_square in block_squares:
#Holen Sie sich die Koordinaten und die Farbe des Blockquadrats
x, y = block_square.get_cord()
color = block_square.get_color()
#Aktualisieren Sie die Farbe des Quadrats im Feld der erfassten Koordinaten
new_field_square = new_field.get_square(x, y)
new_field_square.set_color(color)
#Zeichnen Sie mit Zeichenfeldern auf Leinwand
for y in range(field.get_height()):
for x in range(field.get_width()):
# (x,y)Holen Sie sich die Farbe des Koordinatenfeldes
new_square = new_field.get_square(x, y)
new_color = new_square.get_color()
# (x,y)Zeichnen Sie nicht, wenn sich die Koordinaten seit der letzten Zeichnung nicht geändert haben
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
#Zeichnen Sie ein Rechteck mit der Farbe jeder Position im Feld
self.create_rectangle(
x1, y1, x2, y2,
outline="white", width=1, fill=new_color
)
#Aktualisieren Sie die Informationen des zuletzt gezeichneten Feldes
self.before_field = new_field
#Feldklasse, die die Informationen von gestapelten Blöcken verwaltet
class TetrisField():
def __init__(self):
self.width = FIELD_WIDTH
self.height = FIELD_HEIGHT
#Feld initialisieren
self.squares = []
for y in range(self.height):
for x in range(self.width):
#Felder als Liste quadratischer Instanzen verwalten
self.squares.append(TetrisSquare(x, y, "gray"))
def get_width(self):
'Ermitteln Sie die Anzahl der Quadrate im Feld (horizontal)'
return self.width
def get_height(self):
'Ermitteln Sie die Anzahl der Quadrate im Feld (vertikal).'
return self.height
def get_squares(self):
'Holen Sie sich eine Liste der Quadrate, aus denen das Feld besteht'
return self.squares
def get_square(self, x, y):
'Holen Sie sich das Quadrat an den angegebenen Koordinaten'
return self.squares[y * self.width + x]
def judge_game_over(self, block):
'Stellen Sie fest, ob das Spiel beendet ist'
#Erstellen Sie einen Satz von Koordinaten, die bereits im Feld ausgefüllt sind
no_empty_cord = set(square.get_cord() for square
in self.get_squares() if square.get_color() != "gray")
#Erstellen eines Koordinatensatzes mit Blöcken
block_cord = set(square.get_cord() for square
in block.get_squares())
#Mit einem Satz von Blockkoordinaten
#Erstellen Sie einen Produktsatz von Koordinatensätzen, die bereits im Feld ausgefüllt sind
collision_set = no_empty_cord & block_cord
#Wenn das Produktset leer ist, ist das Spiel noch nicht beendet
if len(collision_set) == 0:
ret = False
else:
ret = True
return ret
def judge_can_move(self, block, direction):
'Stellen Sie fest, ob der Block in die angegebene Richtung bewegt werden kann'
#Erstellen Sie einen Satz von Koordinaten, die bereits im Feld ausgefüllt sind
no_empty_cord = set(square.get_cord() for square
in self.get_squares() if square.get_color() != "gray")
#Erstellen eines Koordinatensatzes mit dem verschobenen Block
move_block_cord = set(square.get_moved_cord(direction) for square
in block.get_squares())
#Stellen Sie fest, ob es außerhalb des Feldes liegt
for x, y in move_block_cord:
#Kann sich nicht bewegen, wenn es herausragt
if x < 0 or x >= self.width or \
y < 0 or y >= self.height:
return False
#Mit dem Koordinatensatz des Blocks nach dem Verschieben
#Erstellen Sie einen Produktsatz von Koordinatensätzen, die bereits im Feld ausgefüllt sind
collision_set = no_empty_cord & move_block_cord
#Beweglich, wenn der Produktsatz leer ist
if len(collision_set) == 0:
ret = True
else:
ret = False
return ret
def fix_block(self, block):
'Block reparieren und zum Feld hinzufügen'
for square in block.get_squares():
#Holen Sie sich die Koordinaten und Farben der im Block enthaltenen Quadrate
x, y = square.get_cord()
color = square.get_color()
#Reflektieren Sie die Koordinaten und Farben im Feld
field_square = self.get_square(x, y)
field_square.set_color(color)
def delete_line(self):
'Zeile löschen'
#Überprüfen Sie, ob alle Zeilen gelöscht werden können
for y in range(self.height):
for x in range(self.width):
#Es kann nicht gelöscht werden, wenn in der Zeile auch nur ein Leerzeichen vorhanden ist
square = self.get_square(x, y)
if(square.get_color() == "gray"):
#Zur nächsten Zeile
break
else:
#Wenn nicht unterbrochen, ist die Leitung voll
#Löschen Sie diese Zeile und verschieben Sie die Zeile über dieser Zeile um eine Zeile nach unten
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())
#Die oberste Zeile ist immer leer
for x in range(self.width):
square = self.get_square(x, 0)
square.set_color("gray")
#Tetris-Blockklasse
class TetrisBlock():
def __init__(self):
'Erstellen Sie einen Block Tetris'
#Liste der Quadrate, aus denen der Block besteht
self.squares = []
#Bestimmen Sie zufällig die Form des Blocks
block_type = random.randint(1, 7)
#Bestimmen Sie die Koordinaten und Farben der vier Quadrate entsprechend der Form des Blocks
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],
]
#Erstellen Sie ein Quadrat mit der festgelegten Farbe und den Koordinaten und fügen Sie es der Liste hinzu
for cord in cords:
self.squares.append(TetrisSquare(cord[0], cord[1], color))
def get_squares(self):
'Holen Sie sich die Quadrate, aus denen der Block besteht'
# return [square for square in self.squares]
return self.squares
def move(self, direction):
'Blöcke verschieben'
#Bewegen Sie die Quadrate, aus denen der Block besteht
for square in self.squares:
x, y = square.get_moved_cord(direction)
square.set_cord(x, y)
#Klasse, die das Tetris-Spiel steuert
class TetrisGame():
def __init__(self, master):
'Tetris-Instanziierung'
#Blockverwaltungsliste initialisieren
self.field = TetrisField()
#Stellen Sie den Fallblock ein
self.block = None
#Stellen Sie den Tetris-Bildschirm ein
self.canvas = TetrisCanvas(master, self.field)
#Tetris Bildschirm Update
self.canvas.update(self.field, self.block)
def start(self, func):
'Starten Sie Tetris'
#Stellen Sie die Funktion so ein, dass sie am Ende aufgerufen wird
self.end_func = func
#Blockverwaltungsliste initialisieren
self.field = TetrisField()
#Neuer Fallblock hinzugefügt
self.new_block()
def new_block(self):
'Neuen Block hinzufügen'
#Erstellen Sie eine fallende Blockinstanz
self.block = TetrisBlock()
if self.field.judge_game_over(self.block):
self.end_func()
print("Game Over!")
#Aktualisieren Sie den Tetris-Bildschirm
self.canvas.update(self.field, self.block)
def move_block(self, direction):
'Blöcke verschieben'
#Bewegen Sie sich nur, wenn Sie sich bewegen können
if self.field.judge_can_move(self.block, direction):
#Blöcke verschieben
self.block.move(direction)
#Bildschirm aktualisieren
self.canvas.update(self.field, self.block)
else:
#Wenn sich der Block nicht nach unten bewegen kann
if direction == MOVE_DOWN:
#Repariere den Block
self.field.fix_block(self.block)
self.field.delete_line()
self.new_block()
#Eine Klasse, die Ereignisse akzeptiert und Tetris entsprechend den Ereignissen steuert
class EventHandller():
def __init__(self, master, game):
self.master = master
#Spiel zu kontrollieren
self.game = game
#Timer, der regelmäßig Ereignisse ausgibt
self.timer = None
#Installieren Sie die Schaltfläche zum Starten des Spiels
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):
'Verarbeitung, wenn die Spielstarttaste gedrückt wird'
#Starten Sie Tetris
self.game.start(self.end_event)
self.running = True
#Timer eingestellt
self.timer_start()
#Akzeptieren Sie die Eingabe der Tastenbedienung
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):
'Verarbeitung am Ende des Spiels'
self.running = False
#Akzeptiere keine Ereignisse mehr
self.timer_end()
self.master.unbind("<Left>")
self.master.unbind("<Right>")
self.master.unbind("<Down>")
def timer_end(self):
'Timer beenden'
if self.timer is not None:
self.master.after_cancel(self.timer)
self.timer = None
def timer_start(self):
'Timer starten'
if self.timer is not None:
#Den Timer einmal abbrechen
self.master.after_cancel(self.timer)
#Der Timer startet nur, wenn Tetris läuft
if self.running:
#Timer starten
self.timer = self.master.after(1000, self.timer_event)
def left_key_event(self, event):
'Verarbeitung beim Akzeptieren der Eingabe der linken Taste'
#Bewegen Sie den Block nach links
self.game.move_block(MOVE_LEFT)
def right_key_event(self, event):
'Verarbeitung bei Annahme der richtigen Tasteneingabe'
#Bewegen Sie den Block nach rechts
self.game.move_block(MOVE_RIGHT)
def down_key_event(self, event):
'Verarbeitung beim Akzeptieren der Eingabe niedrigerer Tasten'
#Bewegen Sie den Block nach unten
self.game.move_block(MOVE_DOWN)
#Starten Sie den Fall-Timer neu
self.timer_start()
def timer_event(self):
'Verarbeitung nach Ablauf des Timers'
#Führt die gleiche Verarbeitung aus wie beim Akzeptieren von Tasteneingaben
self.down_key_event(None)
class Application(tk.Tk):
def __init__(self):
super().__init__()
#App-Fenstereinstellungen
self.geometry("400x600")
self.title("Tetris")
#Tetris-Generation
game = TetrisGame(self)
#Event-Handler-Generierung
EventHandller(self, game)
def main():
'Hauptfunktion'
#Generierung von GUI-Anwendungen
app = Application()
app.mainloop()
if __name__ == "__main__":
main()
Es ist schade, dass wir die Rotation von Tetrimino nicht reproduzieren konnten, was der wahre Nervenkitzel von Tetris ist, aber ich denke, es ist ein Spiel, das jeder genießen kann. Ich habe zum ersten Mal versucht, ein Spiel mit Python zu erstellen, und das Erfolgserlebnis nach Abschluss war wunderbar. Als nächstes werden wir uns rächen, damit wir einen drehbaren Tetris machen können!
https://daeudaeu.com/programming/python/tkinter/tetris/
Recommended Posts