Tetris game in Python Code

Tetris game in Python Code

In this article, we will build an amazing project Tetris game in Python code. In this project, we will use the pygame library to build the game. To create this project, ensure you have the latest version of Python installed in your system. Let’s get started!

Output for Tetris game in Python Code

Pygame

Pygame is a cross-platform set of Python modules that are used to create video games. It consists of computer graphics and sound libraries designed to be used with the Python programming language. Pygame is suitable to create client-side applications that can be potentially wrapped in a standalone executable. To learn pygame, it is required to have basic knowledge of Python.

To install pygame execute the following piece of code in the terminal

pip install pygame

That’s it, we are done with the prerequisites for the project. Let’s look into some of the important functions in this project.

This update_graphics method is used to design the game interface and make necessary updates during the execution of the game. The function sets the background color, and text to display, and sets borders and width. It displays the current score and time. It draws a small screen to show the next block. Set tiles for blocks 20 tile/square per row which is 19 horizontal lines and 10 tile/square per col which is 9 vertical lines.

The draw_small_screen method is used to design the same screen interface which displays the next block during the execution of the game. It sets the background, borders, and text and displays the next block.

The manage_events function is used to handle the blocks during the execution of the game.

Complete code for the Tetris game in Python

We can build Tetris games in Python with the help of Pygame since it has a lot of functions for this purpose. So now, let’s start with the implementation part. You can understand the code line-by-line with the help of comments.

You can download the images required for the project here.

Now create two python files and save them as util.py and tetris.py

util.py

#Import libraries
import pygame
import sys
import random
import time

# Define important global variables
pygame.init()
clock = pygame.time.Clock()

best_score = 0
longest_time = 0

width = 700
height = 750
DISPLAY_SCREEN = pygame.display.set_mode((width, height))
pygame.display.set_caption(" Tetris")

off_set_x = 10
off_set_y = 80
playing_field_width = 330  #330 / 10 = 33 width per tile
playing_field_height = 660  #600 / 20 = 33 height per tile
tile_length = 33 # tile is a square

#colors
blue = (0, 0, 255)
white = (255, 255, 255) 
black = (0, 0, 0)
gray = (95, 95, 96) 
orange  = (249, 87, 0)  
cobalt_blue = (3, 65, 174)
green_apple  = (114, 203, 59)
cyber_yellow= (255, 213, 0)
beer = (255, 151, 28)
ryb_red = (255, 50, 19)
purple = (128, 0, 128)

# colors of Tetris blocks
block_colors = (cobalt_blue, blue, green_apple, purple, cyber_yellow, beer, ryb_red)
# shapes of Tetris blocks
shapes = ("i_block", "l_block", "j_block", "o_block", "s_block", "t_block", "z_block")
directions = ("vertical_1", "vertical_2", "horizontal_1", "horizontal_2")

background_img = pygame.image.load("resources/images/background_img.jpg")      
instructions_img = pygame.image.load("resources/images/instructions_img.jpg")  
icon_img = pygame.image.load("resources/images/icon.png")
pygame.display.set_icon(icon_img)

class Button:
    def __init__(self, button_color, button_hover_over_color, x, y, width, height, text_size,  text_color, text_hover_over_color = None, text_str=""):
        self.button_color = button_color
        self.button_hover_over_color = button_hover_over_color
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.text_size = text_size
        self.text_color = text_color

        if text_hover_over_color:
            self.text_hover_over_color = text_hover_over_color
        else:
            self.text_hover_over_color =  text_color
 
        self.text_str = text_str


    def blit(self, display_screen, outline_color=None):
        if outline_color: 
            pygame.draw.rect(display_screen, outline_color, (self.x-3, self.y-3, self.width+6, self.height+6))
        
        pygame.draw.rect(display_screen, self.button_color, (self.x, self.y, self.width, self.height))

        if self.text_str != "": 
            font = pygame.font.Font("freesansbold.ttf", self.text_size)
            text = font.render(self.text_str, True, self.text_color)
            # to center the text in the middle of the button based on the size of the button
            text_position = (self.x + (self.width/2 - text.get_width()/2), self.y + (self.height/2 - text.get_height()/2))
            display_screen.blit(text, text_position)


    def is_hovered_over(self, mouse_position):
        if self.x < mouse_position[0] < self.x+self.width and self.y < mouse_position[1] < self.y+self.height:
            return True
        return False


    def blit_hovered_over(self, display_screen):
        pygame.draw.rect(display_screen, self.button_hover_over_color, (self.x, self.y, self.width, self.height))

        if self.text_str != "":
            font = pygame.font.Font("freesansbold.ttf", self.text_size)
            text = font.render(self.text_str, True, self.text_hover_over_color)
            # to center the text in the middle of the button based on the size of the button
            text_position = (self.x + (self.width/2 - text.get_width()/2), self.y + (self.height/2 - text.get_height()/2))
            display_screen.blit(text, text_position)


    def is_clicked(self, mouse_position, event):
        if self.is_hovered_over(mouse_position):
            if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                return True
        return False

class Tile:
    def __init__(self, x, y, color = black):
        self.x = x
        self.y = y
        self.color = color
        self.empty = True


    def draw_tile(self):
        pygame.draw.rect(DISPLAY_SCREEN , self.color, (self.x, self.y, tile_length, tile_length) )


