Python实现俄罗斯方块(带完整源码)

博主介绍: 27dCnc
专题 : python项目详细讲解
????????????????????????
☆*: .?. o(≧▽≦)o .?.:*☆

主题: 项目设计流程

今日份打卡
1.23

  • 俄罗斯方块项目分析文档

文章目录

  • 主题: 项目设计流程
    • 概要
    • 整体架构流程
      • 1.引用模块
      • 2.表示方块
      • 3.需求变量
      • 4.绘制窗口
      • 5.方块下落类
      • 6.绘制方块类
      • 7.方块旋转类
      • 8.方块移动类
      • 9.游戏循环执行
    • 技术细节
    • 小结

概要

  1. 项目准备
  2. 项目架构 (思路图)
  3. 代码分块
  4. 详细代码实现

整体架构流程

435

在这里插入图片描述
相关考虑

  1. 游戏区域的表示:使用二维数组或列表来表示游戏区域的网格。每个元素可以表示一个方块的状态,如是否被占据。

  2. 方块的表示与移动:定义不同形状的方块,并使用坐标来表示方块在游戏区域中的位置。实现方块的移动(左右移动、旋转)以及碰撞检测,确保方块在合法范围内移动。

  3. 方块的下落与固定:实现方块的自动下落和手动下落功能,以及判断方块是否需要固定在游戏区域中。

  4. 行消除:检测并消除已填满的行,更新游戏区域的状态,并计算得分。

  5. 游戏结束条件:判断游戏是否结束,例如当方块堆积到游戏区域的顶部时。

  6. 用户输入与界面交互:监听用户的键盘输入或者鼠标点击等事件,响应用户的操作,并更新游戏区域的状态。

  7. 游戏循环:使用游戏循环来控制游戏的进行,包括更新游戏状态、绘制游戏界面、处理用户输入等。

1.引用模块

引用模块

pygame是图形化页面可以用于绘制窗口和绘制方块

2.表示方块

表示方块

用相应坐标表示方块类型

3.需求变量

需求变量

  1. backgroud 用于储存方块绘制坐标
  2. gameover 用于储存下落完成的方块
  3. press 用于控制加速

4.绘制窗口

绘制窗口

pygame.init() 用于初始化
pygame.display.set_mode((400, 800)) 设置窗口大小
list(random.choice(all_block)) 下落方块 random.choice(all_block)随机在all_block方块中选择

5.方块下落类

下落类
代码解释
解释代码1

代码解释2

详细解释

首先,通过 for row, column in select_block: 遍历 select_block 列表中的每个元素,其中每个元素都是一个包含方块位置信息的列表,例如 [row, column]

然后,将 rowcolumn 分别加上变量 yx 的值。这里的 yx 可能表示方块在背景中的偏移量,用于确定方块的实际位置。

接下来,通过 if backgroud[row][column] == 1: 条件语句判断背景中对应位置的值是否为 1。如果是,说明当前方块与背景中已有的方块重叠,即发生碰撞。

如果发生碰撞,将值为 1 的元素添加到 gameover 列表中,以表示游戏结束。

综上所述,这段代码的逻辑是遍历选中的方块中的每个位置,将其与背景中对应位置的值进行比较,如果发生碰撞,则将游戏结束的标志(值为 1)添加到 gameover 列表中。

6.绘制方块类

draw_block类

pygame.draw.rect(screen, (255, 165, 0), (column * 40, 800 - row * 40, 38, 38)) 用pygame的绘制函数绘制方块大小和方块颜色
分别用俩for一个用于绘制动态block 一个用于绘制静态block

7.方块旋转类

在这里插入图片描述

用一个数组储存旋转后的方块顺便规定旋转的范围,控制方块移动范围

8.方块移动类

在这里插入图片描述

方块自动下落

9.游戏循环执行

在这里插入图片描述

键盘输入事件:

  for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_DOWN:
                press = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                rotate()  # 代码无法向下加速的原因是在处理pygame.KEYUP事件时,判断按键是否为向下键时使用了错误的语句。
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RIGHT:  # 具体来说,在代码中,当检测到键盘按键释放事件(pygame.KEYUP)时,
                    # 判断按键是否为向下键时应该使用event.key
                    # 而不是event.type。
                    move(1)  # 因此,将event.type改为event.key即可解决这个问题
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    move(-1)
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_DOWN:
                press = False

通过键盘输入事件可以让方块移动手动移动

