俄罗斯方块也是一个可以简单实现的游戏
代码:
import pygame
import random
import numpy as nppygame.init()# 游戏参数
WIDTH, HEIGHT = 300, 600
GRID_SIZE = 30
GRID_WIDTH = WIDTH // GRID_SIZE
GRID_HEIGHT = HEIGHT // GRID_SIZE
FPS = 3# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
CYAN = (0, 255, 255)
MAGENTA = (255, 0, 255)
YELLOW = (255, 255, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
PURPLE = (148, 0, 211)# 俄罗斯方块形状定义
SHAPES = [[[1, 1, 1, 1]],[[0, 1, 0],[1, 1, 1]],[[1, 1, 1],[0, 0, 1]],[[1, 1, 1],[1, 0, 0]],[[1, 1],[1, 1]],[[1, 1, 0],[0, 1, 1]],[[0, 1, 1],[1, 1, 0]],
]class TetrisGame:def __init__(self):self.grid = [[0] * GRID_WIDTH for _ in range(GRID_HEIGHT)]self.current_shape = Noneself.current_color = Noneself.current_x = 0self.current_y = 0self.score = 0self.game_over = Falseself.current_shape_index = 0self.colors = [RED, CYAN, MAGENTA, YELLOW, GREEN, BLUE, PURPLE]self.current_color_index = 0def new_shape(self):while True:self.current_shape = random.choice(SHAPES)self.current_shape_index = SHAPES.index(self.current_shape)self.current_color_index = self.current_shape_indexself.current_color = self.colors[self.current_color_index]if self.current_shape is not None:breakself.current_x = GRID_WIDTH // 2 - len(self.current_shape[0]) // 2self.current_y = 0return self.current_shapedef rotate(self):if self.current_shape is not None:rotated_shape = np.rot90(self.current_shape)if not self.collision(rotated_shape):self.current_shape = rotated_shapedef move_down(self):self.current_y += 1if self.collision():self.current_y -= 1self.freeze()self.clear_lines()if self.current_y <= 0:# 如果当前方块堆积到游戏区域的顶部,触发游戏结束self.game_over = Trueelse:self.new_shape()def move_left(self):self.current_x -= 1if self.collision():self.current_x += 1def move_right(self):self.current_x += 1if self.collision():self.current_x -= 1def collision(self, shape=None):shape = shape if shape is not None else self.current_shapeif shape is not None:for y, row in enumerate(shape):for x, cell in enumerate(row):if cell and (self.current_y + y >= GRID_HEIGHTor self.current_x + x < 0or self.current_x + x >= GRID_WIDTHor self.grid[self.current_y + y][self.current_x + x]):return Truereturn Falsedef freeze(self):for y, row in enumerate(self.current_shape):for x, cell in enumerate(row):if cell:self.grid[self.current_y + y][self.current_x + x] = self.current_colordef clear_lines(self):lines_to_clear = [i for i, row in enumerate(self.grid) if all(row)]for line in reversed(lines_to_clear):del self.grid[line]self.grid.insert(0, [0] * GRID_WIDTH)self.score += 10def draw_grid(self, surface):for y, row in enumerate(self.grid):for x, cell in enumerate(row):if cell:pygame.draw.rect(surface,cell,(x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE, GRID_SIZE),)def draw_current_shape(self, surface):if self.current_shape is not None:for y, row in enumerate(self.current_shape):for x, cell in enumerate(row):if cell:pygame.draw.rect(surface,self.current_color,((self.current_x + x) * GRID_SIZE, (self.current_y + y) * GRID_SIZE, GRID_SIZE, GRID_SIZE),)def draw_score(self, surface):font = pygame.font.Font(None, 36)score_text = font.render(f"Score: {self.score}", True, WHITE)surface.blit(score_text, (10, 10))def draw_game_over(self, surface):font = pygame.font.Font(None, 72)game_over_text = font.render("Game Over", True, WHITE)surface.blit(game_over_text, (WIDTH // 4, HEIGHT // 3))score_text = font.render(f"Score: {self.score}", True, WHITE)surface.blit(score_text, (WIDTH // 3, HEIGHT // 2))def main():pygame.display.set_caption("Tetris")screen = pygame.display.set_mode((WIDTH, HEIGHT))clock = pygame.time.Clock()game = TetrisGame()# 在循环外部创建第一个形状game.new_shape()while not game.game_over:for event in pygame.event.get():if event.type == pygame.QUIT:game.game_over = Trueelif event.type == pygame.KEYDOWN:if event.key == pygame.K_DOWN:game.move_down()elif event.key == pygame.K_LEFT:game.move_left()elif event.key == pygame.K_RIGHT:game.move_right()elif event.key == pygame.K_UP:game.rotate()# 移动下移移到事件处理外部game.move_down()screen.fill(BLACK)game.draw_grid(screen)game.draw_current_shape(screen)game.draw_score(screen)pygame.display.flip()clock.tick(FPS)while True:for event in pygame.event.get():if event.type == pygame.QUIT:pygame.quit()returnif __name__ == "__main__":main()
运行效果:
俄罗斯方块
失败截图:
核心代码解释:
def freeze(self):for y, row in enumerate(self.current_shape):for x, cell in enumerate(row):if cell:self.grid[self.current_y + y][self.current_x + x] = self.current_color
这段代码位于 TetrisGame
类中的 freeze
方法中,其作用是将当前正在下落的方块 "冻结" 到游戏区域中。具体来说,它将方块的颜色信息赋值给游戏区域中对应位置的格子,从而将方块的形状固定在游戏区域中。
-
for y, row in enumerate(self.current_shape):
使用enumerate
函数遍历当前正在下落的方块的每一行,其中y
是行索引,row
是行的内容。 -
for x, cell in enumerate(row):
在每一行中,再次使用enumerate
函数遍历该行的每个单元格,其中x
是列索引,cell
是单元格的值。 -
if cell:
检查当前单元格是否包含方块的一部分,即是否为非零值。如果是,表示这个单元格是方块的一部分。 -
self.grid[self.current_y + y][self.current_x + x] = self.current_color
将当前方块的颜色信息self.current_color
赋值给游戏区域中对应位置的格子。self.current_y + y
表示方块在游戏区域中的纵坐标,self.current_x + x
表示方块在游戏区域中的横坐标。self.current_x
表示当前方块左上角单元格在游戏区域中的横坐标,x是当前正在遍历的方块的一行中的相对横坐标。通过相加,可以得到方块中每个单元格在游戏区域中的绝对坐标。y也是类似。
可以改进的地方:
- 方块可以更加立体,界面可以更加美化
- 方块控制可以支持长按
- 增加音乐
- 其它