
专栏导读
🌸 欢迎来到Pygame基础专栏—大家可以在这里学习pygame基础知识
文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏
❤️ 欢迎各位佬关注! ❤️
完整代码
import pygame
import random
import time
pygame.init()
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
CYAN = (0, 255, 255)
BLUE = (0, 0, 255)
ORANGE = (255, 165, 0)
YELLOW = (255, 255, 0)
GREEN = (0, 255, 0)
PURPLE = (128, 0, 128)
RED = (255, 0, 0)
BLOCK_SIZE = 30
GRID_WIDTH = 10
GRID_HEIGHT = 20
SCREEN_WIDTH = BLOCK_SIZE * (GRID_WIDTH + 8)
SCREEN_HEIGHT = BLOCK_SIZE * GRID_HEIGHT
GAME_AREA_LEFT = BLOCK_SIZE * 4
GAME_AREA_TOP = 0
SHAPES = [
[[1, 1, 1, 1]],
[[1, 1], [1, 1]],
[[1, 1, 1], [0, 1, 0]],
[[1, 1, 1], [1, 0, 0]],
[[1, 1, 1], [0, 0, 1]],
[[0, 1, 1], [1, 1, 0]],
[[1, 1, 0], [0, 1, 1]]
]
SHAPE_COLORS = [CYAN, YELLOW, PURPLE, ORANGE, BLUE, GREEN, RED]
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("俄罗斯方块")
clock = pygame.time.Clock()
class Tetromino:
def __init__(self):
self.shape_index = random.randint(0, len(SHAPES) - 1)
self.shape = SHAPES[self.shape_index]
self.color = SHAPE_COLORS[self.shape_index]
self.x = GRID_WIDTH // 2 - len(self.shape[0]) // 2
self.y = 0
def rotate(self):
rows = len(self.shape)
cols = len(self.shape[0])
rotated = [[0 for _ in range(rows)] for _ in range(cols)]
for r in range(rows):
for c in range(cols):
rotated[c][rows - 1 - r] = self.shape[r][c]
return rotated
def draw(self, surface):
for y, row in enumerate(self.shape):
for x, cell in enumerate(row):
if cell:
rect = pygame.Rect(
GAME_AREA_LEFT + (self.x + x) * BLOCK_SIZE,
GAME_AREA_TOP + (self.y + y) * BLOCK_SIZE,
BLOCK_SIZE, BLOCK_SIZE
)
pygame.draw.rect(surface, self.color, rect)
pygame.draw.rect(surface, WHITE, rect, 1)
class TetrisGame:
def __init__(self):
self.font = pygame.font.SysFont('simhei', 13)
self.grid = [[0 for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]
self.current_piece = Tetromino()
self.next_piece = Tetromino()
self.game_over = False
self.score = 0
self.level = 1
self.lines_cleared = 0
self.fall_time = 0
self.fall_speed = 0.5
self.last_fall_time = time.time()
def draw_grid(self, surface):
pygame.draw.rect(surface, BLACK, (GAME_AREA_LEFT, GAME_AREA_TOP,
GRID_WIDTH * BLOCK_SIZE,
GRID_HEIGHT * BLOCK_SIZE))
for x in range(GRID_WIDTH + 1):
pygame.draw.line(surface, WHITE,
(GAME_AREA_LEFT + x * BLOCK_SIZE, GAME_AREA_TOP),
(GAME_AREA_LEFT + x * BLOCK_SIZE, GAME_AREA_TOP + GRID_HEIGHT * BLOCK_SIZE))
for y in range(GRID_HEIGHT + 1):
pygame.draw.line(surface, WHITE,
(GAME_AREA_LEFT, GAME_AREA_TOP + y * BLOCK_SIZE),
(GAME_AREA_LEFT + GRID_WIDTH * BLOCK_SIZE, GAME_AREA_TOP + y * BLOCK_SIZE))
for y in range(GRID_HEIGHT):
for x in range(GRID_WIDTH):
if self.grid[y][x]:
color_idx = self.grid[y][x] - 1
rect = pygame.Rect(
GAME_AREA_LEFT + x * BLOCK_SIZE,
GAME_AREA_TOP + y * BLOCK_SIZE,
BLOCK_SIZE, BLOCK_SIZE
)
pygame.draw.rect(surface, SHAPE_COLORS[color_idx], rect)
pygame.draw.rect(surface, WHITE, rect, 1)
def draw_info(self, surface):
info_area = pygame.Rect(0, 0, GAME_AREA_LEFT, SCREEN_HEIGHT)
pygame.draw.rect(surface, (50, 50, 50), info_area)
next_text = self.font.render("下一个:", True, WHITE)
surface.blit(next_text, (20, 20))
next_piece_surface = pygame.Surface((len(self.next_piece.shape[0]) * BLOCK_SIZE,
len(self.next_piece.shape) * BLOCK_SIZE))
next_piece_surface.fill((50, 50, 50))
for y, row in enumerate(self.next_piece.shape):
for x, cell in enumerate(row):
if cell:
rect = pygame.Rect(
x * BLOCK_SIZE,
y * BLOCK_SIZE,
BLOCK_SIZE, BLOCK_SIZE
)
pygame.draw.rect(next_piece_surface, self.next_piece.color, rect)
pygame.draw.rect(next_piece_surface, WHITE, rect, 1)
surface.blit(next_piece_surface, (20, 60))
score_text = self.font.render(f"分数: {self.score}", True, WHITE)
surface.blit(score_text, (20, 180))
level_text = self.font.render(f"等级: {self.level}", True, WHITE)
surface.blit(level_text, (20, 220))
lines_text = self.font.render(f"消除行: {self.lines_cleared}", True, WHITE)
surface.blit(lines_text, (20, 260))
controls_text = [
"操作说明:",
"←→: 左右移动",
"↑: 旋转",
"↓: 加速下落",
"空格: 直接落下",
"P: 暂停游戏",
"R: 重新开始"
]
for i, text in enumerate(controls_text):
ctrl_text = self.font.render(text, True, WHITE)
surface.blit(ctrl_text, (20, 320 + i * 30))
def draw_game_over(self, surface):
overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
overlay.set_alpha(150)
overlay.fill(BLACK)
surface.blit(overlay, (0, 0))
font = pygame.font.SysFont(None, 50)
game_over_text = self.font.render("游戏结束!", True, WHITE)
restart_text = self.font.render("按R键重新开始", True, WHITE)
surface.blit(game_over_text,
(SCREEN_WIDTH // 2 - game_over_text.get_width() // 2,
SCREEN_HEIGHT // 2 - 50))
surface.blit(restart_text,
(SCREEN_WIDTH // 2 - restart_text.get_width() // 2,
SCREEN_HEIGHT // 2 + 10))
def is_collision(self, shape, x, y):
for row_idx, row in enumerate(shape):
for col_idx, cell in enumerate(row):
if cell:
if (x + col_idx < 0 or x + col_idx >= GRID_WIDTH or
y + row_idx >= GRID_HEIGHT):
return True
if y + row_idx >= 0 and self.grid[y + row_idx][x + col_idx]:
return True
return False
def merge_piece(self):
for y, row in enumerate(self.current_piece.shape):
for x, cell in enumerate(row):
if cell and 0 <= self.current_piece.y + y < GRID_HEIGHT:
self.grid[self.current_piece.y + y][self.current_piece.x + x] = self.current_piece.shape_index + 1
def clear_lines(self):
lines_to_clear = []
for y in range(GRID_HEIGHT):
if all(self.grid[y]):
lines_to_clear.append(y)
for line in lines_to_clear:
del self.grid[line]
self.grid.insert(0, [0 for _ in range(GRID_WIDTH)])
if lines_to_clear:
self.lines_cleared += len(lines_to_clear)
self.score += [100, 300, 500, 800][min(len(lines_to_clear) - 1, 3)] * self.level
self.level = min(10, 1 + self.lines_cleared // 10)
self.fall_speed = max(0.05, 0.5 - (self.level - 1) * 0.05)
return len(lines_to_clear)
def move(self, dx, dy):
if not self.is_collision(self.current_piece.shape,
self.current_piece.x + dx,
self.current_piece.y + dy):
self.current_piece.x += dx
self.current_piece.y += dy
return True
return False
def rotate_piece(self):
rotated = self.current_piece.rotate()
if not self.is_collision(rotated, self.current_piece.x, self.current_piece.y):
self.current_piece.shape = rotated
return True
for dx in [-1, 1, -2, 2]:
if not self.is_collision(rotated, self.current_piece.x + dx, self.current_piece.y):
self.current_piece.x += dx
self.current_piece.shape = rotated
return True
return False
def drop_piece(self):
while self.move(0, 1):
pass
def new_piece(self):
self.current_piece = self.next_piece
self.next_piece = Tetromino()
if self.is_collision(self.current_piece.shape,
self.current_piece.x,
self.current_piece.y):
self.game_over = True
def update(self):
current_time = time.time()
if current_time - self.last_fall_time > self.fall_speed:
if not self.move(0, 1):
self.merge_piece()
self.clear_lines()
self.new_piece()
self.last_fall_time = current_time
def reset(self):
self.__init__()
def main():
game = TetrisGame()
paused = False
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
return
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
game.reset()
paused = False
if game.game_over:
continue
if event.key == pygame.K_p:
paused = not paused
if paused:
continue
if event.key == pygame.K_LEFT:
game.move(-1, 0)
elif event.key == pygame.K_RIGHT:
game.move(1, 0)
elif event.key == pygame.K_DOWN:
game.move(0, 1)
elif event.key == pygame.K_UP:
game.rotate_piece()
elif event.key == pygame.K_SPACE:
game.drop_piece()
if not game.game_over and not paused:
game.update()
screen.fill((50, 50, 50))
game.draw_grid(screen)
game.draw_info(screen)
if not game.game_over:
game.current_piece.draw(screen)
if game.game_over:
game.draw_game_over(screen)
pygame.display.flip()
clock.tick(60)
if __name__ == "__main__":
main()
总结
希望对初学者有帮助
致力于办公自动化的小小程序员一枚
希望能得到大家的【一个免费关注】!感谢
求个 🤞 关注 🤞
求个 ❤️ 喜欢 ❤️
求个 👍 收藏 👍