[PYTHON] Mach ein Spiel im Tetris-Stil!

Einführung

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.

Arten von Tetrimino

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.PNG  Tミノ    z.PNG  Zミノ      i.PNG  Iミノ        j.PNG  Lミノ l.PNG  Jミノ     o.PNG  Oミノ      s.PNG  Sミノ

Spielbildschirm

テトリス.PNG  20200707_212249.gif

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. gameover.PNG←ゲームオーバー時の表示

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.

Beispiel des Programms abgeschlossen

# -*- 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()

Schließlich

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!

Referenzseite

https://daeudaeu.com/programming/python/tkinter/tetris/

Recommended Posts

Mach ein Spiel im Tetris-Stil!
Lass uns ein Squashspiel machen
Lassen Sie uns mit Python ein Shiritori-Spiel machen
Ich möchte ein Spiel mit Python machen
Erstellen Sie ein cocos2d-Spiel mit einem Pixel-Doppelwinkelfenster
Erstellen Sie eine Distanzmatrix
Mach ein Janken-Spiel in einer Zeile (Python)
Ich mache ein Passwort!
Machen Sie einen Nyan-Knopf
Ich habe ein ○ ✕ Spiel mit TensorFlow gemacht
Erstellen Sie einen Base64-Decoder
Versuchen Sie, ein einfaches Spiel mit Python 3 und iPhone zu erstellen
Erstellen Sie ein Blueqat-Backend ~ Teil 1
Erstellen Sie ein Blueqat-Backend ~ Teil 2
[Django] Erstellen Sie ein Pulldown-Menü
Machen Sie einen LINE BOT (Chat)
Machen Sie eine Lotterie mit Python
Machen Sie Responder zu einem Daemon (Dienst)
Machen Sie ein Feuer mit kdeplot
Erstellen Sie einen Berechnungsbohrdruck
Wie erstelle ich ein Multiplayer-Online-Actionspiel mit Slack?
Wie man ein einfaches Flappy Bird-Spiel mit Pygame macht
Machen wir eine Remote-Rumba [Hardware]
Wie erstelle ich eine japanisch-englische Übersetzung?
Machen Sie eine Santa-Kennung aus einem Santa-Bild
Machen Sie eine Tweet-Box für Pepper
Lassen Sie uns eine GUI mit Python erstellen.
Machen Sie einen Sound mit Jupyter Notebook
Machen wir einen Spot Sale Service 2
Erstellen Sie mit TensorFlow eine Gesichtserkennung
Machen wir einen Blockbruch mit wxPython
Machen wir einen Spot Sale Service 1
Wie erstelle ich einen Crawler?
So erstellen Sie eine rekursive Funktion
Machen Sie die C-Kompilierung etwas einfacher
Python / Machen Sie ein Diktat aus einer Liste.
[Python] Machen Sie die Funktion zu einer Lambda-Funktion
Erstellen Sie ein Empfehlungssystem mit Python
[Blender] So erstellen Sie ein Blender-Plug-In
Machen Sie einen Filter mit einer Django-Vorlage
Zura machte wie ein Lebensspiel
Lassen Sie uns ein Diagramm mit Python erstellen! !!
Machen wir mit xCAT einen Spacon
Wie erstelle ich einen Crawler?
Erstellen Sie mit PySide einen Modelliterator
Machen Sie eine schöne Grafik mit Plotly
Machen Sie einen Vorhanggenerator mit Blender
Machen wir einen Spot Sale Service 3
Erstellen Sie einen Videoplayer mit PySimpleGUI + OpenCV
[Python] Wie man eine Klasse iterierbar macht
Machen wir einen Jupyter-Kernel
Ich habe versucht, ○ ✕ mit TensorFlow zu spielen
Erstellen Sie ein Beziehungsdiagramm von Python-Modulen
Machen Sie einen seltenen Gacha-Simulator mit Flask