class PlayingField():
    def __init__(self):
        #y coordinate of first row = (80) off_set_y 
        self.tiles = {
            "row1":  {80:  []},
            "row2":  {113: []},
            "row3":  {146: []},
            "row4":  {179: []},
            "row5":  {212: []},
            "row6":  {245: []},
            "row7":  {278: []},
            "row8":  {311: []},
            "row9":  {344: []},
            "row10": {377: []},
            "row11": {410: []},
            "row12": {443: []},
            "row13": {476: []},
            "row14": {509: []},
            "row15": {542: []},
            "row16": {575: []},
            "row17": {608: []},
            "row18": {641: []},
            "row19": {674: []},
            "row20": {707: []},
        }
        self.__init_field()


    def __init_field(self):    
        y = off_set_y
        for i in range(20): #rows
            x = off_set_x
            for j in range(10): #cols
                tile_to_add = Tile(x, y) 
                self.tiles["row"+str(i+1)][y].append(tile_to_add)
                x += tile_length
            y += tile_length
    

    def destory_full_row(self, player):
        times = 0
        y = off_set_y        
        for i in range(20):
            for tile in self.tiles["row"+str(i+1)][y]:
                if tile.empty: break

                elif tile.x == off_set_x+playing_field_width-tile_length:
                    times += 1
                    for j in range(800): #just for flashing the row
                        if j%2 == 0:
                            pygame.draw.rect(DISPLAY_SCREEN , black, (self.tiles["row"+str(i+1)][y][0].x+1, self.tiles["row"+str(i+1)][y][0].y+1, playing_field_width-2, tile_length-2) )
                        else:
                            for tile in self.tiles["row"+str(i+1)][y]:
                                pygame.draw.rect(DISPLAY_SCREEN , tile.color, (tile.x, tile.y, tile_length, tile_length) )
                        pygame.draw.line(DISPLAY_SCREEN , white, (off_set_x, y), (playing_field_width+off_set_x-1, y)) # horizontal line
                        pygame.display.update()

                    # let's destory this full row
                    self.destroy_and_replace(i+1, y)
                    player.score += 10*times

            y += tile_length 


    def destroy_and_replace(self, row_number, row_y):
        for i in range (row_number, 1, -1):
            prev_row_number = i-1
            prev_y = row_y-tile_length
            
            self.tiles["row"+str(i)][row_y].clear() #current_row.clear()
            temp_x = off_set_x
            for j in range(10):
                empty_tile = Tile(temp_x, row_y)
                temp_x += tile_length
                self.tiles["row"+str(i)][row_y].append(empty_tile)
            if prev_y < 80: 
                break

            
            for j in range(10):
                old_tile = self.tiles["row"+str(i)][row_y][j]
                new_tile = self.tiles["row"+str(prev_row_number)][prev_y][j] 
                old_tile.x = new_tile.x
                old_tile.color = new_tile.color 
                old_tile.empty = new_tile.empty

            row_y -= tile_length


