Tetris

Du hast eine Idee für ein Projekt?
Antworten
Szabi
User
Beiträge: 5
Registriert: Donnerstag 21. Oktober 2021, 09:22
Wohnort: Hildisrieden, Schweiz

Hallo zusammen,
Ich brauche eure Hilfe. Ich habe einen Tetris Programm nachgebaut, aber es funktioniert noch nicht ganz so wie es gerne will.
Vielleicht seht ihr, wo der Fehler liegt. Ich komme langsam an meine Grenzen, weil ich erst Python lerne.

Code:

Code: Alles auswählen

import pygame
import random

colors = [
    (0, 0, 0),
    (0, 240, 240),
    (0, 0, 240),
    (240, 160, 0),
    (240, 240, 0),
    (0, 240, 0),
    (160, 0, 240),
    (240, 0, 0)]
    
class Figure:
    x = 0
    y = 0
    
    Figures = [
        [[1, 5, 9, 13], [4, 5, 6, 7]], #Gerade
        [[1, 2, 5, 9], [0, 4, 5, 6], [1, 5, 9, 8], [4, 5, 6, 10]], #Rev L-Block
        [[1, 2, 6, 10], [5, 6, 7, 9], [2, 6, 10, 11], [3, 5, 6, 7]], # L-Block
        [[1, 2, 5, 6]], #Block
        [[6, 7, 9, 10], [1, 5, 6, 10]], # S-Block
        [[1, 4, 5, 6], [1, 4, 5, 9], [4, 5, 6, 9], [1, 5, 6, 9]], #T-Block
        [[4, 5, 9, 10],[2, 6, 5, 9]] #Reverse S-Block
        ]
        
    def __init__(self, x_coord, y_coord):
        self.x = x_coord
        self.y = y_coord
        self.type = random.randint(0, len(self.Figures)-1)
        self.color = colors[self.type + 1]
        self.rotation = 0
            
    def image(self):
        return self.Figures[self.type][self.rotation]  
            
    def rotate(self):
        self.rotation = (self.rotation + 1) % len(self.Figures[self.type])
            
class Tetris:
    height = 0
    width = 0
    field = []
    score = 0
    state = "start"
    Figure = None
        
    def __init__(self, _height, _width):
        self.height = _height
        self.width = _width
        self.field = []
        self.score = 0
        self.state = "start"
        for i in range(_height):
            new_line = []
            for j in range(_width):
                new_line.append(0)
                self.field.append(new_line)
        self.new_figure()
            
    def new_figure(self):
        self.Figure = Figure(3, 0)
        
    def go_down(self):
        self.Figure.y += 1
        if self.intersects():
            self.Figure.y -= 1
            self.freeze()
        
    def side(self, dx):
        old_x = self.Figure.x
        edge = False
        for i in range(4):
            for j in range(4):
                p = i * 4 + j
                if p in self.Figure.image():
                    if j + self.Figure.x + dx > self.width -1 or \
                        j + self.Figure.x + dx < 0:
                        edge = True
        if not edge:
            self.Figure.x += dx
        if self.intersects():
            self.Figure.x = old_x
        
        
    def left(self):
        self.side(-1)
    
    def right(self):
        self.side(1)
    
    def down(self):
        while not self.intersects():
            self.Figure.y += 1
        self.Figure.y -= 1
        self.freeze()
    
    def rotate(self):
        old_rotation = self.Figure.rotation
        self.Figure.rotate()
        if self.intersects():
            self.Figure.rotation = old_rotation
        
    def intersects(self):
        intersection = False
        for i in range(4):
            for j in range(4):
                p = i * 4 + j
                if p in self.Figure.image():
                    if i + self.Figure.y > self.height -1 or i + self.Figure.y < 0 or self.field[i + self.Figure.y][j + self.Figure.x] > 0:
                        intersection = True
        return intersection
        
    def freeze(self):
        for i in range(4):
            for j in range(4):
                p = i * 4 + j
                if p in self.Figure.image():
                    self.field[i + self.Figure.y][j + self.Figure.x] = self.Figure.type + 1
        self.break_lines()
        self.new_figure()
        if self.intersects():
            self.state == "gameover"
            
    def break_lines(self):
        lines = 0
        for i in range(1, self.height):
            zeros = 0
            for j in range(self.width):
                if self.field[i][j] == 0:
                    zeros += 1
            if zeros == 0:
                lines += 1
                for i2 in range(i, 1, -1):
                    for j in range(self.width):
                        self.field[i2][j] = self.field[i2 - 1][j]
            self.score += lines ** 2
        
pygame.init()
screen = pygame.display.set_mode((370,670))
pygame.display.set_caption("Tetris")

