python 基于pygame实现俄罗斯方块


Posted in Python onMarch 02, 2021

一、简单说明

80、90后的小伙伴都玩过“俄罗斯方块”,那种“叱咤风云”场景 偶尔闪现在脑海 真的是太爽了;如果没有来得及玩过的同学,这次可以真正的自己做一个了

本实例用的是Python3(当然了Python3.5 3.6 3.7....都行 )+ pygame实现的

运行之前需要安装pygame模块,安装命令如下

pip install pygame -i https://mirrors.aliyun.com/pypi/simple/

二、运行效果

python 基于pygame实现俄罗斯方块

python 基于pygame实现俄罗斯方块

三、完整代码

文件main.py代码如下:

"""
作者:it项目实例网
更多项目实例,请访问:www.itprojects.cn
"""

import random
import sys
import time

import pygame

from blocks import block_s, block_i, block_j, block_l, block_o, block_t, block_z

SCREEN_WIDTH, SCREEN_HEIGHT = 450, 750
BG_COLOR = (40, 40, 60) # 背景色
BLOCK_COL_NUM = 10 # 每行的方格数
SIZE = 30 # 每个小方格大小
BLOCK_ROW_NUM = 25 # 每列的方个数
BORDER_WIDTH = 4 # 游戏区边框宽度
RED = (200, 30, 30) # 红色,GAME OVER 的字体颜色


def judge_game_over(stop_all_block_list):
 """
 判断游戏是否结束
 """
 if "O" in stop_all_block_list[0]:
  return True


def change_speed(score):
 speed_level = [("1", 0.5, 0, 20), ("2", 0.4, 21, 50), ("3", 0.3, 51, 100), ("4", 0.2, 101, 200), ("5", 0.1, 201, None)]
 for speed_info, speed, score_start, score_stop in speed_level:
  if score_stop and score_start <= score <= score_stop:
   return speed_info, speed
  elif score_stop is None and score >= score_start:
   return speed_info, speed


def judge_lines(stop_all_block_list):
 """
 判断是否有同一行的方格,如果有则消除
 """
 # 记录刚刚消除的行数
 move_row_list = list()
 # 消除满格的行
 for row, line in enumerate(stop_all_block_list):
  if "." not in line:
   # 如果这一行没有. 那么就意味着全部是O,则消除这一行
   stop_all_block_list[row] = ['.' for _ in range(len(line))]
   move_row_list.append(row)

 # 如果没有满格的行,则结束此函数
 if not move_row_list:
  return 0

 # 移动剩余的行到下一行
 for row in move_row_list:
  stop_all_block_list.pop(row)
  stop_all_block_list.insert(0, ['.' for _ in range(len(line))])

 return len(move_row_list) * 10


def add_to_stop_all_block_list(stop_all_block_list, current_block, current_block_start_row, current_block_start_col):
 """
 将当前已经停止移动的block添加到列表中
 """
 for row, line in enumerate(current_block):
  for col, block in enumerate(line):
   if block != '.':
    stop_all_block_list[current_block_start_row + row][current_block_start_col + col] = "O"


def change_current_block_style(current_block):
 """
 改变图形的样式
 """
 # 计算出,当前图形样式属于哪个图形
 current_block_style_list = None
 for block_style_list in [block_s, block_i, block_j, block_l, block_o, block_t, block_z]:
  if current_block in block_style_list:
   current_block_style_list = block_style_list

 # 得到当前正在用的图形的索引(下标)
 index = current_block_style_list.index(current_block)
 # 它的下一个图形的索引
 index += 1
 # 防止越界
 index = index % len(current_block_style_list)
 # 返回下一个图形
 return current_block_style_list[index]


