三、生成随机方块,Python基于thinker实现的简单的俄罗斯方块小游戏

生成

**功能:**每次运行都随机生成一个方块

思路分析:

基本逻辑:随机生成一个方块对象 >> 绘制方块对象 >> 移动方块对象

第一步:随机生成方块对象

首先我们需要删除原来的位于game_loop方法上面的a_block = … 和*draw_block_move(canvas, a_block)*这2行代码(这两行代码俄罗斯方块是在固定位置,按照指定形状生成的,需要删掉这部分代码)

然后再在原来的这2行代码所在位置,添加一个随机生成俄罗斯方块的方法generate_new_block

def generate_new_block():
    # 随机生成新的俄罗斯方块

    kind = random.choice(list(SHAPES.keys()))
    # 对应横纵坐标,以左上角为原点,水平向右为x轴正方向,
    # 竖直向下为y轴正方向,x对应横坐标,y对应纵坐标
    cr = [C // 2, 0]
    new_block = {
        'kind': kind,  # 对应俄罗斯方块的类型
        'cell_list': SHAPES[kind],
        'cr': cr
    }

    return new_block

第二步:修改游戏运行方法

再将游戏运行方法game_loop修改成如下:

其中,将当前的俄罗斯方块对象通过全局变量来存储,

并在game_loop方法下面设置初始的俄罗斯方块为空(None)

此时每次运行代码都会发现生成了随机的俄罗斯方块

def game_loop():
    win.update()
    global current_block
    if current_block is None:
        new_block = generate_new_block()
        # 新生成的俄罗斯方块需要先在生成位置绘制出来
        draw_block_move(canvas, new_block)
        current_block = new_block
    else:
        draw_block_move(canvas, current_block, [0, 1])

    win.after(FPS, game_loop)

current_block = None

运行结果如下:

image-20230208171120035

当然,此时还有问题没有解决,就是俄罗斯方块生成后,会一直往下移动,就算出了可视范围还是会往下移动(只是这时再也看不到了)。

所以接下来我们要实现的是:当俄罗斯方块落地的时候,将它固定住,然后再去生成新的

固定

**功能:**落到底部的方块固定住不动

思路分析:

判断俄罗斯方块落地的原则是,该方块是否可以继续向下移动

这里我们首先需要的是一个方法check_move需要判断俄罗斯方块是否可以向指定位置移动

def check_move(block, direction=[0, 0]):
    """
        判断俄罗斯方块是否可以朝制定方向移动
        :param block: 俄罗斯方块对象
        :param direction: 俄罗斯方块移动方向
        :return: boolean 是否可以朝制定方向移动
        """
    cc, cr = block['cr']
    cell_list = block['cell_list']

    for cell in cell_list:
        cell_c, cell_r = cell
        c = cell_c + cc + direction[0]
        r = cell_r + cr + direction[1]
        # 判断该位置是否超出左右边界,以及下边界
        # 一般不判断上边界,因为俄罗斯方块生成的时候,可能有一部分在上边界之上还没有出来
        if c < 0 or c >= C or r >= R:
            return False
    return True

再将游戏运行方法game_loop修改成如下,便可以每次俄罗斯方块落地后都会生成新的

def game_loop():
    win.update()
    global current_block

    if current_block is None:
        new_block = generate_new_block()
        # 新生成的俄罗斯方块需要先在生成位置绘制出来
        draw_block_move(canvas, new_block)
        current_block = new_block
    else:
        if check_move(current_block, [0, 1]):
            draw_block_move(canvas, current_block, [0, 1])
        else:
            current_block = None

    win.after(FPS, game_loop)

运行结果如下:

图片

此时仍然有个问题:就是老的俄罗斯方块会被新的落地的俄罗斯方块覆盖,这个需要处理

思路分析:

当俄罗斯方块发现下面有已固定的俄罗斯方块时,也不能移动

当俄罗斯方块发现下面有已固定的俄罗斯方块时,也不能移动首先

解决方案:

第一步:记录固定的方块

我们需要添加一个变量block_list来记录已固定的俄罗斯方块

在原代码draw_blank_board(canvas)的位置的下面,添加如下代码

block_list = []
for i in range(R):
    i_row = ['' for j in range(C)]
    block_list.append(i_row)

然后再在固定俄罗斯方块的时候记录进去,所以

  • 一要添加一个save_block_to_list方法,将无法移动的俄罗斯方块记录进去
  • 二要修改game_loop
def save_block_to_list(block):
    shape_type = block['kind']
    cc, cr = block['cr']
    cell_list = block['cell_list']

    for cell in cell_list:
        cell_c, cell_r = cell
        c = cell_c + cc
        r = cell_r + cr
        # block_list 在对应位置记下其类型
        block_list[r][c] = shape_type

def game_loop():
    win.update()
    global current_block
    if current_block is None:
        new_block = generate_new_block()
        # 新生成的俄罗斯方块需要先在生成位置绘制出来
        draw_block_move(canvas, new_block)
        current_block = new_block
    else:
        if check_move(current_block, [0, 1]):
            draw_block_move(canvas, current_block, [0, 1])
        else:
            # 无法移动,记入 block_list 中
            save_block_to_list(current_block)
            current_block = None

    win.after(FPS, game_loop)

第二步:修改check_move方法

然后还要再修改原来的check_move方法,就是发现下面有已固定的俄罗斯方块时,也不能移动,具体如下

def check_move(block, direction=[0, 0]):
    """
        判断俄罗斯方块是否可以朝制定方向移动
        :param block: 俄罗斯方块对象
        :param direction: 俄罗斯方块移动方向
        :return: boolean 是否可以朝制定方向移动
        """
    cc, cr = block['cr']
    cell_list = block['cell_list']

    for cell in cell_list:
        cell_c, cell_r = cell
        c = cell_c + cc + direction[0]
        r = cell_r + cr + direction[1]
        # 判断该位置是否超出左右边界,以及下边界
        # 一般不判断上边界,因为俄罗斯方块生成的时候,可能有一部分在上边界之上还没有出来
        if c < 0 or c >= C or r >= R:
            return False

        # 必须要判断r不小于0才行,具体原因你可以不加这个判断,试试会出现什么效果
        if r >= 0 and block_list[r][c]:
            return False

    return True

运行结果如下:

图片

左右移动

**功能:**左右移动方块

思路分析:

我们需要新建一个左右移动俄罗斯方块的方法horizontal_move_block,其中的参数event对应键鼠事件

在save_block_to_list方法下面添加horizontal_move_block方法的代码如下:

第一步:左右移动方块

def horizontal_move_block(event):
    """
    左右水平移动俄罗斯方块
    """
    direction = [0, 0]
    if event.keysym == 'Left':
        direction = [-1, 0]
    elif event.keysym == 'Right':
        direction = [1, 0]
    else:
        return

    global current_block
    if current_block is not None and check_move(current_block, direction):
        draw_block_move(canvas, current_block, direction)

第二步:绑定键盘

canvas.focus_set() # 聚焦到canvas画板对象上
canvas.bind("<KeyPress-Left>", horizontal_move_block)
canvas.bind("<KeyPress-Right>", horizontal_move_block)

现在可以左右移动方块了

旋转

**功能:**按下键盘⬆️表示顺时针旋转90度;按下键盘⬇️表示方块加速到底

思路分析:

第一步:添加旋转方法

def rotate_block(event):
    """
    该函数用于实现方块旋转,当current_block有值时,遍历其cell_list,将每个cell顺时针旋转90度,放入rotate_list中,新生成旋转后的block,并判断是否超出边界,如果不超出边界,把新block覆盖原来的block。
    """
    global current_block
    if current_block is None:
        return

    cell_list = current_block['cell_list']
    rotate_list = []
    for cell in cell_list:
        cell_c, cell_r = cell
        rotate_cell = [cell_r, -cell_c]
        rotate_list.append(rotate_cell)

    block_after_rotate = {
        'kind': current_block['kind'],  # 对应俄罗斯方块的类型
        'cell_list': rotate_list,
        'cr': current_block['cr']
    }

    if check_move(block_after_rotate):
        cc, cr= current_block['cr']
        draw_cells(canvas, cc, cr, current_block['cell_list'])
        draw_cells(canvas, cc, cr, rotate_list,SHAPESCOLOR[current_block['kind']])
        current_block = block_after_rotate

第二步:添加加速到底方法

def land(event):
    """
    该函数的功能是让当前正在运行的方块移动到最低的可能高度。它遍历当前块所有单元格的位置,然后找出方块单元格距离下面块的最小高度,并将其保存到min_height中,最后调用check_move函数以及draw_block_move函数来处理并将方块移动到最低的可能高度。
    """
    global current_block
    if current_block is None:
        return

    cell_list = current_block['cell_list']
    cc, cr = current_block['cr']
    min_height = R
    for cell in cell_list:
        cell_c, cell_r = cell
        c, r = cell_c + cc, cell_r + cr
        if r>=0 and block_list[r][c]:
            return
        h = 0
        for ri in range(r+1, R):
            if block_list[ri][c]:
                break
            else:
                h += 1
        if h < min_height:
            min_height = h

    down = [0, min_height]
    if check_move(current_block, down):
        draw_block_move(canvas, current_block, down)

第三步:绑定键盘

canvas.bind("<KeyPress-Up>", rotate_block)
canvas.bind("<KeyPress-Down>", land)

运行结果如下:

image-20230208232322856

完整代码下载地址:Python基于thinker实现的简单的俄罗斯方块小游戏源代码

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

程序员柳

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

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

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

打赏作者

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

抵扣说明:

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

余额充值