done = False
fps = 1
clock = pygame.time.Clock()
counter = 0
zoom = 30

game = Tetris (20, 10)
pressing_down = False
pressing_left = False
pressing_right = False

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRAY = (128, 128, 128)


while not done:
    if game.state == "start":
        game.go_down()
            
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                game.rotate()
            if event.key == pygame.K_DOWN:
                pressing_down = True
            if event.key == pygame.K_LEFT:
                pressing_left = True
            if event.key == pygame.K_RIGHT:
                pressing_right = True
                        
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_DOWN:
                pressing_down = False
            if event.key == pygame.K_LEFT:
                 pressing_left = False
            if event.key == pygame.K_RIGHT:
                pressing_right = False
                            
    if pressing_down:
        game.down()           
    if pressing_left:
        game.left()            
    if pressing_right:
        game.right()

                
    screen.fill(color=WHITE)
    for i in range(game.height):
        for j in range(game.width):
            if game.field[i][j] == 0:
                color = GRAY
                just_border = 1
            else:
                color = colors[game.field[i][j]]
                just_border = 0    
            pygame.draw.rect(screen, color, [30 + j * zoom, 30 + i * zoom, zoom, zoom], just_border)
                        
        if game.Figure is not None:
            for i in range(4):
                for j in range(4):
                    p = i * 4 + j
                    if p in game.Figure.image():
                        pygame.draw.rect(screen, game.Figure.color,
                                         [30 + (j + game.Figure.x) * zoom, 30 + (i + game.Figure.y) * zoom, zoom, zoom])

    gameover_font = pygame.font.SysFont("Calibri", 65, True, False)
    text_gameover = gameover_font.render("Game Over!\n Press ESC", True, (255, 215, 0))

    if game.state == "gameover":
        screen.blit(text_gameover, (30, 250))
                    
    score_font = pygame.font.SysFont('Calibri', 15, True, False)
    text_score = gameover_font.render("Score: " + str(game.score), True, (0, 0, 0))
    screen.blit(text_score, (0,0))

                                
    pygame.display.flip()
    clock.tick(fps)          

pygame.quit()
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du wolltest sagen du hast ein Tetris Programm im Netz gefunden, dass nicht funktioniert, und wie sollen das jetzt für dich reparieren?

https://stackoverflow.com/questions/661 ... iven-below
Szabi
User
Beiträge: 5
Registriert: Donnerstag 21. Oktober 2021, 09:22
Wohnort: Hildisrieden, Schweiz

Ja, teilweise hast du recht. Aber der Programm im Netz funktioniert. Es funktioniert so weit, bis die Blöcke unten ankommen, danach wird alles mit Farbe gefüllt. Ich habe irgendwo einen Fehler gemacht, finde es aber nicht.
Das Video ist von Morpheus Tutorials, er programmiert aber nicht mit Visual Code, sondern mit PyCharm. Vieles konnte ich schon anpassen, aber 1 oder 2 Fehler habe ich noch, die ich nicht finde.
Ich will nicht, dass repariert wird, sondern ich suche nach Tipps, was der Fehler sein könnte.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

Klassenattribute sind kein Ersatz für Instanzattribute, vor allem, wenn die in __init__ ja gleich überschrieben werden.
Konstanten schreibt man KOMPLETT_GROSS. Warum ist `colors` auf oberster Ebene definiert, Figures aber im Klassen-Namensraum?
Statt `random.randint` würde man random.choice nehmen und gleich eine Figure-Liste haben, kombiniert mit der Farbe.

Der _ in den Argumenten von Tetris.__init__ sagt, dass diese Argumente gar nicht verwendet werden, werden sie aber doch. `self.field.append` ist falsch eingerückt. `self.Figure` wird in __init__ nicht initialisiert und ist zudem falsch geschrieben, Attribute werden komplett klein geschrieben.

Es fehlt die main-Funktion, also alles ab `pygame.init` muß in eine Funktion wandern.
An vier Stellen im Code gibt es Schleifen über die Bausteine einer Figur. Hätte man die statt magischer Zahlen gleich bei der Defintion die (i,j)-Schreibweise gewählt, wäre das deutlich lesbarer und kürzer.
Z.b. `intersects`, eine Methode, die besser in der Figure-Klasse aufgehoben wäre:

Code: Alles auswählen

class Figure:
    def intersects(self, field):
        try:
            return any(
                field[i + self.y][j + self.x] > 0
                for i, j in self.image()
            )
        except IndexError:
            return True
Szabi
User
Beiträge: 5
Registriert: Donnerstag 21. Oktober 2021, 09:22
Wohnort: Hildisrieden, Schweiz

Vielen Dank. Somit ist mein Problem gelöst.
Danke!!
Antworten