pygame俄罗斯方块游戏

俄罗斯方块游戏开发

俄罗斯方块是一款世界级经典游戏,每门语言开发学习初步都会考虑制作俄罗斯方块游戏今天带着大家把俄罗斯方块用python语言开发一次

开发准备

1.安装python
2.引入游戏库pygame
3.引入随机数

import pygame
import random

俄罗斯游戏步骤

俄罗斯方块初始形状

这里使用一个二维数组 用来标记俄罗斯相对应的方块形状 代码如下:

# 定义方块的基本形状
blocks = [
    # I
    [
        [1, 1, 1, 1],
        [0, 0, 0, 0],
        [0, 0, 0, 0],
        [0, 0, 0, 0],
    ],

    # O
    [
        [1, 1, 0, 0],
        [1, 1, 0, 0],
        [0, 0, 0, 0],
        [0, 0, 0, 0],
    ],

    # T
    [
        [1, 1, 1, 0],
        [0, 1, 0, 0],
        [0, 0, 0, 0],
        [0, 0, 0, 0],
    ],

    # S
    [
        [0, 1, 1, 0],
        [1, 1, 0, 0],
        [0, 0, 0, 0],
        [0, 0, 0, 0],
    ],

    # Z
    [
        [1, 1, 0, 0],
        [0, 1, 1, 0],
        [0, 0, 0, 0],
        [0, 0, 0, 0],
    ],

    # J
    [
        [1, 1, 1, 0],
        [0, 0, 1, 0],
        [0, 0, 0, 0],
        [0, 0, 0, 0],
    ],

    # L
    [
        [1, 1, 1, 0],
        [1, 0, 0, 0],
        [0, 0, 0, 0],
        [0, 0, 0, 0],
    ],
]

游戏移动方向是否可能判断

这里为了不让他出现穿墙,跨过方块下落 都做对应的碰撞判断 具体代码如下:

# 判断方块是否可以向左移动
def can_move_left(x, y, block):
    for i in range(len(block)):
        for j in range(len(block[i])):
            if block[i][j] == 1:
                if x + j - 1 < 0 or play_area[y + i][x + j - 1] != EMPTY:
                    return False
    return True


# 判断方块是否可以向右移动
def can_move_right(x, y, block):
    for i in range(len(block)):
        for j in range(len(block[i])):
            if block[i][j] == 1:
                if x + j + 1 >= COLS or play_area[y + i][x + j + 1] != EMPTY:
                    return False
    return True


# 判断方块是否可以向下移动
def can_move_down(x, y, block):
    for i in range(len(block)):
        for j in range(len(block[i])):
            if block[i][j] == 1:
                if y + i + 1 >= ROWS or play_area[y + i + 1][x + j] != EMPTY:
                    global count
                    count += 1
                    print(y,",",x,";不能下降了",count)
                    return False
    return True


# 判断方块是否可以变形
def can_rotate(x, y, block):
    return rotate_block(x, y, block) != block

俄罗斯方块旋转变形代码实现

# 变形方块
def rotate_block(x, y, block):
    new_block = []

    for i in range(len(block)):
        row = []
        for j in range(len(block[i])):
            row.append(block[len(block) - j - 1][i])
        new_block.append(row)

    if x + len(new_block[0]) > COLS or y + len(new_block) > ROWS:
        return block

    for i in range(len(new_block)):
        for j in range(len(new_block[i])):
            if new_block[i][j] == 1 and play_area[y + i][x + j] != EMPTY:
                return block

    return new_block

俄罗斯方块整行满格删除对应行

# 删除行
def delete_rows():
    full_rows = []  # 总共要删除的行号列表
    for i in range(len(play_area)):  # 检测整行没有空格了
        if EMPTY not in play_area[i]:
            full_rows.append(i)   # 加入删除这行
    # 偏移量bu 在一次性删除多行的时候 因为边删边补 会引起删除索引改变
    bu = 0
    for row in sorted(full_rows, reverse=True):  # 必须逆序 删除没有空格的行
        del play_area[row+bu]
        play_area.insert(0, [EMPTY] * COLS)
        bu += 1
    return len(full_rows)  # 返回删除的总行数

删除行后 根据一次删除的行计算得分规则

一次一行得10分 一次2行得30分 一次3行得50分 一次四行得100分,代码如下:

# 消除几行加分规则
def add_score(drow):
    global score
    if drow == 1:
        score += 10  # 一次消除一行 得分加10
    elif drow == 2:  # 一次消除2行 得分加30
        score += 30
    elif drow == 3:
        score += 50
    elif drow == 4:
        score += 100

检测游戏失败后 是否重新继续