技术细节

以下是一些在Pygame中常用的函数和模块:

  1. pygame.init():初始化Pygame库。

  2. pygame.display.set_mode():创建游戏窗口。

  3. pygame.event.get():获取所有待处理的事件。

  4. pygame.event.pump():处理所有待处理的事件。

  5. pygame.key.get_pressed():检测按键状态。

  6. pygame.draw.rect():绘制矩形。

  7. pygame.draw.polygon():绘制多边形。

  8. pygame.draw.line():绘制线段。

  9. pygame.time.Clock():控制游戏帧率。

  10. pygame.font.Font():加载字体文件。

  11. pygame.font.render():渲染文本。

  12. pygame.mixer.Sound():加载声音文件。

  13. pygame.mixer.music.load():加载音乐文件。

  14. pygame.mixer.music.play():播放音乐。

  15. pygame.image.load():加载图像文件。

  16. pygame.transform.scale():缩放图像。

这些函数和模块是Pygame库中常用的功能,可以帮助你实现俄罗斯方块游戏的各个方面,如绘制游戏界面、处理用户输入、播放音效和音乐等。你可以根据具体需求,在代码中适时调用这些函数和模块来完成相应的功能。

这些就是pygame我们要用的函数

总结

小结

代码

import pygame, sys
import random

# 物块的形状是二维数组
all_block = [
    [[0, 0], [0, 1], [0, 2], [0, 3], ],  # 一个物体4个方块组成      长方形
    [[0, 0], [0, 1], [1, 0], [1, 1], ],  # 7个列表表示7种形状      正方形
    [[0, 0], [1, 0], [0, 1], [0, 2], ],  # 7字型
    [[0, 0], [0, 1], [0, -1], [0, -2], ],  # 倒7字型
    [[0, 0], [0, 1], [1, 1], [1, 2], ],  # Z字型
    [[0, 0], [0, -1], [1, -1], [1, -2], ],  # 倒z字型
    [[0, 0], [0, 1], [0, -1], [1, 0]],  # T字型
]

backgroud = [[0 for column in range(0, 10)] for row in range(0, 23)]  # 创造列表集
backgroud[0] = [1 for colum in range(0, 10)]  # 把0层修改为[1*10]

# 设置全局变量
# select_block = list(random.choice(all_block))  # 从7个形状中随机选择一种
initial_position = [21, 5]
times = 0  # 计时
score = [0]  # 得分  系统出错

gameover = []  # 游戏结束

press = False  # 按键加速
# 初始化
pygame.init()
screen = pygame.display.set_mode((400, 800))  # 设置窗口大小
select_block = list(random.choice(all_block))


def block_down():
    global select_block  # 将global改为全局变量
    y, x = initial_position  # initial_position = [21, 5]
    y -= 1  # 表示相距的间隔
    for row, column in select_block:  # 调节方块下落的位置
        row += y
        column += x
        if backgroud[row][column]:  # 注意
            break
    else:
        initial_position.clear()  # 刷新对初始位置进行更新
        initial_position.extend([y, x])  # [x,y]定义:[一个列表集,第一个值表示1行row,第二个值表示column
        return
    y, x = initial_position
    for row, column in select_block:
        row += y  # 对当前选择的方块
        column += x
        backgroud[row][column] = 1  # 这个是是将背景网格中指定位置的值修改为1
    complete_row = []  # 用来存储静态的block就是完成一行后,将静态block存储在数组中
    # 然后通过删除数组元素达到消除方块的效果

    # 下面代码用于处理和检测背景网格中是不是有完整的行
    for row in range(1, 21):  # 通过循环遍历背景网格中的每一行
        if 0 not in backgroud[row]:  # 条件判断是否存在值为0的元素,如果不存在,则表示该行是完整的。
            complete_row.append(row)  # 如果一行是完整的将其行号row添加到complete_row中
    for row in complete_row:  # 再次循环对每一行进行遍历
        backgroud.pop(row)  # 将完整的行移除
        backgroud.append(list(0 for _ in range(0, 10)))  # 注意 移除行后在网格底部添加一个新行就是为让网格大小保持不变
    score[0] += len(complete_row)  # 计算消除行数并记录
    pygame.display.set_caption('你现在的分数是 ' + str(score[0]) + '分')  # 显示消除行数显示标题中
    # text = font.render("Score: " + str(score[0]), True, (0, 0, 0))
    initial_position.clear()  # 清空 initial_position列表中的元素
    select_block = list(random.choice(all_block))  # 随机选择一个方块
    initial_position.extend(select_block)  # 将选中的方块赋值给initial_position,initial_position里面存储着随机选择的方块
    initial_position.clear()  # 当动态的block变成静态block清楚initial_position中存储的上个方块的信息然后为重新加载方块做准备
    initial_position.extend([20, 5])  # 将[20,5]添加到initial_position中[20,5]代表下落的初始坐标
    y, x = initial_position
    for row, column in select_block:  # 用于确定方块的偏移量
        row += y
        column += x
        if backgroud[row][column] == 1:  # 判断静态block对应位置是否为1如果是说明当前方块于背景中已有方块重叠
            gameover.append(1)
            # 这段代码的逻辑是遍历选中的方块中的每个位置,将其与背景中对应位置的值进行比较,如果发生碰撞,则将游戏结束的标志(值为 1)