class Block:
    def __init__(self, shape:str, color = black):
        self.shape = shape
        self.color = color

        self.direction = directions[0] #vertical_1

        #                         tile1                                                        , tile2            , tile3            , tile4
        self.tiles = [ Tile(off_set_x+playing_field_width/2-tile_length, off_set_y, self.color), Tile(0, 0, color), Tile(0, 0, color), Tile(0, 0, color)]
        
        self.__init_shape() 
        for tile in self.tiles:
            tile.empty = False


    def __init_shape(self):
        if self.shape == "i_block":
            self.tiles[1] = Tile(self.tiles[0].x, self.tiles[0].y-tile_length, self.color)
            self.tiles[2] = Tile(self.tiles[0].x, self.tiles[1].y-tile_length, self.color)
            self.tiles[3] = Tile(self.tiles[0].x, self.tiles[2].y-tile_length, self.color)
        elif self.shape == "l_block":
            self.tiles[1] = Tile(self.tiles[0].x+tile_length, self.tiles[0].y, self.color)
            self.tiles[2] = Tile(self.tiles[0].x-tile_length, self.tiles[0].y, self.color)
            self.tiles[3] = Tile(self.tiles[2].x, self.tiles[2].y-tile_length, self.color)
        elif self.shape == "j_block":
            self.tiles[1] = Tile(self.tiles[0].x+tile_length, self.tiles[0].y, self.color)
            self.tiles[2] = Tile(self.tiles[0].x-tile_length, self.tiles[0].y, self.color)
            self.tiles[3] = Tile(self.tiles[1].x, self.tiles[1].y-tile_length, self.color)
        elif self.shape == "o_block":
            self.tiles[1] = Tile(self.tiles[0].x+tile_length,  self.tiles[0].y, self.color)
            self.tiles[2] = Tile(self.tiles[0].x, self.tiles[0].y-tile_length, self.color)
            self.tiles[3] = Tile(self.tiles[1].x, self.tiles[1].y-tile_length, self.color)
        elif self.shape == "s_block":
            self.tiles[1] = Tile(self.tiles[0].x-tile_length, self.tiles[0].y, self.color)
            self.tiles[2] = Tile(self.tiles[0].x, self.tiles[0].y-tile_length, self.color)
            self.tiles[3] = Tile(self.tiles[2].x+tile_length, self.tiles[2].y, self.color)
        elif self.shape == "t_block":
            self.tiles[1] = Tile(self.tiles[0].x+tile_length,  self.tiles[0].y, self.color)
            self.tiles[2] = Tile(self.tiles[0].x-tile_length, self.tiles[0].y, self.color)
            self.tiles[3] = Tile(self.tiles[0].x, self.tiles[0].y-tile_length, self.color)
        elif self.shape == "z_block":
            self.tiles[1] = Tile(self.tiles[0].x+tile_length,  self.tiles[0].y, self.color)
            self.tiles[2] = Tile(self.tiles[0].x, self.tiles[0].y-tile_length, self.color)
            self.tiles[3] = Tile(self.tiles[2].x-tile_length, self.tiles[2].y, self.color)
        else:
            print("Error: wrong block name.")
            pygame.quit()
            sys.exit()

    
    def complete_block(self):
        self.__init_shape()


    def can_fall(self, next_block, playing_field, player):
        from tetris import manage_events, update_graphics
        manage_events(self, next_block, playing_field, player)
        #check borders
        for block_tile in self.tiles:
            if block_tile.y >= playing_field_height+off_set_y-tile_length:
                return False  

        #check already existed tiles
        for block_tile in self.tiles:
            y = off_set_y
            for i in range(20):
                for tile in playing_field.tiles["row"+str(i+1)][y]:
                    if not tile.empty and block_tile.y+tile_length == tile.y and block_tile.x == tile.x: 
                        return False  
                y += tile_length
    
        return True


    def block_is_falling(self, next_block, playing_field, player, faster=None):
        from tetris import manage_events, update_graphics
        manage_events(self,next_block, playing_field, player)

        if self.can_fall(next_block, playing_field, player):
            for tile in self.tiles:
                tile.y += tile_length

            manage_events(self, next_block, playing_field, player)             
            update_graphics(self, next_block, playing_field, player)
            if faster:                
                clock.tick(40)
                self.block_is_falling( next_block, playing_field, player)
            else:                
                clock.tick(5)
            manage_events(self, next_block, playing_field, player)             
            update_graphics(self, next_block, playing_field, player)


    def get_new_block(self, next_block, playing_field, player):
        if self.can_fall(next_block, playing_field, player): return (self, next_block, False)
        
        #if the block has falled completely
        for block_tile in self.tiles: 
            found = False 
            y = off_set_y
            for i in range(20):
                if not found:
                    for j in range(10):
                        if block_tile.x == playing_field.tiles["row"+str(i+1)][y][j].x and block_tile.y == playing_field.tiles["row"+str(i+1)][y][j].y:
                            playing_field.tiles["row"+str(i+1)][y][j].color = block_tile.color
                            playing_field.tiles["row"+str(i+1)][y][j].empty = False
                            found = True
                            break
                    y += tile_length
                else:
                    break
        
        new_block = next_block

        next_rand_index1 = random.randint(0, 6)
        next_rand_index2 = random.randint(0, 6)
        new_next_block = Block(shapes[next_rand_index1], block_colors[next_rand_index2])

        clock.tick(2)
        return (new_block, new_next_block, True)


    def move_left(self, playing_field):
        if self.can_move_left(playing_field):
            for tile in self.tiles:
                tile.x -= tile_length


    def move_right(self, playing_field):
        if self.can_move_right(playing_field):
            for tile in self.tiles:
                tile.x += tile_length


    def can_move_left(self, playing_field):
        # whether inside the playing field or not
        for tile in self.tiles:
            if tile.x <= off_set_x:
                return False
        # whether adjacent field_tiles are occupied or not
        for block_tile in self.tiles:
            y = off_set_y
            for i in range(20):
                for tile in playing_field.tiles["row"+str(i+1)][y]:
                    if not tile.empty and block_tile.x-tile_length == tile.x and block_tile.y  == tile.y:
                        return False  
                y += tile_length
        return True
        

    def can_move_right(self, playing_field):
        # whether inside the playing field or not
        for tile in self.tiles:
            if tile.x + tile_length >= off_set_x+playing_field_width:
                return False
        # whether adjacent field_tiles are occupied or not
        for block_tile in self.tiles:
            y = off_set_y
            for i in range(20):
                for tile in playing_field.tiles["row"+str(i+1)][y]:
                    if not tile.empty and block_tile.x+tile_length == tile.x and block_tile.y  == tile.y:
                        return False  
                y += tile_length
        return True


    def rotate(self, next_block, playing_field, player):
        from tetris import manage_events, update_graphics
        manage_events(self, next_block, playing_field, player)

        if self.shape == "i_block":
            self.rotate_i_block(playing_field)
        elif self.shape == "l_block":
            self.rotate_l_block(playing_field)
        elif self.shape == "j_block":
            self.rotate_j_block(playing_field)
        elif self.shape == "o_block":
            return
            #no rotation for o_block.
        elif self.shape == "s_block":
            self.rotate_s_block(playing_field)
        elif self.shape == "t_block":
            self.rotate_t_block(playing_field)
        elif self.shape == "z_block":
            self.rotate_z_block(playing_field)
        else:
            print("Error: wrong block name.")
            pygame.quit()
            sys.exit()
        manage_events(self, next_block, playing_field, player)
        update_graphics(self, next_block, playing_field, player)


    def rotate_i_block(self, playing_field): #done
        temp_rotated_i = Block("i_block", self.color)
        temp_rotated_i.tiles = self.tiles.copy()
        
        if self.direction == directions[0] or self.direction == directions[1]:
            # ----
            temp_rotated_i.tiles[0] = Tile(temp_rotated_i.tiles[1].x, temp_rotated_i.tiles[0].y, temp_rotated_i.color) 
            temp_rotated_i.tiles[1] = Tile(temp_rotated_i.tiles[0].x-tile_length, temp_rotated_i.tiles[0].y, temp_rotated_i.color)
            temp_rotated_i.tiles[2] = Tile(temp_rotated_i.tiles[0].x+tile_length, temp_rotated_i.tiles[0].y, temp_rotated_i.color)
            temp_rotated_i.tiles[3] = Tile(temp_rotated_i.tiles[2].x+tile_length, temp_rotated_i.tiles[0].y, temp_rotated_i.color)
            temp_rotated_i.direction = directions[2] # "horizontal_1"
        elif self.direction == directions[2] or self.direction == directions[3]:
            # |
            # |
            # |
            # |
            temp_rotated_i.tiles[1] = Tile(temp_rotated_i.tiles[0].x, temp_rotated_i.tiles[0].y-tile_length, temp_rotated_i.color)
            temp_rotated_i.tiles[2] = Tile(temp_rotated_i.tiles[1].x, temp_rotated_i.tiles[1].y-tile_length, temp_rotated_i.color)
            temp_rotated_i.tiles[3] = Tile(temp_rotated_i.tiles[2].x, temp_rotated_i.tiles[2].y-tile_length, temp_rotated_i.color)
            temp_rotated_i.direction = directions[0] #"vertical_1"

        for block_tile in temp_rotated_i.tiles:
            if block_tile.x <= off_set_x or block_tile.x >= playing_field_width:
                return 
            y = off_set_y
            for i in range(20):
                for tile in playing_field.tiles["row"+str(i+1)][y]:
                    if not tile.empty and block_tile.x == tile.x and block_tile.y  == tile.y:
                        return
                y += tile_length

        self.direction = temp_rotated_i.direction
        self.tiles = temp_rotated_i.tiles


    def rotate_l_block(self, playing_field): #done
        temp_rotated_l = Block("l_block", self.color)
        temp_rotated_l.tiles = self.tiles.copy()
        
        if self.direction == directions[0]:
            # after rotating, the block should look like this ↓
            #  _
            # |
            # |
            # |
            temp_rotated_l.tiles[0] = Tile(temp_rotated_l.tiles[0].x, temp_rotated_l.tiles[0].y, temp_rotated_l.color)
            temp_rotated_l.tiles[1] = Tile(temp_rotated_l.tiles[0].x, temp_rotated_l.tiles[0].y-tile_length, temp_rotated_l.color)
            temp_rotated_l.tiles[2] = Tile(temp_rotated_l.tiles[1].x, temp_rotated_l.tiles[1].y-tile_length, temp_rotated_l.color)
            temp_rotated_l.tiles[3] = Tile(temp_rotated_l.tiles[2].x+tile_length, temp_rotated_l.tiles[2].y, temp_rotated_l.color)
            temp_rotated_l.direction = directions[2] # "horizontal_1"
        elif self.direction == directions[2]:
            # after rotating, the block should look like this ↓
            # ---
            #   |
            temp_rotated_l.tiles[0] = Tile(temp_rotated_l.tiles[3].x, temp_rotated_l.tiles[0].y, temp_rotated_l.color)
            temp_rotated_l.tiles[1] = Tile(temp_rotated_l.tiles[0].x, temp_rotated_l.tiles[0].y-tile_length, temp_rotated_l.color)
            temp_rotated_l.tiles[2] = Tile(temp_rotated_l.tiles[1].x-tile_length, temp_rotated_l.tiles[1].y, temp_rotated_l.color)
            temp_rotated_l.tiles[3] = Tile(temp_rotated_l.tiles[2].x-tile_length, temp_rotated_l.tiles[2].y, temp_rotated_l.color)
            temp_rotated_l.direction = directions[1] #"vertical_2"
        elif self.direction == directions[1]: 
            # after rotating, the block should look like this ↓
            #  |
            #  |
            # _|
            temp_rotated_l.tiles[0] = Tile(temp_rotated_l.tiles[3].x, temp_rotated_l.tiles[0].y, temp_rotated_l.color)
            temp_rotated_l.tiles[1] = Tile(temp_rotated_l.tiles[0].x+tile_length, temp_rotated_l.tiles[0].y, temp_rotated_l.color)
            temp_rotated_l.tiles[2] = Tile(temp_rotated_l.tiles[1].x, temp_rotated_l.tiles[1].y-tile_length, temp_rotated_l.color)
            temp_rotated_l.tiles[3] = Tile(temp_rotated_l.tiles[2].x, temp_rotated_l.tiles[2].y-tile_length, temp_rotated_l.color)
            temp_rotated_l.direction = directions[3] #"horizontal_2"
        elif self.direction == directions[3]: 
            # after rotating, the block should look like this ↓
            # |
            # ---
            temp_rotated_l.tiles[0] = Tile(temp_rotated_l.tiles[1].x, temp_rotated_l.tiles[0].y, temp_rotated_l.color)
            temp_rotated_l.tiles[1] = Tile(temp_rotated_l.tiles[0].x+tile_length, temp_rotated_l.tiles[0].y, temp_rotated_l.color)
            temp_rotated_l.tiles[2] = Tile(temp_rotated_l.tiles[0].x-tile_length, temp_rotated_l.tiles[1].y, temp_rotated_l.color)
            temp_rotated_l.tiles[3] = Tile(temp_rotated_l.tiles[2].x, temp_rotated_l.tiles[2].y-tile_length, temp_rotated_l.color) 
            temp_rotated_l.direction = directions[0] #"vertical_1"

        for block_tile in temp_rotated_l.tiles:
            if block_tile.x <= off_set_x or block_tile.x >= playing_field_width:
                return 
            y = off_set_y
            for i in range(20):
                for tile in playing_field.tiles["row"+str(i+1)][y]:
                    if not tile.empty and block_tile.x == tile.x and block_tile.y  == tile.y:
                        return
                y += tile_length

        self.direction = temp_rotated_l.direction
        self.tiles = temp_rotated_l.tiles
        

    def rotate_j_block(self, playing_field): #done
        temp_rotated_j = Block("j_block", self.color)
        temp_rotated_j.tiles = self.tiles.copy()
        
        if self.direction == directions[0]: 
            temp_rotated_j.tiles[0] = Tile(temp_rotated_j.tiles[1].x, temp_rotated_j.tiles[0].y, temp_rotated_j.color)
            temp_rotated_j.tiles[1] = Tile(temp_rotated_j.tiles[0].x-tile_length, temp_rotated_j.tiles[0].y, temp_rotated_j.color)
            temp_rotated_j.tiles[2] = Tile(temp_rotated_j.tiles[1].x, temp_rotated_j.tiles[1].y-tile_length, temp_rotated_j.color)
            temp_rotated_j.tiles[3] = Tile(temp_rotated_j.tiles[2].x, temp_rotated_j.tiles[2].y-tile_length, temp_rotated_j.color)
            temp_rotated_j.direction = directions[2] # "horizontal_1"
        elif self.direction == directions[2]:
            temp_rotated_j.tiles[0] = Tile(temp_rotated_j.tiles[1].x-tile_length, temp_rotated_j.tiles[0].y, temp_rotated_j.color)
            temp_rotated_j.tiles[1] = Tile(temp_rotated_j.tiles[0].x, temp_rotated_j.tiles[0].y-tile_length, temp_rotated_j.color)
            temp_rotated_j.tiles[2] = Tile(temp_rotated_j.tiles[1].x+tile_length, temp_rotated_j.tiles[1].y, temp_rotated_j.color)
            temp_rotated_j.tiles[3] = Tile(temp_rotated_j.tiles[2].x+tile_length, temp_rotated_j.tiles[2].y, temp_rotated_j.color)
            temp_rotated_j.direction = directions[1] #"vertical_2"
        elif self.direction == directions[1]: 
            temp_rotated_j.tiles[0] = Tile(temp_rotated_j.tiles[2].x, temp_rotated_j.tiles[0].y, temp_rotated_j.color)
            temp_rotated_j.tiles[1] = Tile(temp_rotated_j.tiles[0].x, temp_rotated_j.tiles[0].y-tile_length, temp_rotated_j.color)
            temp_rotated_j.tiles[2] = Tile(temp_rotated_j.tiles[1].x, temp_rotated_j.tiles[1].y-tile_length, temp_rotated_j.color)
            temp_rotated_j.tiles[3] = Tile(temp_rotated_j.tiles[2].x-tile_length, temp_rotated_j.tiles[2].y, temp_rotated_j.color)
            temp_rotated_j.direction = directions[3] #"horizontal_2"
        elif self.direction == directions[3]: #back to normal:
            temp_rotated_j.tiles[0] = Tile(temp_rotated_j.tiles[0].x, temp_rotated_j.tiles[0].y, temp_rotated_j.color)
            temp_rotated_j.tiles[1] = Tile(temp_rotated_j.tiles[0].x+tile_length, temp_rotated_j.tiles[0].y, temp_rotated_j.color)
            temp_rotated_j.tiles[2] = Tile(temp_rotated_j.tiles[0].x-tile_length, temp_rotated_j.tiles[0].y, temp_rotated_j.color)
            temp_rotated_j.tiles[3] = Tile(temp_rotated_j.tiles[1].x, temp_rotated_j.tiles[1].y-tile_length, temp_rotated_j.color) 
            temp_rotated_j.direction = directions[0] #"vertical_1"

        for block_tile in temp_rotated_j.tiles:
            if block_tile.x <= off_set_x or block_tile.x >= playing_field_width:
                return 
            y = off_set_y
            for i in range(20):
                for tile in playing_field.tiles["row"+str(i+1)][y]:
                    if not tile.empty and block_tile.x == tile.x and block_tile.y  == tile.y:
                        return 
                y += tile_length

        self.direction = temp_rotated_j.direction
        self.tiles = temp_rotated_j.tiles


    def rotate_s_block(self, playing_field): #done
        temp_rotated_s = Block("s_block", self.color)
        temp_rotated_s.tiles = self.tiles.copy()
        
        if self.direction == directions[0] or self.direction == directions[1]:
            temp_rotated_s.tiles[0] = Tile(temp_rotated_s.tiles[3].x, temp_rotated_s.tiles[0].y, temp_rotated_s.color)
            temp_rotated_s.tiles[1] = Tile(temp_rotated_s.tiles[0].x, temp_rotated_s.tiles[0].y-tile_length, temp_rotated_s.color)
            temp_rotated_s.tiles[2] = Tile(temp_rotated_s.tiles[1].x-tile_length, temp_rotated_s.tiles[1].y, temp_rotated_s.color)
            temp_rotated_s.tiles[3] = Tile(temp_rotated_s.tiles[2].x, temp_rotated_s.tiles[2].y-tile_length, temp_rotated_s.color)
            temp_rotated_s.direction = directions[2] # "horizontal_1"
        elif self.direction == directions[2] or self.direction == directions[3]
            temp_rotated_s.tiles[0] = Tile(temp_rotated_s.tiles[2].x, temp_rotated_s.tiles[0].y, temp_rotated_s.color)
            temp_rotated_s.tiles[1] = Tile(temp_rotated_s.tiles[0].x-tile_length, temp_rotated_s.tiles[0].y, temp_rotated_s.color)
            temp_rotated_s.tiles[2] = Tile(temp_rotated_s.tiles[0].x, temp_rotated_s.tiles[0].y-tile_length, temp_rotated_s.color)
            temp_rotated_s.tiles[3] = Tile(temp_rotated_s.tiles[2].x+tile_length, temp_rotated_s.tiles[2].y, temp_rotated_s.color)
            temp_rotated_s.direction = directions[0] #"vertical_1"

        for block_tile in temp_rotated_s.tiles:
            if block_tile.x <= off_set_x or block_tile.x >= playing_field_width:
                return 
            y = off_set_y
            for i in range(20):
                for tile in playing_field.tiles["row"+str(i+1)][y]:
                    if not tile.empty and block_tile.x == tile.x and block_tile.y  == tile.y:
                        return
                y += tile_length

        self.direction = temp_rotated_s.direction
        self.tiles = temp_rotated_s.tiles   


    def rotate_t_block(self, playing_field): #done
        temp_rotated_t = Block("j_block", self.color)
        temp_rotated_t.tiles = self.tiles.copy()
        
        if self.direction == directions[0]: 
            temp_rotated_t.tiles[0] = Tile(temp_rotated_t.tiles[0].x, temp_rotated_t.tiles[0].y, temp_rotated_t.color)
            temp_rotated_t.tiles[1] = Tile(temp_rotated_t.tiles[0].x, temp_rotated_t.tiles[0].y-tile_length, temp_rotated_t.color)
            temp_rotated_t.tiles[2] = Tile(temp_rotated_t.tiles[1].x, temp_rotated_t.tiles[1].y-tile_length, temp_rotated_t.color)
            temp_rotated_t.tiles[3] = Tile(temp_rotated_t.tiles[1].x+tile_length, temp_rotated_t.tiles[1].y, temp_rotated_t.color)
            temp_rotated_t.direction = directions[2] # "horizontal_1"
        elif self.direction == directions[2]:
            temp_rotated_t.tiles[0] = Tile(temp_rotated_t.tiles[0].x, temp_rotated_t.tiles[0].y, temp_rotated_t.color)
            temp_rotated_t.tiles[1] = Tile(temp_rotated_t.tiles[0].x, temp_rotated_t.tiles[0].y-tile_length, temp_rotated_t.color)
            temp_rotated_t.tiles[2] = Tile(temp_rotated_t.tiles[1].x-tile_length, temp_rotated_t.tiles[1].y, temp_rotated_t.color)
            temp_rotated_t.tiles[3] = Tile(temp_rotated_t.tiles[1].x+tile_length, temp_rotated_t.tiles[2].y, temp_rotated_t.color)
            temp_rotated_t.direction = directions[1] #"vertical_2"
        elif self.direction == directions[1]:
            temp_rotated_t.tiles[0] = Tile(temp_rotated_t.tiles[0].x, temp_rotated_t.tiles[0].y, temp_rotated_t.color)
            temp_rotated_t.tiles[1] = Tile(temp_rotated_t.tiles[0].x, temp_rotated_t.tiles[0].y-tile_length, temp_rotated_t.color)
            temp_rotated_t.tiles[2] = Tile(temp_rotated_t.tiles[1].x, temp_rotated_t.tiles[1].y-tile_length, temp_rotated_t.color)
            temp_rotated_t.tiles[3] = Tile(temp_rotated_t.tiles[1].x-tile_length, temp_rotated_t.tiles[1].y, temp_rotated_t.color)
            temp_rotated_t.direction = directions[3] #"horizontal_2"
        elif self.direction == directions[3]: #back to normal:
            temp_rotated_t.tiles[0] = Tile(temp_rotated_t.tiles[0].x, temp_rotated_t.tiles[0].y, temp_rotated_t.color)
            temp_rotated_t.tiles[1] = Tile(temp_rotated_t.tiles[0].x+tile_length, temp_rotated_t.tiles[0].y, temp_rotated_t.color)
            temp_rotated_t.tiles[2] = Tile(temp_rotated_t.tiles[0].x-tile_length, temp_rotated_t.tiles[0].y, temp_rotated_t.color)
            temp_rotated_t.tiles[3] = Tile(temp_rotated_t.tiles[0].x, temp_rotated_t.tiles[0].y-tile_length, temp_rotated_t.color) 
            temp_rotated_t.direction = directions[0] #"vertical_1"

        for block_tile in temp_rotated_t.tiles:
            if block_tile.x <= off_set_x or block_tile.x >= playing_field_width:
                return 
            y = off_set_y
            for i in range(20):
                for tile in playing_field.tiles["row"+str(i+1)][y]:
                    if not tile.empty and block_tile.x == tile.x and block_tile.y  == tile.y:
                        return
                y += tile_length

        self.direction = temp_rotated_t.direction
        self.tiles = temp_rotated_t.tiles


    def rotate_z_block(self, playing_field): #done
        temp_rotated_z = Block("z_block", self.color)
        temp_rotated_z.tiles = self.tiles.copy()
        
        if self.direction == directions[0] or self.direction == directions[1]:

            temp_rotated_z.tiles[0] = Tile(temp_rotated_z.tiles[3].x, temp_rotated_z.tiles[0].y, temp_rotated_z.color)
            temp_rotated_z.tiles[1] = Tile(temp_rotated_z.tiles[0].x, temp_rotated_z.tiles[0].y-tile_length, temp_rotated_z.color)
            temp_rotated_z.tiles[2] = Tile(temp_rotated_z.tiles[1].x+tile_length, temp_rotated_z.tiles[1].y, temp_rotated_z.color)
            temp_rotated_z.tiles[3] = Tile(temp_rotated_z.tiles[2].x, temp_rotated_z.tiles[2].y-tile_length, temp_rotated_z.color)
            temp_rotated_z.direction = directions[2] # "horizontal_1"
        elif self.direction == directions[2] or self.direction == directions[3]:
            temp_rotated_z.tiles[0] = Tile(temp_rotated_z.tiles[3].x, temp_rotated_z.tiles[0].y, temp_rotated_z.color)
            temp_rotated_z.tiles[1] = Tile(temp_rotated_z.tiles[0].x+tile_length, temp_rotated_z.tiles[0].y, temp_rotated_z.color)
            temp_rotated_z.tiles[2] = Tile(temp_rotated_z.tiles[0].x, temp_rotated_z.tiles[0].y-tile_length, temp_rotated_z.color)
            temp_rotated_z.tiles[3] = Tile(temp_rotated_z.tiles[2].x-tile_length, temp_rotated_z.tiles[2].y, temp_rotated_z.color)
            temp_rotated_z.direction = directions[0] #"vertical_1"

        for block_tile in temp_rotated_z.tiles:
            if block_tile.x <= off_set_x or block_tile.x >= playing_field_width:
                return 
            y = off_set_y
            for i in range(20):
                for tile in playing_field.tiles["row"+str(i+1)][y]:
                    if not tile.empty and block_tile.x == tile.x and block_tile.y  == tile.y:
                        return
                y += tile_length

        self.direction = temp_rotated_z.direction
        self.tiles = temp_rotated_z.tiles      

    def fall_completely(self, next_block, playing_field, player):
        from tetris import update_graphics

        fall= True
        while fall:
            for block_tile in self.tiles:
                if block_tile.y >= playing_field_height+off_set_y-tile_length:
                    fall = False  
                    break 

            #check already existed tiles
            for block_tile in self.tiles:
                y = off_set_y
                for i in range(20):
                    for tile in playing_field.tiles["row"+str(i+1)][y]:
                        if not tile.empty and block_tile.y+tile_length == tile.y and block_tile.x == tile.x: 
                            fall = False   
                            break
                    y += tile_length
            
            if not fall:
                break
            
            for tile in self.tiles:
                tile.y += tile_length
            
            update_graphics(self, next_block, playing_field, player)
            clock.get_rawtime()
            clock.tick(50)
            

