一、环境准备
1. 安装Python 3
Ubuntu系统通常预装了Python。如果没有,可以通过以下命令安装:
sudo apt-get update sudo apt-get install python3 python3-pip
2. 安装Pygame库
Pygame是Python的一个跨平台的游戏开发库,适合用于开发2D游戏。
使用pip安装Pygame:
pip3 install pygame
验证安装是否成功:
python3 -c "import pygame; print(pygame.ver)"
如果没有报错,且打印出版本信息,说明Pygame安装成功。
二、创建项目
1. 创建项目目录
在主目录下创建一个名为tetris_game
的项目文件夹:
mkdir ~/tetris_game cd ~/tetris_game
2. 创建Python脚本文件
创建主程序文件:
touch tetris.py
3. 打开Python脚本文件
gedit tetris.py
三、编写代码
在tetris.py
中,粘贴Python代码:
import pygame
import sys
import random
# 初始化Pygame
pygame.init()
# 设置窗口大小
screen_width = 400
screen_height = 500
# 创建游戏窗口
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('俄罗斯方块')
# 设置时钟
clock = pygame.time.Clock()
# 定义游戏网格大小
grid_width = 10
grid_height = 20
block_size = 20
# 定义颜色
colors = [
(0, 0, 0), # 黑色
(255, 0, 0), # 红色
(0, 255, 0), # 绿色
(0, 0, 255), # 蓝色
(255, 255, 0), # 黄色
(255, 165, 0), # 橙色
(128, 0, 128), # 紫色
(0, 255, 255) # 青色
]
# 创建游戏网格
grid = [[0 for x in range(grid_width)] for y in range(grid_height)]
# 形状定义
shapes = [
[['.....',
'.....',
'..00.',
'.00..',
'.....'],
['.....',
'..0..',
'..00.',
'...0.',
'.....']],
[['.....',
'.....',
'.00..',
'..00.',
'.....'],
['.....',
'..0..',
'.00..',
'.0...',
'.....']],
[['..0..',
'..0..',
'..0..',
'..0..',
'.....'],
['.....',
'0000.',
'.....',
'.....',
'.....']],
[['.....',
'.....',
'.00..',
'.00..',
'.....']],
[['.....',
'..0..',
'.000.',
'.....',
'.....'],
['.....',
'..0..',
'..00.',
'..0..',
'.....'],
['.....',
'.....',
'.000.',
'..0..',
'.....'],
['.....',
'..0..',
'.00..',
'..0..',
'.....']],
[['.....',
'.0...',
'.000.',
'.....',
'.....'],
['.....',
'..00.',
'..0..',
'..0..',
'.....'],
['.....',
'.....',
'.000.',
'...0.',
'.....'],
['.....',
'..0..',
'..0..',
'.00..',
'.....']],
[['.....',
'...0.',
'.000.',
'.....',
'.....'],
['.....',
'..0..',
'..0..',
'..00.',
'.....'],
['.....',
'.....',
'.000.',
'.0...',
'.....'],
['.....',
'.00..',
'..0..',
'..0..',
'.....']]
]
# 形状对应的颜色(从1开始,0为黑色)
shape_colors = [1, 2, 3, 4, 5, 6, 7]
# 分数
score = 0
class Piece(object):
def __init__(self, x, y, shape):
self.x = x # x位置(网格坐标)
self.y = y # y位置(网格坐标)
self.shape = shape
self.color = random.choice(shape_colors)
self.rotation = 0 # 当前旋转状态
def create_grid(locked_positions={}):
grid = [[0 for _ in range(grid_width)] for _ in range(grid_height)]
for y in range(grid_height):
for x in range(grid_width):
if (x, y) in locked_positions:
c = locked_positions[(x, y)]
grid[y][x] = c
return grid
def convert_shape_format(shape):
positions = []
format = shape.shape[shape.rotation % len(shape.shape)]
for i, line in enumerate(format):
row = list(line)
for j, column in enumerate(row):
if column == '0':
positions.append((shape.x + j - 2, shape.y + i - 4))
return positions
def valid_space(shape, grid):
accepted_positions = [[(x, y) for x in range(grid_width) if grid[y][x] == 0] for y in range(grid_height)]
accepted_positions = [x for sub in accepted_positions for x in sub]
formatted = convert_shape_format(shape)
for pos in formatted:
if pos not in accepted_positions:
if pos[1] > -1:
return False
return True
def check_lost(positions):
for pos in positions:
x, y = pos
if y < 1:
return True
return False
def get_shape():
return Piece(5, 0, random.choice(shapes))
def draw_text_middle(text, size, color, surface):
font = pygame.font.SysFont('comicsans', size)
label = font.render(text, 1, color)
surface.blit(label, (screen_width / 2 - label.get_width() / 2, screen_height / 2 - label.get_height() / 2))
def draw_grid(surface):
for y in range(grid_height):
pygame.draw.line(surface, (128, 128, 128), (0, y*block_size), (grid_width*block_size, y*block_size))
for x in range(grid_width):
pygame.draw.line(surface, (128, 128, 128), (x*block_size, 0), (x*block_size, grid_height*block_size))
def clear_rows(grid, locked):
global score
inc = 0
for i in range(len(grid)-1, -1, -1):
row = grid[i]
if 0 not in row:
inc += 1
ind = i
for j in range(len(row)):
try:
del locked[(j, i)]
except:
continue
if inc > 0:
score += inc * 10 # 每消除一行加10分
for key in sorted(list(locked), key=lambda x: x[1])[::-1]:
x, y = key
if y < ind:
newKey = (x, y + inc)
locked[newKey] = locked.pop(key)
def draw_next_shape(shape, surface):
font = pygame.font.SysFont('comicsans', 30)
label = font.render('下一个方块:', 1, (255, 255, 255))
start_x = screen_width - 150
start_y = 50
format = shape.shape[shape.rotation % len(shape.shape)]
for i, line in enumerate(format):
row = list(line)
for j, column in enumerate(row):
if column == '0':
pygame.draw.rect(surface, colors[shape.color], (start_x + j*block_size, start_y + i*block_size, block_size, block_size), 0)
surface.blit(label, (start_x, start_y - 30))
def draw_window(surface, grid, score=0, next_piece=None):
surface.fill((0, 0, 0)) # 清空屏幕
# 绘制当前得分
font = pygame.font.SysFont('comicsans', 30)
label = font.render('得分: ' + str(score), 1, (255, 255, 255))
surface.blit(label, (screen_width - label.get_width() - 10, 10))
for y in range(grid_height):
for x in range(grid_width):
pygame.draw.rect(surface, colors[grid[y][x]], (x*block_size, y*block_size, block_size, block_size), 0)
# 绘制网格线
draw_grid(surface)
# 绘制下一个方块
if next_piece:
draw_next_shape(next_piece, surface)
def main():
global grid, score
locked_positions = {}
grid = create_grid(locked_positions)
change_piece = False
run = True
current_piece = get_shape()
next_piece = get_shape()
fall_time = 0
while run:
fall_speed = 0.27
grid = create_grid(locked_positions)
fall_time += clock.get_rawtime()
clock.tick()
# 让方块下降
if fall_time / 1000 > fall_speed:
fall_time = 0
current_piece.y += 1
if not(valid_space(current_piece, grid)) and current_piece.y > 0:
current_piece.y -= 1
change_piece = True
# 处理事件
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.display.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
current_piece.x -= 1
if not valid_space(current_piece, grid):
current_piece.x += 1
elif event.key == pygame.K_RIGHT:
current_piece.x += 1
if not valid_space(current_piece, grid):
current_piece.x -= 1
elif event.key == pygame.K_DOWN:
current_piece.y += 1
if not valid_space(current_piece, grid):
current_piece.y -= 1
elif event.key == pygame.K_UP:
current_piece.rotation = (current_piece.rotation + 1) % len(current_piece.shape)
if not valid_space(current_piece, grid):
current_piece.rotation = (current_piece.rotation - 1) % len(current_piece.shape)
shape_pos = convert_shape_format(current_piece)
# 将方块添加到网格
for pos in shape_pos:
x, y = pos
if y > -1:
grid[y][x] = current_piece.color
# 如果方块落地,生成新方块
if change_piece:
for pos in shape_pos:
locked_positions[(pos[0], pos[1])] = current_piece.color
current_piece = next_piece
next_piece = get_shape()
change_piece = False
clear_rows(grid, locked_positions)
if check_lost(locked_positions):
run = False
draw_window(screen, grid, score, next_piece)
pygame.display.update()
# 游戏结束画面
screen.fill((0, 0, 0))
font = pygame.font.SysFont('comicsans', 60)
label = font.render('游戏结束', 1, (255, 255, 255))
score_label = font.render('得分: ' + str(score), 1, (255, 255, 255))
screen.blit(label, (screen_width / 2 - label.get_width() / 2, screen_height / 2 - label.get_height()))
screen.blit(score_label, (screen_width / 2 - score_label.get_width() / 2, screen_height / 2))
pygame.display.update()
pygame.time.delay(3000)
pygame.quit()
sys.exit()
if __name__ == '__main__':
main()
四、运行游戏
保存tetris.py
文件,然后在终端中运行:
python3 tetris.py
可以看到一个游戏窗口,方块会自动下落,您可以使用键盘方向键进行控制:
- 左键:向左移动方块
- 右键:向右移动方块
- 下键:加速方块下落
- 上键:旋转方块
当方块堆积到顶部时,游戏会结束,并显示最终得分。