def judge_move_right(current_block, current_block_start_col):
 """
 判断是否可以向右移动
 """
 # 先判断列的方式是从右到左
 for col in range(len(current_block[0]) - 1, -1, -1):
  # 得到1列的所有元素
  col_list = [line[col] for line in current_block]
  # 判断是否碰到右边界
  if 'O' in col_list and current_block_start_col + col >= BLOCK_COL_NUM:
   return False
 return True


def judge_move_left(current_block, current_block_start_col):
 """
 判断是否可以向左移动
 """
 # 先判断列的方式是从左到右
 for col in range(len(current_block[0])):
  # 得到1列的所有元素
  col_list = [line[col] for line in current_block]
  # 判断是否碰到右边界
  if 'O' in col_list and current_block_start_col + col < 0:
   return False
 return True


def judge_move_down(current_block, current_block_start_row, current_block_start_col, stop_all_block_list):
 """
 判断是否碰撞到其它图形或者底边界
 """
 # 得到其它图形所有的坐标
 stop_all_block_position = list()
 for row, line in enumerate(stop_all_block_list):
  for col, block in enumerate(line):
   if block != ".":
    stop_all_block_position.append((row, col))
 # print(stop_all_block_position)

 # 判断碰撞
 for row, line in enumerate(current_block):
  if 'O' in line and current_block_start_row + row >= BLOCK_ROW_NUM:
   # 如果当前行有0,且从起始行开始算+当前显示的行,超过了总行数,那么就认为碰到了底部
   return False
  for col, block in enumerate(line):
   if block != "." and (current_block_start_row + row, current_block_start_col + col) in stop_all_block_position:
    return False

 return True


def get_block():
 """
 创建一个图形
 """
 block_style_list = random.choice([block_s, block_i, block_j, block_l, block_o, block_t, block_z])
 return random.choice(block_style_list)