class Player:
    def __init__(self, start_time):
        self.start_time = start_time

        self.time_since_start = 0
        self.score = 0 

tetris.py

#import libraries
import pygame
from util import *

def update_graphics(block, next_block, playing_field, player):
    
    #Sets black background and text
    DISPLAY_SCREEN.blit(background_img, (0, 0))
    pygame.draw.rect(DISPLAY_SCREEN , black, (off_set_x, off_set_y, playing_field_width, playing_field_height) )
    font = pygame.font.SysFont("comicsansms", 48)
    rendered_text = font.render("Tetris", 1, orange)
    DISPLAY_SCREEN.blit(rendered_text, (width/2-80, 10))

    #Displays Current score and time
    player.time_since_start = pygame.time.get_ticks() - player.start_time
    font = pygame.font.SysFont("comicsansms", 20)
    rendered_text_time =  font.render("Time: " + str(player.time_since_start), 1, orange)
    DISPLAY_SCREEN.blit(rendered_text_time, (playing_field_width+tile_length*2, playing_field_height-80))  
    rendered_text_score = font.render("Score: " + str(player.score), 1, orange)
    DISPLAY_SCREEN.blit(rendered_text_score, (playing_field_width+tile_length*2, playing_field_height-50))
    
    #Draw the small screen for the next block
    draw_small_screen(next_block)

    #Set tiles
    y = off_set_y
    for i in range(20):
        for tile in playing_field.tiles["row"+str(i+1)][y]:
            tile.draw_tile()
        y += tile_length

    #Blocks while falling
    for tile in block.tiles:
        if tile.y >= off_set_y:
            tile.draw_tile()

    #Sets borders
    pygame.draw.line(DISPLAY_SCREEN , blue, (off_set_x-2, off_set_y-3), (playing_field_width+off_set_x+1, off_set_y-3), 4) # horizontal line top
    pygame.draw.line(DISPLAY_SCREEN , blue, (off_set_x-2, off_set_y+playing_field_height+1), (playing_field_width+off_set_x+1, off_set_y+playing_field_height+1), 4) # horizontal line bottom
    pygame.draw.line(DISPLAY_SCREEN , blue, (off_set_x-3, off_set_y-3), (off_set_x-3, off_set_y+playing_field_height+1), 4) # vertical line left
    pygame.draw.line(DISPLAY_SCREEN , blue, (playing_field_width+off_set_x+1, off_set_y-3), (playing_field_width+off_set_x+1, off_set_y+playing_field_height+1), 4) # vertical line right

    #Sets Grid
    current_y_horizontal_lines = off_set_y
    current_x_vertical_lines = off_set_x
    for i in range(19): 
        current_y_horizontal_lines += 33
        pygame.draw.line(DISPLAY_SCREEN , white, (off_set_x, current_y_horizontal_lines), (playing_field_width+off_set_x-1, current_y_horizontal_lines)) # horizontal line top
    for j in range(9): 
        current_x_vertical_lines += 33        
        pygame.draw.line(DISPLAY_SCREEN , white, (current_x_vertical_lines-1, off_set_y), (current_x_vertical_lines-1, playing_field_height+off_set_y)) # horizontal line top

    pygame.display.update()

