Python Tetris Game – Develop Tetris using PyGame
Master Python with 70+ Hands-on Projects and Get Job-ready - Learn Python
Have you ever played the Tetris puzzle? It is a video game that is developed with a motive to get an order out of chaos. It helps in improving both thinking and learning skills. Wouldn’t it be interesting to build this game in Python? So, let’s start.
What is Tetris?
The Tetris game consists of blocks/tetriminos, of different shapes. that appear one after another. And the objective is to place these blocks on the screen such that we form rows at the bottom of the board.
Every completed row increases the score. To do so, the player will be allowed to move the falling block to left, right, down and also rotate it using the keyboard buttons.
Python Tetris – Project details
To build this game we will be using the Pygame module in Python. We will also use the random module to select the shape and color of the Tetrimino. And we consider the whole game board and the blocks as matrices. This makes it easy to do the operations, shifting, and rotation.
Download Python Tetris Code
Please download the code for the Tetris game here: Python Tetris Game Project Source Code
Project Prerequisites
It is suggested to have prior knowledge on Python and PyGame. If you don’t have the PyGame module, then you can install it using the following command.
pip install pygame
Steps to build the Python Tetris Game
We are done discussing the necessities of the project, let us look into the steps to be followed to build the project.
1. Create a matrix storing the information about the block and write a class to handle these details.
2. Create a class to handle the creation of blocks, their movement, and placement.
Technology is evolving rapidly!
Stay updated with DataFlair on WhatsApp!!
3. Create the main window for the game.
4. Keep checking the button pressed and the status of the blocks in the board.
5. End the game when the blocks touch the top of the board.
This game is written in an infinite while loop that runs till the fifth condition above is met.
1. Importing the required modules
We are importing the pygame module which we use to build the Tetris game and then importing the random module to get the shapes of the blocks in a random manner.
import pygame import random
2. Creating variables to store shapes and colors of the blocks
In the below code, the shapes variable holds the matrix that contains information about the shape of the block. Assume a 4×4 block and give each cell indices as shown below
0 | 1 | 2 | 3 |
4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 |
Then, [1, 5, 9, 13] represents the vertical line (second column), [1, 5, 9, 8] represents L shape, etc. And the shapeColors hold the RGB values of different colors from which we randomly select a color for a block.
#Shapes of the blocks shapes = [ [[1, 5, 9, 13], [4, 5, 6, 7]], [[4, 5, 9, 10], [2, 6, 5, 9]], [[6, 7, 9, 10], [1, 5, 6, 10]], [[1, 2, 5, 9], [0, 4, 5, 6], [1, 5, 9, 8], [4, 5, 6, 10]], [[1, 2, 6, 10], [5, 6, 7, 9], [2, 6, 10, 11], [3, 5, 6, 7]], [[1, 4, 5, 6], [1, 4, 5, 9], [4, 5, 6, 9], [1, 5, 6, 9]], [[1, 2, 5, 6]], ] #Colors of the blocks shapeColors = [(0, 255, 0), (255, 0, 0), (0, 255, 255), (255, 255, 0), (255, 165, 0), (0, 0, 255), (128, 0, 128)]
3. Creating a class Blocks to hold information about the current block
This class assigns the coordinates, shape, color and rotation to the block object created. Using the function random.randint(), which generates a random integer in the given range, a random shape and color are assigned to a block.
The function rotate() gives the index of the rotation variant of a given shape from the matrix ‘shapes’. And the function image() returns the rotated variant block to the Block object.
# GLOBALS VARS width = 700 height = 600 gameWidth = 100 gameHeight = 400 blockSize = 20 topLeft_x = (width - gameWidth) // 2 topLeft_y = height - gameHeight - 50 class Block: x = 0 y = 0 n = 0 def __init__(self, x, y,n): self.x = x self.y = y self.type = n self.color = n self.rotation = 0 def image(self): return shapes[self.type][self.rotation] def rotate(self): self.rotation = (self.rotation + 1) % len(shapes[self.type])
4. Creating a class Tetris for creation of blocks, controlling their movement and placement
In this class, we first create variables that set the properties of the board and also set the score to 0 and state to “start”. The field variable stores the board in the form of a 2D matrix.
# GLOBALS VARS width = 700 height = 600 gameWidth = 100 gameHeight = 400 blockSize = 20 topLeft_x = (width - gameWidth) // 2 topLeft_y = height - gameHeight - 50 class Block: x = 0 y = 0 n = 0 def __init__(self, x, y,n): self.x = x self.y = y self.type = n self.color = n self.rotation = 0 def image(self): return shapes[self.type][self.rotation] def rotate(self): self.rotation = (self.rotation + 1) % len(shapes[self.type])
In the following code, which is a part of the Tetris class, has the below functions
1. The new_block() function creates a new block using the Block() class.
2. The function next_block() creates the next block that would be appearing on the screen.
3. The intersects() function checks if the blocks touch the top of the board. This decides the end of the game.
4. The break_lines() function checks if the blocks form any row. If the condition is met, then it increases the score and deletes the line.
5. And the function draw_next_block() places the next block beside the main game to show it to the player.
#Creates a new block def new_block(self): self.block = Block(3, 0,random.randint(0, len(shapes) - 1)) def next_block(self): self.nextBlock=Block(3,0,random.randint(0, len(shapes) - 1)) #Checks if the blocks touch the top of the board def intersects(self): intersection = False for i in range(4): for j in range(4): if i * 4 + j in self.block.image(): if i + self.block.y > self.height - 1 or \ j + self.block.x > self.width - 1 or \ j + self.block.x < 0 or \ self.field[i + self.block.y][j + self.block.x] > 0: intersection = True return intersection #Checks if a row is formed and destroys that line 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 i1 in range(i, 1, -1): for j in range(self.width): self.field[i1][j] = self.field[i1 - 1][j] self.score += lines ** 2 def draw_next_block(self,screen): font = pygame.font.SysFont("Calibri", 30) label = font.render("Next Shape", 1, (128,128,128)) sx = topLeft_x + gameWidth + 50 sy = topLeft_y + gameHeight/2 - 100 format = self.nextBlock.image() for i in range(4): for j in range(4): p = i * 4 + j if p in self.nextBlock.image(): pygame.draw.rect(screen, shapeColors[self.nextBlock.color],(sx + j*30, sy + i*30, 30, 30), 0)
Now it’s time to write the functions to move the blocks.
1. The go_down() function moves the block down by a unit
2. The go_space() function is similar to go_down(), but it moves the block down to the bottom
3. The freez() function runs once the block reaches the bottom. And it checks if any row is formed, forms a new block and if it touches the top, it ends the game.
4. The go_side() function moves the block to either right or left
5. And the rotate() function rotates the block by 90 degrees in clockwise or anticlockwise direction
#Moves the block down by a unit def go_down(self): self.block.y += 1 if self.intersects(): self.block.y -= 1 self.freeze() #Moves the block to the bottom def go_space(self): while not self.intersects(): self.block.y += 1 self.block.y -= 1 self.freeze() # This function runs once the block reaches the bottom. def freeze(self): for i in range(4): for j in range(4): if i * 4 + j in self.block.image(): self.field[i + self.block.y][j + self.block.x] = self.block.color self.break_lines() #Checking if any row is formed self.new_block() #Creating a new block if self.intersects(): #If blocks touch the top of the board, then ending the game by setting status as gameover self.state = "gameover" #This function moves the block horizontally def go_side(self, dx): old_x = self.block.x self.block.x += dx if self.intersects(): self.block.x = old_x #This function rotates the block def rotate(self): old_rotation = self.block.rotation self.block.rotate() if self.intersects(): self.block.rotation = old_rotation
Main game
It’s time to create the main window. We do this by using the init() function in PyGame. We also set the other properties like size, and title. When the user presses any of the keyboard buttons, the main game starts.
pygame.font.init() screen = pygame.display.set_mode((width, height)) pygame.display.set_caption("Tetris by DataFlair") run = True while run: screen.fill((16, 57, 34 )) font = pygame.font.SysFont("Calibri", 70, bold=True) label = font.render("Press any key to begin!", True, '#FFFFFF') screen.blit(label, (10, 300 )) pygame.display.update() for event in pygame.event.get(): if event.type == pygame.QUIT: run = False if event.type == pygame.KEYDOWN: startGame() pygame.quit()
Now, write the function startGame() with a for loop that runs infinitely till the game end condition is met. This loop includes the following operations:
1. Creating a new block if there is no moving block.
2. Moving the block down by a unit continuously or when the down key is pressed.
3. Checking the key pressed, if any, and doing the corresponding function discussed above.
4. Updating the board with the previous blocks and the moving block.
5. Checking the status and ending the game if the status is gameover
def startGame(): done = False clock = pygame.time.Clock() fps = 25 game = Tetris(20, 10) counter = 0 pressing_down = False while not done: #Create a new block if there is no moving block if game.block is None: game.new_block() if game.nextBlock is None: game.next_block() counter += 1 #Keeping track of the time if counter > 100000: counter = 0 #Moving the block continuously with time or when down key is pressed if counter % (fps // game.level // 2) == 0 or pressing_down: if game.state == "start": game.go_down() #Checking which key is pressed and running corresponding function 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: game.moveDown() if event.key == pygame.K_LEFT: game.moveHoriz(-1) if event.key == pygame.K_RIGHT: game.moveHoriz(1) if event.key == pygame.K_SPACE: game.moveBottom() if event.key == pygame.K_ESCAPE: game.__init__(20, 10) screen.fill('#FFFFFF') #Updating the game board regularly for i in range(game.height): for j in range(game.width): pygame.draw.rect(screen, '#B2BEB5', [game.x + game.zoom * j, game.y + game.zoom * i, game.zoom, game.zoom], 1) if game.field[i][j] > 0: pygame.draw.rect(screen, shapeColors[game.field[i][j]], [game.x + game.zoom * j + 1, game.y + game.zoom * i + 1, game.zoom - 2, game.zoom - 1]) #Updating the board with the moving block if game.block is not None: for i in range(4): for j in range(4): p = i * 4 + j if p in game.block.image(): pygame.draw.rect(screen, shapeColors[game.block.color], [game.x + game.zoom * (j + game.block.x) + 1, game.y + game.zoom * (i + game.block.y) + 1, game.zoom - 2, game.zoom - 2]) #Showing the score font = pygame.font.SysFont('Calibri', 40, True, False) font1 = pygame.font.SysFont('Calibri', 25, True, False) text = font.render("Score: " + str(game.score), True, '#000000') text_game_over = font.render("Game Over", True, '#000000') text_game_over1 = font.render("Press ESC", True, '#000000') #Ending the game if state is gameover screen.blit(text, [300, 0]) if game.state == "gameover": screen.blit(text_game_over, [300, 200]) screen.blit(text_game_over1, [300, 265]) game.draw_next_block(screen) pygame.display.flip() clock.tick(fps)
Python Tetris Game Output
Summary
With this Python project, we have successfully built the python tetris game. For this, we used the pygame and random libraries. We learned how to create shapes for blocks, capture events from the keyboard and trigger a function. We could also check the status of the Tetris board. Hoping that you enjoyed developing this with us!
Your 15 seconds will encourage us to work even harder
Please share your happy experience on Google
whenever i try to run the terminal says ‘Tetris’ object has no attribute ‘go_down’
Hi try move_down and bin solved
when i try to run it says Tetris object has no attribute go_down
change line 187 from “go_down()” to “moveDown()
I got it working, butt wasn’t able to get the 1×4 (light green) to stay in the game, it would disappear whenever it was placed without removing any lines, it just disappeared.
yes I also tested this code, the 1×4 is just disappears
game = Tetris(20, 10)
NameError: name ‘Tetris’ is not defined