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 相关文章推荐
python实现模拟按键,自动翻页看u17漫画
Mar 17 Python
Python实现数据库编程方法详解
Jun 09 Python
Python编程入门之Hello World的三种实现方式
Nov 13 Python
Python Pandas找到缺失值的位置方法
Apr 12 Python
Python使用logging模块实现打印log到指定文件的方法
Sep 05 Python
python基于SMTP协议发送邮件
May 31 Python
Flask框架请求钩子与request请求对象用法实例分析
Nov 07 Python
Python 限定函数参数的类型及默认值方式
Dec 24 Python
python列表推导和生成器表达式知识点总结
Jan 10 Python
tensorflow实现读取模型中保存的值 tf.train.NewCheckpointReader
Feb 10 Python
Django {{ MEDIA_URL }}无法显示图片的解决方式
Apr 07 Python
pytorch 常用函数 max ,eq说明
Jun 28 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
使用XDebug调试及单元测试覆盖率分析
2011/01/27 PHP
php线性表顺序存储实现代码(增删查改)
2012/02/16 PHP
php解析html类库simple_html_dom(详细介绍)
2013/07/05 PHP
phpmyadmin配置文件现在需要绝密的短密码(blowfish_secret)的2种解决方法
2014/05/07 PHP
PHP版微信公众平台红包API
2015/04/02 PHP
实例讲解PHP设计模式编程中的简单工厂模式
2016/02/29 PHP
ThinkPHP框架里隐藏index.php
2016/04/12 PHP
浅析PHP7新功能及语法变化总结
2016/06/17 PHP
Mac系统下搭建Nginx+php-fpm实例讲解
2020/12/15 PHP
javascript 字符 Escape,encodeURI,encodeURIComponent
2009/07/09 Javascript
jquery mobile实现拨打电话功能的几种方法
2013/08/05 Javascript
javascript控制层显示或隐藏的方法
2015/07/22 Javascript
JavaScript实现选择框按比例拖拉缩放的方法
2015/08/04 Javascript
jQuery动态星级评分效果实现方法
2015/08/06 Javascript
第三章之Bootstrap 表格与按钮功能
2016/04/25 Javascript
解析利用javascript如何判断一个数为素数
2016/12/08 Javascript
基于jQuery实现手风琴菜单、层级菜单、置顶菜单、无缝滚动效果
2017/07/20 jQuery
基于node.js实现微信支付退款功能
2017/12/19 Javascript
vue项目打包后怎样优雅的解决跨域
2019/05/26 Javascript
Vue中常用rules校验规则(实例代码)
2019/11/14 Javascript
Python实现扫描指定目录下的子目录及文件的方法
2014/07/16 Python
python删除指定类型(或非指定)的文件实例详解
2015/07/06 Python
基于Pandas读取csv文件Error的总结
2018/06/15 Python
基于多进程中APScheduler重复运行的解决方法
2019/07/22 Python
给Python学习者的文件读写指南(含基础与进阶)
2020/01/29 Python
python实现UDP协议下的文件传输
2020/03/20 Python
Python3标准库之threading进程中管理并发操作方法
2020/03/30 Python
Django Form设置文本框为readonly操作
2020/07/03 Python
Kmeans均值聚类算法原理以及Python如何实现
2020/09/26 Python
美国折扣地毯销售网站:Rugs.com
2020/03/27 全球购物
科学育儿宣传标语
2014/10/08 职场文书
新教师个人总结
2015/02/06 职场文书
社区工作者个人总结
2015/02/28 职场文书
2015年房产销售工作总结范文
2015/05/22 职场文书
辩论会主持词
2015/07/03 职场文书
OpenCV-Python实现人脸磨皮算法
2021/06/07 Python