def draw_small_screen(next_block):
    
    #Sets background
    pygame.draw.rect(DISPLAY_SCREEN , black, (playing_field_width+tile_length*2, height/2-20, 6*tile_length, 6*tile_length) )
    
    #Sets borders
    pygame.draw.line(DISPLAY_SCREEN , blue, (playing_field_width+tile_length*2-2, height/2-20-2), ((6*tile_length)+(playing_field_width+tile_length*2), (height/2-20-2)), 3) # horizontal line top
    pygame.draw.line(DISPLAY_SCREEN , blue, (playing_field_width+tile_length*2-2, height/2-20+(6*tile_length)), ((6*tile_length)+(playing_field_width+tile_length*2), height/2-20+(6*tile_length)), 3) # horizontal line bottom
    pygame.draw.line(DISPLAY_SCREEN , blue, (playing_field_width+tile_length*2-2, height/2-20-2), (playing_field_width+tile_length*2-2, height/2-20+(6*tile_length)), 3) # vertical line left
    pygame.draw.line(DISPLAY_SCREEN , blue, ((6*tile_length)+(playing_field_width+tile_length*2), height/2-20-2), ((6*tile_length)+(playing_field_width+tile_length*2), height/2-20+(6*tile_length)), 3) # vertical line right
    
    #Sets text
    font = pygame.font.SysFont("comicsansms", 30)
    rendered_text = font.render("Next Block", 1, orange)
    DISPLAY_SCREEN.blit(rendered_text, (playing_field_width+tile_length*2,  height/2-70))
    
    #Displays next block
    temp_block = Block(next_block.shape, next_block.color)  
    temp_block.tiles = [Tile(playing_field_width+tile_length*2+2*tile_length, height/2-20+4*tile_length, next_block.color), Tile(0, 0, next_block.color), Tile(0, 0, next_block.color), Tile(0, 0, next_block.color)]
    temp_block.complete_block()

    for tile in temp_block.tiles:
        tile.draw_tile()

