Skip to content

Commit e863537

Browse files
committed
add tetris game tutorial
1 parent 860def9 commit e863537

File tree

4 files changed

+269
-0
lines changed

4 files changed

+269
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -268,5 +268,6 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
268268
- [How to Build a GUI Dictionary App with Tkinter in Python](https://www.thepythoncode.com/article/make-a-gui-audio-dictionary-python). ([code](gui-programming/word-dictionary-with-audio))
269269
- [How to Make a Real-Time GUI Spelling Checker in Python](https://www.thepythoncode.com/article/make-a-realtime-spelling-checker-gui-python). ([code](gui-programming/realtime-spelling-checker))
270270
- [How to Create a GUI Hangman Game using PyGame in Python](https://www.thepythoncode.com/article/hangman-gui-game-with-pygame-in-python). ([code](gui-programming/hangman-game-gui))
271+
- [How to Make a Tetris Game using PyGame in Python](https://www.thepythoncode.com/article/create-a-tetris-game-with-pygame-in-python). ([code](gui-programming/tetris-game))
271272

272273
For any feedback, please consider pulling requests.

gui-programming/tetris-game/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# [How to Make a Tetris Game using PyGame in Python](https://www.thepythoncode.com/article/create-a-tetris-game-with-pygame-in-python)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pygame

gui-programming/tetris-game/tetris.py

+266
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
import sys
2+
import pygame
3+
import random
4+
5+
pygame.init()
6+
7+
# Screen dimensions
8+
WIDTH, HEIGHT = 800, 600
9+
GRID_SIZE = 25
10+
11+
# Colors
12+
WHITE = (255, 255, 255)
13+
BLACK = (0, 0, 0)
14+
RED = (255, 0, 0)
15+
BLUE = (0, 0, 255)
16+
GREEN = (0, 255, 0)
17+
COLORS = [RED, BLUE, GREEN]
18+
19+
# Tetromino shapes
20+
SHAPES = [
21+
[
22+
['.....',
23+
'.....',
24+
'.....',
25+
'OOOO.',
26+
'.....'],
27+
['.....',
28+
'..O..',
29+
'..O..',
30+
'..O..',
31+
'..O..']
32+
],
33+
[
34+
['.....',
35+
'.....',
36+
'..O..',
37+
'.OOO.',
38+
'.....'],
39+
['.....',
40+
'..O..',
41+
'.OO..',
42+
'..O..',
43+
'.....'],
44+
['.....',
45+
'.....',
46+
'.OOO.',
47+
'..O..',
48+
'.....'],
49+
['.....',
50+
'..O..',
51+
'..OO.',
52+
'..O..',
53+
'.....']
54+
],
55+
[
56+
[
57+
'.....',
58+
'.....',
59+
'..OO.',
60+
'.OO..',
61+
'.....'],
62+
['.....',
63+
'.....',
64+
'.OO..',
65+
'..OO.',
66+
'.....'],
67+
['.....',
68+
'.O...',
69+
'.OO..',
70+
'..O..',
71+
'.....'],
72+
['.....',
73+
'..O..',
74+
'.OO..',
75+
'.O...',
76+
'.....']
77+
],
78+
[
79+
['.....',
80+
'..O..',
81+
'..O.',
82+
'..OO.',
83+
'.....'],
84+
['.....',
85+
'...O.',
86+
'.OOO.',
87+
'.....',
88+
'.....'],
89+
['.....',
90+
'.OO..',
91+
'..O..',
92+
'..O..',
93+
'.....'],
94+
['.....',
95+
'.....',
96+
'.OOO.',
97+
'.O...',
98+
'.....']
99+
],
100+
]
101+
102+
103+
class Tetromino:
104+
def __init__(self, x, y, shape):
105+
self.x = x
106+
self.y = y
107+
self.shape = shape
108+
self.color = random.choice(COLORS) # You can choose different colors for each shape
109+
self.rotation = 0
110+
111+
112+
class Tetris:
113+
def __init__(self, width, height):
114+
self.width = width
115+
self.height = height
116+
self.grid = [[0 for _ in range(width)] for _ in range(height)]
117+
self.current_piece = self.new_piece()
118+
self.game_over = False
119+
self.score = 0 # Add score attribute
120+
121+
def new_piece(self):
122+
# Choose a random shape
123+
shape = random.choice(SHAPES)
124+
# Return a new Tetromino object
125+
return Tetromino(self.width // 2, 0, shape)
126+
127+
def valid_move(self, piece, x, y, rotation):
128+
"""Check if the piece can move to the given position"""
129+
for i, row in enumerate(piece.shape[(piece.rotation + rotation) % len(piece.shape)]):
130+
for j, cell in enumerate(row):
131+
try:
132+
if cell == 'O' and (self.grid[piece.y + i + y][piece.x + j + x] != 0):
133+
return False
134+
except IndexError:
135+
return False
136+
return True
137+
138+
def clear_lines(self):
139+
"""Clear the lines that are full and return the number of cleared lines"""
140+
lines_cleared = 0
141+
for i, row in enumerate(self.grid[:-1]):
142+
if all(cell != 0 for cell in row):
143+
lines_cleared += 1
144+
del self.grid[i]
145+
self.grid.insert(0, [0 for _ in range(self.width)])
146+
return lines_cleared
147+
148+
def lock_piece(self, piece):
149+
"""Lock the piece in place and create a new piece"""
150+
for i, row in enumerate(piece.shape[piece.rotation % len(piece.shape)]):
151+
for j, cell in enumerate(row):
152+
if cell == 'O':
153+
self.grid[piece.y + i][piece.x + j] = piece.color
154+
# Clear the lines and update the score
155+
lines_cleared = self.clear_lines()
156+
self.score += lines_cleared * 100 # Update the score based on the number of cleared lines
157+
# Create a new piece
158+
self.current_piece = self.new_piece()
159+
# Check if the game is over
160+
if not self.valid_move(self.current_piece, 0, 0, 0):
161+
self.game_over = True
162+
return lines_cleared
163+
164+
def update(self):
165+
"""Move the tetromino down one cell"""
166+
if not self.game_over:
167+
if self.valid_move(self.current_piece, 0, 1, 0):
168+
self.current_piece.y += 1
169+
else:
170+
self.lock_piece(self.current_piece)
171+
172+
def draw(self, screen):
173+
"""Draw the grid and the current piece"""
174+
for y, row in enumerate(self.grid):
175+
for x, cell in enumerate(row):
176+
if cell:
177+
pygame.draw.rect(screen, cell, (x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE - 1, GRID_SIZE - 1))
178+
179+
if self.current_piece:
180+
for i, row in enumerate(self.current_piece.shape[self.current_piece.rotation % len(self.current_piece.shape)]):
181+
for j, cell in enumerate(row):
182+
if cell == 'O':
183+
pygame.draw.rect(screen, self.current_piece.color, ((self.current_piece.x + j) * GRID_SIZE, (self.current_piece.y + i) * GRID_SIZE, GRID_SIZE - 1, GRID_SIZE - 1))
184+
185+
186+
def draw_score(screen, score, x, y):
187+
"""Draw the score on the screen"""
188+
font = pygame.font.Font(None, 36)
189+
text = font.render(f"Score: {score}", True, WHITE)
190+
screen.blit(text, (x, y))
191+
192+
193+
def draw_game_over(screen, x, y):
194+
"""Draw the game over text on the screen"""
195+
font = pygame.font.Font(None, 48)
196+
text = font.render("Game Over", True, RED)
197+
screen.blit(text, (x, y))
198+
199+
200+
def main():
201+
# Initialize pygame
202+
screen = pygame.display.set_mode((WIDTH, HEIGHT))
203+
pygame.display.set_caption('Tetris')
204+
# Create a clock object
205+
clock = pygame.time.Clock()
206+
# Create a Tetris object
207+
game = Tetris(WIDTH // GRID_SIZE, HEIGHT // GRID_SIZE)
208+
fall_time = 0
209+
fall_speed = 50 # You can adjust this value to change the falling speed, it's in milliseconds
210+
while True:
211+
# Fill the screen with black
212+
screen.fill(BLACK)
213+
for event in pygame.event.get():
214+
# Check for the QUIT event
215+
if event.type == pygame.QUIT:
216+
pygame.quit()
217+
sys.exit()
218+
# Check for the KEYDOWN event
219+
if event.type == pygame.KEYDOWN:
220+
if event.key == pygame.K_LEFT:
221+
if game.valid_move(game.current_piece, -1, 0, 0):
222+
game.current_piece.x -= 1 # Move the piece to the left
223+
if event.key == pygame.K_RIGHT:
224+
if game.valid_move(game.current_piece, 1, 0, 0):
225+
game.current_piece.x += 1 # Move the piece to the right
226+
if event.key == pygame.K_DOWN:
227+
if game.valid_move(game.current_piece, 0, 1, 0):
228+
game.current_piece.y += 1 # Move the piece down
229+
if event.key == pygame.K_UP:
230+
if game.valid_move(game.current_piece, 0, 0, 1):
231+
game.current_piece.rotation += 1 # Rotate the piece
232+
if event.key == pygame.K_SPACE:
233+
while game.valid_move(game.current_piece, 0, 1, 0):
234+
game.current_piece.y += 1 # Move the piece down until it hits the bottom
235+
game.lock_piece(game.current_piece) # Lock the piece in place
236+
# Get the number of milliseconds since the last frame
237+
delta_time = clock.get_rawtime()
238+
# Add the delta time to the fall time
239+
fall_time += delta_time
240+
if fall_time >= fall_speed:
241+
# Move the piece down
242+
game.update()
243+
# Reset the fall time
244+
fall_time = 0
245+
# Draw the score on the screen
246+
draw_score(screen, game.score, 10, 10)
247+
# Draw the grid and the current piece
248+
game.draw(screen)
249+
if game.game_over:
250+
# Draw the "Game Over" message
251+
draw_game_over(screen, WIDTH // 2 - 100, HEIGHT // 2 - 30) # Draw the "Game Over" message
252+
# You can add a "Press any key to restart" message here
253+
# Check for the KEYDOWN event
254+
if event.type == pygame.KEYDOWN:
255+
# Create a new Tetris object
256+
game = Tetris(WIDTH // GRID_SIZE, HEIGHT // GRID_SIZE)
257+
# Update the display
258+
pygame.display.flip()
259+
# Set the framerate
260+
clock.tick(60)
261+
262+
263+
if __name__ == "__main__":
264+
main()
265+
266+

0 commit comments

Comments
 (0)