# TODO: 
# 详细解释
# 首先,通过 `for row, column in select_block:` 遍历 `select_block` 列表中的每个元素,其中每个元素都是一个包含方块位置信息的列表,例如 `[row, column]`。
#
# 然后,将 `row` 和 `column` 分别加上变量 `y` 和 `x` 的值。这里的 `y` 和 `x` 可能表示方块在背景中的偏移量,用于确定方块的实际位置。
#
# 接下来,通过 `if backgroud[row][column] == 1:` 条件语句判断背景中对应位置的值是否为 1。如果是,说明当前方块与背景中已有的方块重叠,即发生碰撞。
#
# 如果发生碰撞,将值为 1 的元素添加到 `gameover` 列表中,以表示游戏结束。
#
# 综上所述,这段代码的逻辑是遍历选中的方块中的每个位置,将其与背景中对应位置的值进行比较,如果发生碰撞,则将游戏结束的标志(值为 1)添加到 `gameover` 列表中。



def draw_block():
    y, x = initial_position
    for row, column in select_block:
        row += y
        column += x
        pygame.draw.rect(screen, (255, 165, 0), (column * 40, 800 - row * 40, 38, 38))
    for row in range(1, 21):
        for column in range(0, 10):
            if backgroud[row][column] == 1:
                pygame.draw.rect(screen, (0, 0, 255), (column * 40, 800 - row * 40, 38, 38))


def rotate():
    y, x = initial_position
    # select_block = list(random.choice(all_block))
    rotating_position = [(-colum, row) for row, colum in select_block]  # 计算方块旋转后的位置
    for row, colum in rotating_position:
        row += y
        colum += x
        if colum < 0 or colum > 9 or backgroud[row][colum]:
            break
    else:
        select_block.clear()
        select_block.extend(rotating_position)


def move(d):
    y, x = initial_position
    # select_block = list(random.choice(all_block))
    x += d
    for row, colum in select_block:
        row += y
        colum += x
        if colum < 0 or colum > 9 or backgroud[row][colum]:
            break
    else:
        initial_position.clear()
        initial_position.extend([y, x])


while True:
    screen.fill((255, 255, 255))
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_DOWN:
                press = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                rotate()  # 代码无法向下加速的原因是在处理pygame.KEYUP事件时,判断按键是否为向下键时使用了错误的语句。
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RIGHT:  # 具体来说,在代码中,当检测到键盘按键释放事件(pygame.KEYUP)时,
                    # 判断按键是否为向下键时应该使用event.key
                    # 而不是event.type。
                    move(1)  # 因此,将event.type改为event.key即可解决这个问题
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    move(-1)
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_DOWN:
                press = False

    if times % 60 == 0:
        block_down()
    times += 1
    if press:
        times += 10
    if gameover:
        sys.exit()
    draw_block()
    pygame.time.Clock().tick(400)
    # 创建字体对象
    font = pygame.font.Font(None, 36)
    # 创建显示文本
    text = font.render("Score: " + str(score[0]), True, (0, 0, 0))
    # 创建显示区域然后显示
    screen.blit(text, (10, 10))
    # 刷新
    pygame.display.update()

    pygame.display.flip()

# 俄罗斯方块基本类
# 方块
# 旋转
# 移动
# 物块
# 形状
# 碰撞检测
# 绘制

我创建的相关文章

提供先进的推理,复杂的指令,更多的创造力。

??如果此文对你有帮助的话,欢迎??关注、??点赞、?收藏、??评论,支持一下博主~