def is_game_over(playing_field, player): 
    y = off_set_y
    for i in range(20):
        for tile in playing_field.tiles["row"+str(i+1)][y]:
            if not tile.empty and tile.y <= off_set_y: 
                temp_y = off_set_y
                for j in range(20):
                    for tile in playing_field.tiles["row"+str(j+1)][temp_y]:
                        tile.draw_tile()
                    temp_y += tile_length

                font = pygame.font.SysFont("comicsansms", 48)
                rendered_text = font.render("GAME OVER", 1, white)
                DISPLAY_SCREEN.blit(rendered_text, (off_set_x+20, playing_field_height/2))
                pygame.display.update()

                time.sleep(2)   
                introduction(player)
        y += tile_length

def start_game():    
    global best_score
    global longest_time

    rand_index = random.randint(0, 6)
    block = Block(shapes[rand_index], block_colors[rand_index])

    next_rand_index = random.randint(0, 6)
    next_block = Block(shapes[next_rand_index], block_colors[next_rand_index]) 

    playing_field = PlayingField()
    start_time = pygame.time.get_ticks()
    player = Player(start_time)

    while True:
        update_graphics(block, next_block, playing_field, player)

        (block, next_block, is_new) = block.get_new_block(next_block, playing_field, player)
        if is_new:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
            pygame.event.clear()

        manage_events(block, next_block, playing_field, player)
        update_graphics(block, next_block, playing_field, player)

        block.block_is_falling(next_block, playing_field, player)
        update_graphics(block, next_block, playing_field, player)
        
        playing_field.destory_full_row(player)
        update_graphics(block, next_block, playing_field, player)

        if player.score > best_score:
            best_score = player.score
        if player.time_since_start > longest_time:
            longest_time = player.time_since_start

        is_game_over(playing_field, player)
        update_graphics(block, next_block, playing_field, player)

        pygame.display.update()
        clock.tick(60)