def main():
 pygame.init()
 screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
 pygame.display.set_caption('俄罗斯方块')

 current_block = get_block() # 当前图形
 current_block_start_row = -2 # 当前图片从哪一行开始显示图形
 current_block_start_col = 4 # 当前图形从哪一列开始显示
 next_block = get_block() # 下一个图形
 last_time = time.time()
 speed = 0.5 # 降落的速度
 speed_info = '1' # 显示的速度等级

 # 定义一个列表,用来存储所有的已经停止移动的形状
 stop_all_block_list = [['.' for i in range(BLOCK_COL_NUM)] for j in range(BLOCK_ROW_NUM)]

 # 字体
 font = pygame.font.Font('yh.ttf', 24) # 黑体24
 game_over_font = pygame.font.Font("yh.ttf", 72)
 game_over_font_width, game_over_font_height = game_over_font.size('GAME OVER')
 game_again_font_width, game_again_font_height = font.size('鼠标点击任意位置,再来一局')

 # 得分
 score = 0

 # 标记游戏是否结束
 game_over = False

 # 创建计时器(防止while循环过快,占用太多CPU的问题)
 clock = pygame.time.Clock()
 while True:
  for event in pygame.event.get():
   if event.type == pygame.QUIT:
    sys.exit()
   elif event.type == pygame.KEYDOWN:
    if event.key == pygame.K_LEFT:
     if judge_move_left(current_block, current_block_start_col - 1):
      current_block_start_col -= 1
    elif event.key == pygame.K_RIGHT:
     if judge_move_right(current_block, current_block_start_col + 1):
      current_block_start_col += 1
    elif event.key == pygame.K_UP:
     current_block_next_style = change_current_block_style(current_block)
     if judge_move_left(current_block_next_style, current_block_start_col) and \
       judge_move_right(current_block_next_style, current_block_start_col) and \
       judge_move_down(current_block, current_block_start_row, current_block_start_col, stop_all_block_list):
      # 判断新的样式没有越界
      current_block = current_block_next_style
    elif event.key == pygame.K_DOWN:
     # 判断是否可以向下移动,如果碰到底部或者其它的图形就不能移动了
     if judge_move_down(current_block, current_block_start_row + 1, current_block_start_col, stop_all_block_list):
      current_block_start_row += 1
   elif event.type == pygame.MOUSEBUTTONDOWN and event.button:
    if game_over:
     # 重置游戏用到的变量
     current_block = get_block() # 当前图形
     current_block_start_row = -2 # 当前图片从哪一行开始显示图形
     current_block_start_col = 4 # 当前图形从哪一列开始显示
     next_block = get_block() # 下一个图形
     stop_all_block_list = [['.' for i in range(BLOCK_COL_NUM)] for j in range(BLOCK_ROW_NUM)]
     score = 0
     game_over = False

  # 判断是否修改当前图形显示的起始行
  if not game_over and time.time() - last_time > speed:
   last_time = time.time()
   # 判断是否可以向下移动,如果碰到底部或者其它的图形就不能移动了
   if judge_move_down(current_block, current_block_start_row + 1, current_block_start_col, stop_all_block_list):
    current_block_start_row += 1
   else:
    # 将这个图形存储到统一的列表中,这样便于判断是否成为一行
    add_to_stop_all_block_list(stop_all_block_list, current_block, current_block_start_row, current_block_start_col)
    # 判断是否有同一行的,如果有就消除,且加上分数
    score += judge_lines(stop_all_block_list)
    # 判断游戏是否结束(如果第一行中间有O那么就表示游戏结束)
    game_over = judge_game_over(stop_all_block_list)
    # 调整速度
    speed_info, speed = change_speed(score)
    # 创建新的图形
    current_block = next_block
    next_block = get_block()
    # 重置数据
    current_block_start_col = 4
    current_block_start_row = -2

  # 画背景(填充背景色)
  screen.fill(BG_COLOR)

  # 画游戏区域分隔线
  pygame.draw.line(screen, (100, 40, 200), (SIZE * BLOCK_COL_NUM, 0), (SIZE * BLOCK_COL_NUM, SCREEN_HEIGHT), BORDER_WIDTH)

  # 显示当前图形
  for row, line in enumerate(current_block):
   for col, block in enumerate(line):
    if block != '.':
     pygame.draw.rect(screen, (20, 128, 200), ((current_block_start_col + col) * SIZE, (current_block_start_row + row) * SIZE, SIZE, SIZE), 0)

  # 显示所有停止移动的图形
  for row, line in enumerate(stop_all_block_list):
   for col, block in enumerate(line):
    if block != '.':
     pygame.draw.rect(screen, (20, 128, 200), (col * SIZE, row * SIZE, SIZE, SIZE), 0)

  # 画网格线 竖线
  for x in range(BLOCK_COL_NUM):
   pygame.draw.line(screen, (0, 0, 0), (x * SIZE, 0), (x * SIZE, SCREEN_HEIGHT), 1)
  # 画网格线 横线
  for y in range(BLOCK_ROW_NUM):
   pygame.draw.line(screen, (0, 0, 0), (0, y * SIZE), (BLOCK_COL_NUM * SIZE, y * SIZE), 1)

  # 显示右侧(得分、速度、下一行图形)
  # 得分
  score_show_msg = font.render('得分: ', True, (255, 255, 255))
  screen.blit(score_show_msg, (BLOCK_COL_NUM * SIZE + 10, 10))
  score_show_msg = font.render(str(score), True, (255, 255, 255))
  screen.blit(score_show_msg, (BLOCK_COL_NUM * SIZE + 10, 50))
  # 速度
  speed_show_msg = font.render('速度: ', True, (255, 255, 255))
  screen.blit(speed_show_msg, (BLOCK_COL_NUM * SIZE + 10, 100))
  speed_show_msg = font.render(speed_info, True, (255, 255, 255))
  screen.blit(speed_show_msg, (BLOCK_COL_NUM * SIZE + 10, 150))
  # 下一个图形(文字提示)
  next_style_msg = font.render('下一个: ', True, (255, 255, 255))
  screen.blit(next_style_msg, (BLOCK_COL_NUM * SIZE + 10, 200))
  # 下一个图形(图形)
  for row, line in enumerate(next_block):
   for col, block in enumerate(line):
    if block != '.':
     pygame.draw.rect(screen, (20, 128, 200), (320 + SIZE * col, (BLOCK_COL_NUM + row) * SIZE, SIZE, SIZE), 0)
     # 显示这个方格的4个边的颜色
     # 左
     pygame.draw.line(screen, (0, 0, 0), (320 + SIZE * col, (BLOCK_COL_NUM + row) * SIZE), (320 + SIZE * col, (BLOCK_COL_NUM + row + 1) * SIZE), 1)
     # 上
     pygame.draw.line(screen, (0, 0, 0), (320 + SIZE * col, (BLOCK_COL_NUM + row) * SIZE), (320 + SIZE * (col + 1), (BLOCK_COL_NUM + row) * SIZE), 1)
     # 下
     pygame.draw.line(screen, (0, 0, 0), (320 + SIZE * col, (BLOCK_COL_NUM + row + 1) * SIZE), (320 + SIZE * (col + 1), (BLOCK_COL_NUM + row + 1) * SIZE), 1)
     # 右
     pygame.draw.line(screen, (0, 0, 0), (320 + SIZE * (col + 1), (BLOCK_COL_NUM + row) * SIZE), (320 + SIZE * (col + 1), (BLOCK_COL_NUM + row + 1) * SIZE), 1)

  # 显示游戏结束画面
  if game_over:
   game_over_tips = game_over_font.render('GAME OVER', True, RED)
   screen.blit(game_over_tips, ((SCREEN_WIDTH - game_over_font_width) // 2, (SCREEN_HEIGHT - game_over_font_height) // 2))
   # 显示"鼠标点击任意位置,再来一局"
   game_again = font.render('鼠标点击任意位置,再来一局', True, RED)
   screen.blit(game_again, ((SCREEN_WIDTH - game_again_font_width) // 2, (SCREEN_HEIGHT - game_again_font_height) // 2 + 80))

  # 刷新显示(此时窗口才会真正的显示)
  pygame.display.update()
  # FPS(每秒钟显示画面的次数)
  clock.tick(60) # 通过一定的延时,实现1秒钟能够循环60次


if __name__ == '__main__':
 main()

文件blocks.py代码如下:

# S形方块
block_s = [['.OO',
   'OO.',
   '...'],
   ['O..',
   'OO.',
   '.O.']]
# Z形方块
block_z = [['OO.',
   '.OO',
   '...'],
   ['.O.',
   'OO.',
   'O..']]
# I型方块
block_i = [['.O..',
   '.O..',
   '.O..',
   '.O..'],
   ['....',
   '....',
   'OOOO',
   '....']]
# O型方块
block_o = [['OO',
   'OO']]
# J型方块
block_j = [['O..',
   'OOO',
   '...'],
   ['.OO',
   '.O.',
   '.O.'],
   ['...',
   'OOO',
   '..O'],
   ['.O.',
   '.O.',
   'OO.']]
# L型方块
block_l = [['..O',
   'OOO',
   '...'],
   ['.O.',
   '.O.',
   '.OO'],
   ['...',
   'OOO',
   'O..'],
   ['OO.',
   '.O.',
   '.O.']]
# T型方块
block_t = [['.O.',
   'OOO',
   '...'],
   ['.O.',
   '.OO',
   '.O.'],
   ['...',
   'OOO',
   '.O.'],
   ['.O.',
   'OO.',
   '.O.']]

以上就是python 基于pygame实现俄罗斯方块的详细内容,更多关于python 俄罗斯方块的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
压缩包密码破解示例分享(类似典破解)
Jan 17 Python
Python线程的两种编程方式
Apr 14 Python
浅析Python中的赋值和深浅拷贝
Aug 15 Python
Python实现将doc转化pdf格式文档的方法
Jan 19 Python
Python实现购物车程序
Apr 16 Python
python 通过字符串调用对象属性或方法的实例讲解
Apr 21 Python
python实现事件驱动
Nov 21 Python
Python实现针对json中某个关键字段进行排序操作示例
Dec 25 Python
解决运行出现'dict' object has no attribute 'has_key'问题
Jul 15 Python
Python列表推导式实现代码实例
Sep 09 Python
Python3使用tesserocr识别字母数字验证码的实现
Jan 29 Python
浅析python连接数据库的重要事项
Feb 22 Python
使用Python快速打开一个百万行级别的超大Excel文件的方法
Mar 02 #Python
Autopep8的使用(python自动编排工具)
Mar 02 #Python
python 将Excel转Word的示例
Mar 02 #Python
Python字节单位转换(将字节转换为K M G T)
Mar 02 #Python
Python使用cn2an实现中文数字与阿拉伯数字的相互转换
Mar 02 #Python
jupyter notebook指定启动目录的方法
Mar 02 #Python
python实现发送邮件
Mar 02 #Python
You might like
PHP 和 XML: 使用expat函数(二)
2006/10/09 PHP
PHP一些有意思的小区别
2006/12/06 PHP
鸡肋的PHP单例模式应用详解
2013/06/03 PHP
PHP与MYSQL中UTF8编码的中文排序实例
2014/10/21 PHP
使用纯php代码实现页面伪静态的方法
2015/07/25 PHP
Thinkphp 框架配置操作之配置加载与读取配置实例分析
2020/05/15 PHP
JavaScript window.setTimeout() 的详细用法
2009/11/04 Javascript
网页前台通过js非法字符过滤代码(骂人的话等等)
2010/05/26 Javascript
调试Node.JS的辅助工具(NodeWatcher)
2012/01/04 Javascript
定时器(setTimeout/setInterval)调用带参函数失效解决方法
2013/03/26 Javascript
基于JavaScript 下namespace 功能的简单分析
2013/07/05 Javascript
jquery批量控制form禁用的代码
2013/08/06 Javascript
node.js中watch机制详解
2014/11/17 Javascript
js实现Select下拉框具有输入功能的方法
2015/02/06 Javascript
jQuery 3.0十大新特性最终版发布
2016/07/14 Javascript
详解JavaScript节流函数中的Throttle
2016/07/16 Javascript
jQuery实现移动端手机商城购物车功能
2016/09/24 Javascript
Angularjs过滤器实现动态搜索与排序功能示例
2017/12/13 Javascript
js 取消页面可以选中文字的功能方法
2018/01/02 Javascript
vue引入新版 vue-awesome-swiper插件填坑问题
2018/01/25 Javascript
通过Python使用saltstack生成服务器资产清单
2016/03/01 Python
Python基于hashlib模块的文件MD5一致性加密验证示例
2018/02/10 Python
windows下pycharm安装、创建文件、配置默认模板
2018/07/31 Python
感知器基础原理及python实现过程详解
2019/09/30 Python
pygame实现贪吃蛇游戏(上)
2019/10/29 Python
Pycharm 2020年最新激活码(亲测有效)
2020/09/18 Python
将python字符串转化成长表达式的函数eval实例
2020/05/11 Python
英语专业毕业个人求职自荐信
2013/09/21 职场文书
事业单位请假制度
2014/01/13 职场文书
数控技术专业毕业自荐书范文
2014/02/05 职场文书
2014厂务公开实施方案
2014/02/17 职场文书
相亲大会策划方案
2014/06/05 职场文书
银行会计主管岗位职责
2014/10/01 职场文书
领导干部作风建设总结
2014/10/23 职场文书
2015年度合同管理工作总结
2015/05/22 职场文书
JavaScript 实现页面滚动动画
2021/04/24 Javascript