俄罗斯方块游戏开发
俄罗斯方块是一款世界级经典游戏,每门语言开发学习初步都会考虑制作俄罗斯方块游戏今天带着大家把俄罗斯方块用python语言开发一次
开发准备
安装python
2.引入游戏库pygame
3.引入随机数
import pygameimport 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 = -1FPS = 60 ## 祯数SIZE = 20ROWS = height//SIZECOLS = width//SIZEcount = 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个小时的精力,还有很多心得 得大家一起去写写用用改改才能发现。有什么问题可以互相交流
游戏截图
来源地址:https://blog.csdn.net/yu126long/article/details/133691398