def manage_events(block, next_block, playing_field, player):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                #move the block to the left
                block.move_left(playing_field)
            elif event.key == pygame.K_RIGHT:
                #move the block to the right
                block.move_right(playing_field)
            elif event.key == pygame.K_UP:
                # rotate block
                block.rotate(next_block, playing_field, player)
            if event.key == pygame.K_SPACE:
                # let the block fall completely
                block.fall_completely(next_block, playing_field, player)
            if event.key == pygame.K_DOWN:
                # let the block fall down faster
                block.block_is_falling(next_block, playing_field, player, "faster")

    update_graphics(block, next_block, playing_field, player)


def introduction(player = None):
    button_width = 300
    button_height = 90
    
    #start_x_button = width/2-button_width/2
    play_button = Button(blue, orange, -400, height/2, button_width, button_height, 32, black, white, "PLAY")
    instructions_button = Button(blue, orange, width+150, height/2+button_height+10, button_width,button_height, 32, black, white, "INSTRUCTIONS")
    quit_button = Button(blue, orange, -400, height/2+button_height*2+20, button_width,button_height, 32, black, white, "QUIT")
    
    font = pygame.font.SysFont("comicsansms", 48)
    rendered_text = font.render("Tetris", 1, black)
    rendered_text_y = height

    #To draw the Tetris text in an animated way
    while rendered_text_y > 10: 
        DISPLAY_SCREEN.blit(background_img, (0, 0))

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

        rendered_text_y -= 1.5
        DISPLAY_SCREEN.blit(rendered_text, (width/2-80, rendered_text_y))
        pygame.display.update()

    #To draw the score and time texts in an animated way
    if player:
        font_small = pygame.font.SysFont("comicsansms", 30)
        rendered_current_score = font_small.render("Current Score: " + str(player.score), 1, orange)
        rendered_best_score = font_small.render("Best Score: " + str(best_score), 1, orange)
        rendered_current_time = font_small.render("Current Time: " + str(player.time_since_start), 1, orange)
        rendered_longest_time = font_small.render("Longest Time: " + str(longest_time), 1, orange)

        rendered_current_score_y = height
        rendered_best_score_y = height+40
        rendered_current_time_y = height+80
        rendered_longest_time_y = height+120

        while rendered_current_score_y > 150: 
            DISPLAY_SCREEN.blit(background_img, (0, 0))
            DISPLAY_SCREEN.blit(rendered_text, (width/2-80, rendered_text_y))

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()

            rendered_current_score_y -= 1.5
            rendered_best_score_y -= 1.5
            rendered_current_time_y -= 1.5
            rendered_longest_time_y -= 1.5

            DISPLAY_SCREEN.blit(rendered_current_score, (off_set_x, rendered_current_score_y))
            DISPLAY_SCREEN.blit(rendered_best_score, (off_set_x+45, rendered_best_score_y))
            DISPLAY_SCREEN.blit(rendered_current_time, (off_set_x+15, rendered_current_time_y))
            DISPLAY_SCREEN.blit(rendered_longest_time, (off_set_x+15, rendered_longest_time_y))

            pygame.display.update()

    #To draw the buttons in an animated way
    while play_button.x < width/2-button_width/2 or instructions_button.x > width/2-button_width/2:
        DISPLAY_SCREEN.blit(background_img, (0, 0))
        DISPLAY_SCREEN.blit(rendered_text, (width/2-80, rendered_text_y))
        if player:
            DISPLAY_SCREEN.blit(rendered_current_score, (off_set_x, rendered_current_score_y))
            DISPLAY_SCREEN.blit(rendered_best_score, (off_set_x+45, rendered_best_score_y))
            DISPLAY_SCREEN.blit(rendered_current_time, (off_set_x+15, rendered_current_time_y))
            DISPLAY_SCREEN.blit(rendered_longest_time, (off_set_x+15, rendered_longest_time_y))

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
        
        if play_button.x < width/2-button_width/2:
            play_button.x += 3
            quit_button.x += 3
        if instructions_button.x > width/2-button_width/2 :    
            instructions_button.x -= 3

        play_button.blit(DISPLAY_SCREEN)
        instructions_button.blit(DISPLAY_SCREEN)
        quit_button.blit(DISPLAY_SCREEN)
        pygame.display.update()

    run = True
    while run:
        DISPLAY_SCREEN.blit(background_img, (0, 0))
        DISPLAY_SCREEN.blit(rendered_text, (width/2-80, rendered_text_y))
        if player:
            DISPLAY_SCREEN.blit(rendered_current_score, (off_set_x, rendered_current_score_y))
            DISPLAY_SCREEN.blit(rendered_best_score, (off_set_x+45, rendered_best_score_y))
            DISPLAY_SCREEN.blit(rendered_current_time, (off_set_x+15, rendered_current_time_y))
            DISPLAY_SCREEN.blit(rendered_longest_time, (off_set_x+15, rendered_longest_time_y))

        # Get the position of the mouse
        mouse_position = pygame.mouse.get_pos() 
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                if play_button.is_clicked(mouse_position, event):
                    start_game()
                    run = False
                elif instructions_button.is_clicked(mouse_position, event):
                    instructions(player)
                    run = False
                elif quit_button.is_clicked(mouse_position, event):
                    pygame.quit()
                    sys.exit()
        
        if play_button.is_hovered_over(mouse_position):
            play_button.blit_hovered_over(DISPLAY_SCREEN)
        else:
            play_button.blit(DISPLAY_SCREEN, gray)
        if instructions_button.is_hovered_over(mouse_position):
            instructions_button.blit_hovered_over(DISPLAY_SCREEN)
        else:
            instructions_button.blit(DISPLAY_SCREEN, gray)
        if quit_button.is_hovered_over(mouse_position):
            quit_button.blit_hovered_over(DISPLAY_SCREEN)
        else:
            quit_button.blit(DISPLAY_SCREEN, gray)

        clock.tick(60)
        pygame.display.update()