# 游戏结束,重置游戏
def reset_game():
    global score
    # 绘制提示语言
    font = pygame.font.Font("simsun.ttc", 24)
    # font = pygame.font.SysFont(None, 24)
    text = font.render("游戏结束您的得分是{},重新开始请按空格键".format(score), True, WHITE)
    screen.blit(text, (10, height//2-12))
    pygame.display.update()
    flag = True
    while flag:
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                flag = False
                break

    global play_area, cur_block, cur_color
    play_area = [[EMPTY] * COLS for i in range(ROWS)]
    # play_area = [[EMPTY] * width for i in range(height)]
    # 随机生成俄罗斯方块
    cur_block = blocks[random.randint(0, len(blocks) - 1)]
    cur_color = random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
    # 重置分数
    score = 0

游戏窗体创建与游戏初始数据设置

# 颜色定义
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)

# 初始化游戏
pygame.init()

# 设置游戏界面大小
size = width, height = 640, 480
# 游戏设置
EMPTY = -1
FPS = 60   ## 祯数
SIZE = 20
ROWS = height//SIZE
COLS = width//SIZE
count = 0
# 创建游戏界面
screen = pygame.display.set_mode(size)

# 设置游戏标题
pygame.display.set_caption("俄罗斯方块")

# 随机生成俄罗斯方块
cur_block = blocks[random.randint(0, len(blocks) - 1)]
cur_color = random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
play_area = [[EMPTY] * COLS for i in range(ROWS)]
x, y = width // 2//SIZE, 0  # 方块的初始位置
clock = pygame.time.Clock()
score = 0  # 分数 
speed = 1000 #下降速度 目前没用到 后续会根据这个值来调整关卡速度(方块下落速度)
# 设置定时器来控制下降速度  如果用帧数控制游戏速度的话 会影响按键 帧数低的时候 按键也失灵 这里用定时器来控制速度
pygame.time.set_timer(pygame.USEREVENT ,speed)

主体控制代码:

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
        elif event.type == pygame.USEREVENT:
            y += 1  # 一秒下降一格
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT and can_move_left(x, y, cur_block):
                x -= 1

            elif event.key == pygame.K_RIGHT and can_move_right(x, y, cur_block):
                x += 1
            elif event.key == pygame.K_UP and can_rotate(x, y, cur_block):
                cur_block = rotate_block(x, y, cur_block)
            elif event.key == pygame.K_DOWN and can_move_down(x, y+3, cur_block):
                y += 3

    # print(x,",",y)
    # 消除行并计分
    add_score(delete_rows())

    # 随机生成新方块
    if not can_move_down(x, y, cur_block):
        # 将方块添加到游戏区域
        for i in range(len(cur_block)):
            for j in range(len(cur_block[i])):
                if cur_block[i][j] == 1:
                    print("y=",y,";x=",x,";i=",i,";j=",j)
                    play_area[y + i][x + j] = cur_color

        # 随机生成俄罗斯方块
        cur_block = blocks[random.randint(0, len(blocks) - 1)]
        cur_color = random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)

        x, y = width // 2//SIZE, 0  # 方块的初始位置

        # 判断游戏是否结束
        for i in play_area[0]:
            if i != EMPTY:
                reset_game()

    # 绘制游戏区域
    screen.fill(BLACK)
    # print(play_area)
    for i in range(ROWS):
        for j in range(COLS):
            if play_area[i][j] != EMPTY:
                pygame.draw.rect(screen, play_area[i][j], pygame.Rect(j * 20, i * 20, 20, 20), 0)

    # 绘制当前方块
    for i in range(len(cur_block)):
        for j in range(len(cur_block[i])):
            if cur_block[i][j] == 1:
                pygame.draw.rect(screen, cur_color, pygame.Rect((x + j) * 20, (y + i) * 20, 20, 20), 0)

    # 绘制分数
    font = pygame.font.SysFont(None, 24)
    text = font.render("Score: {}".format(score), True, WHITE)
    screen.blit(text, (10, 10))

    pygame.display.update()
    clock.tick(FPS)

开发总结

整个项目下载链接: pygame-俄罗斯方块游戏项目
1.游戏细节比较多,容易出错,需要清晰的逻辑思维,
2.速度控制上原先一直用FPS(帧数)来调节速度发现 按键灵敏度也跟帧数息息相关,所以这里用定时器来控制。不知道如果有多个定时器同时使用的话 会不会有新的问题,后续继续研究
3.消除行判断 原先没考虑到整个屏幕用二维列表来定义是否占格,浪费了很长时间无法很好的实现消除整行,这里用二维可以完美解决这个问题。
4.要显示中文字体需要加载字体,后面我会放整个项目下载链接,里面包括字体,后续持续更新 可能会加上音效等。
5.整个游戏花费了我5,6个小时的精力,还有很多心得 得大家一起去写写用用改改才能发现。有什么问题可以互相交流

游戏截图

