You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pygame开发俄罗斯方块生存模式多事件修改字典触发KeyError求解

问题根源

你遇到的KeyError本质是**grid网格数据与locked字典数据不同步**+主逻辑执行时序交叉共同导致的:

  • 你的消行逻辑用grid的行数据判断是否要消除,但grid并没有在survival_add_line修改locked后实时更新,行号对应关系已经错位
  • 当前主循环先执行时间触发的新增行逻辑,再处理玩家的方块锁定消行逻辑,刚好会出现「新增行改了locked、但grid还是旧的」的时间窗口,导致消行时尝试删除已经被上移不存在的坐标键
解决方案

1. 优先调整主循环执行顺序(根治成本最低)

Pygame是单线程主循环模型,不需要复杂的多线程锁,只要把两个修改locked的逻辑执行顺序固定,先处理所有玩家输入相关的逻辑,再处理时间触发的自动新增行逻辑,从根源上避免时序交叉:

# 调整后主循环顺序
if change_piece:
    for pos in tetrimino_position:
        locked[(pos[0], pos[1])] = current_piece.color      
    current_piece = next_pieces[0]
    next_pieces.pop(0)
    next_pieces.append(new_tetromino())
    change_piece = False
    cleared_lines += clear_rows(grid, locked)
# 玩家逻辑全部处理完再处理自动加行
if level_time / 1000 >= 1:
    survival_add_line(locked)
    level_time = 0

2. 消除两个数据源的不一致问题

消行判断逻辑不要用可能滞后的grid数据,直接从locked字典读取数据判断行是否填满,从根源上避免行号错位:

def clear_rows(grid, locked):
    rows_cleared = 0
    # 从最底部行开始遍历
    for i in range(19, -1, -1):
        # 直接从locked判断当前行是否填满
        is_full = all((j, i) in locked for j in range(10))
        if is_full:
            i_new = i + rows_cleared
            # 删之前先判断键存在,兜底避免报错
            for j in range(10):
                if (j, i_new) in locked:
                    del locked[(j, i_new)]
            rows_cleared += 1
            # 更新上方方块坐标
            for key in sorted(list(locked), key=lambda x: x[1])[::-1]:
                x_coord, y_coord = key
                if y_coord < i_new:
                    new_key = (x_coord, y_coord + 1)
                    locked[new_key] = locked.pop(key)
    return rows_cleared

3. 兜底兼容方案

如果不想改动现有逻辑结构,可直接在del操作前加存在性判断,虽然属于治标方案,但可以快速解决报错问题:

for j in range(len(row)):
    # 只有键存在时才删除
    if (j, i_new) in locked:
        del locked[(j, i_new)]

内容的提问来源于stack exchange,提问作者Rabinzel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 00:36:03