def instructions(player = None):
    button_width = 150
    button_height = 60

    play_button = Button(blue, orange, width-150-10, height-80, button_width, button_height, 32, black, white, "PLAY >>")
    back_button = Button(blue, orange, 10, height-80, button_width, button_height, 32, black, white, "<< BACK")

    run = True
    while run:
        DISPLAY_SCREEN.blit(instructions_img, (0, 0))
        font = pygame.font.SysFont("comicsansms", 48)
        rendered_text = font.render("Tetris", 1, orange)
        DISPLAY_SCREEN.blit(rendered_text, (width/2-80, 10))

        # Get the position of the mouse
        mouse_position = pygame.mouse.get_pos() 
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                if play_button.is_clicked(mouse_position, event):
                    start_game()
                    run = False
                elif back_button.is_clicked(mouse_position, event):
                    introduction(player)
                    run = False

        instructions_label = "Instructions" 
        font = pygame.font.SysFont("comicsansms", 40)
        rendered_text = font.render(instructions_label, 1, orange)
        DISPLAY_SCREEN.blit(rendered_text, (width/2 - rendered_text.get_width()/2, 100))
    
         
        instructions1 = "   Move Right:                      right arrow >"  
        instructions2 = "   Move   Left:                     left    arrow <" 
        instructions3 = "          Rotate:                      up      arrow ^" 
        instructions4 = "   Soft  Drop:                      down   arrow" 
        instructions5 = "   Hard  Drop:                      space"

        font = pygame.font.SysFont("comicsansms", 20)
        rendered_text1 = font.render(instructions1, 1, orange)
        rendered_text2 = font.render(instructions2, 1, orange)
        rendered_text3 = font.render(instructions3, 1, orange)
        rendered_text4 = font.render(instructions4, 1, orange)
        rendered_text5 = font.render(instructions5, 1, orange)

        DISPLAY_SCREEN.blit(rendered_text1, (20, 200))
        DISPLAY_SCREEN.blit(rendered_text2, (20, 240))
        DISPLAY_SCREEN.blit(rendered_text3, (20, 280))
        DISPLAY_SCREEN.blit(rendered_text4, (20, 320))
        DISPLAY_SCREEN.blit(rendered_text5, (20, 360))

        if play_button.is_hovered_over(mouse_position):
            play_button.blit_hovered_over(DISPLAY_SCREEN)
        else:
            play_button.blit(DISPLAY_SCREEN, gray)
        if back_button.is_hovered_over(mouse_position):
            back_button.blit_hovered_over(DISPLAY_SCREEN)
        else:
            back_button.blit(DISPLAY_SCREEN, gray)
        
        clock.tick(60)
        pygame.display.update()

if __name__ == "__main__":
    introduction()
    

Output

Output 1 of Tetris game in python
Output 2 of Tetris game in python

Also Read:

Share:

Author: Ayush Purawr