俄罗斯方块游戏截图

  • 26
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
下面是一个使用 Pygame 实现的俄罗斯方块游戏的代码,其中包括了使用 Tkinter 按钮指令控制游戏的函数封装。 ```python import pygame import random import tkinter as tk # 游戏区域大小 SCREEN_WIDTH = 400 SCREEN_HEIGHT = 600 BLOCK_SIZE = 20 # 方块种类及其形状 TETROMINOS = { 'I': [(0, -1), (0, 0), (0, 1), (0, 2)], 'J': [(0, -1), (0, 0), (0, 1), (1, 1)], 'L': [(0, -1), (0, 0), (0, 1), (1, -1)], 'O': [(0, 0), (0, 1), (1, 0), (1, 1)], 'S': [(0, 0), (0, 1), (1, -1), (1, 0)], 'T': [(0, -1), (0, 0), (0, 1), (1, 0)], 'Z': [(0, -1), (0, 0), (1, 0), (1, 1)] } class Tetromino: def __init__(self, shape, x, y): self.shape = shape self.x = x self.y = y def move(self, dx, dy): self.x += dx self.y += dy def rotate(self): if self.shape == 'O': return cx, cy = self.x, self.y for i in range(4): x, y = self.shape[i] self.shape[i] = (-y, x) if self.collide(): self.x, self.y = cx, cy for i in range(4): x, y = self.shape[i] self.shape[i] = (y, -x) def get_blocks(self): return [(self.x + x, self.y + y) for x, y in self.shape] def collide(self): for x, y in self.get_blocks(): if x < 0 or x >= SCREEN_WIDTH // BLOCK_SIZE or y >= SCREEN_HEIGHT // BLOCK_SIZE or grid[x][y]: return True return False def draw(self, screen): for x, y in self.get_blocks(): pygame.draw.rect(screen, COLORS[self.shape], (x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE)) # 颜色 COLORS = { 'I': (0, 255, 255), 'J': (0, 0, 255), 'L': (255, 165, 0), 'O': (255, 255, 0), 'S': (0, 255, 0), 'T': (128, 0, 128), 'Z': (255, 0, 0) } # 初始化 Pygame pygame.init() # 创建游戏窗口 screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption('Tetris') # 创建时钟对象 clock = pygame.time.Clock() # 创建 Tkinter 窗口 root = tk.Tk() root.title('Tetris Controller') # 创建按钮 left_button = tk.Button(root, text='Left', command=lambda: move_tetromino(-1, 0)) left_button.pack(side=tk.LEFT, padx=10, pady=10) right_button = tk.Button(root, text='Right', command=lambda: move_tetromino(1, 0)) right_button.pack(side=tk.LEFT, padx=10, pady=10) down_button = tk.Button(root, text='Down', command=lambda: move_tetromino(0, 1)) down_button.pack(side=tk.LEFT, padx=10, pady=10) rotate_button = tk.Button(root, text='Rotate', command=rotate_tetromino) rotate_button.pack(side=tk.LEFT, padx=10, pady=10) # 创建游戏区域的网格 grid = [[None] * (SCREEN_HEIGHT // BLOCK_SIZE) for _ in range(SCREEN_WIDTH // BLOCK_SIZE)] # 创建当前方块和下一个方块 current_tetromino = Tetromino(random.choice(list(TETROMINOS.keys())), SCREEN_WIDTH // BLOCK_SIZE // 2, 0) next_tetromino = Tetromino(random.choice(list(TETROMINOS.keys())), SCREEN_WIDTH // BLOCK_SIZE // 2, 0) # 定义移动和旋转函数 def move_tetromino(dx, dy): current_tetromino.move(dx, dy) if current_tetromino.collide(): current_tetromino.move(-dx, -dy) def rotate_tetromino(): current_tetromino.rotate() if current_tetromino.collide(): current_tetromino.rotate() # 游戏循环 while True: # 处理事件 for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() root.destroy() exit() # 绘制背景 screen.fill((0, 0, 0)) # 绘制当前方块和下一个方块 current_tetromino.draw(screen) next_tetromino.draw(screen) # 绘制网格 for x in range(SCREEN_WIDTH // BLOCK_SIZE): for y in range(SCREEN_HEIGHT // BLOCK_SIZE): if grid[x][y]: pygame.draw.rect(screen, COLORS[grid[x][y]], (x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE), 1) # 处理当前方块的下落 if pygame.time.get_ticks() % 500 == 0: current_tetromino.move(0, 1) if current_tetromino.collide(): current_tetromino.move(0, -1) for x, y in current_tetromino.get_blocks(): grid[x][y] = current_tetromino.shape current_tetromino = next_tetromino next_tetromino = Tetromino(random.choice(list(TETROMINOS.keys())), SCREEN_WIDTH // BLOCK_SIZE // 2, 0) if current_tetromino.collide(): pygame.quit() root.destroy() exit() # 更新 Pygame 窗口 pygame.display.update() # 更新 Tkinter 窗口 root.update() # 控制游戏帧率 clock.tick(60) ``` 在上述代码中,我们首先创建了一个 Tkinter 窗口,并添加了四个按钮。这些按钮分别用于向左、向右、向下移动方块以及旋转方块。按钮的回调函数分别为 `move_tetromino(dx, dy)` 和 `rotate_tetromino()`,它们分别用于移动和旋转当前方块。 在游戏循环中,我们每隔一定时间就让当前方块向下移动一格。如果当前方块与已经落下的方块碰撞,则将当前方块的位置恢复到移动前的位置,并将当前方块的形状添加到网格中。然后,我们创建一个新的方块作为当前方块,并在屏幕上绘制它。如果新的方块无法落下,则游戏结束。 值得注意的是,在游戏循环中还包括了更新 Pygame 窗口和 Tkinter 窗口的代码,以及控制游戏帧率的代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宇龙神

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值