python实现俄罗斯方块小游戏


Posted in Python onApril 24, 2020

回顾我们的python制作小游戏之路,几篇非常精彩的文章

我们用python实现了坦克大战

我们用python实现了飞船大战

我们用python实现了两种不同的贪吃蛇游戏

150行代码实现贪吃蛇游戏

我们用python实现了扫雷游戏

我们用python实现了五子棋游戏

今天我们用python来实现小时候玩过的俄罗斯方块游戏吧
具体代码与文件可以访问我的GitHub地址获取

第一步——构建各种方块

import random
from collections import namedtuple

Point = namedtuple('Point', 'X Y')
Shape = namedtuple('Shape', 'X Y Width Height')
Block = namedtuple('Block', 'template start_pos end_pos name next')

# 方块形状的设计,我最初我是做成 4 × 4,因为长宽最长都是4,这样旋转的时候就不考虑怎么转了,就是从一个图形替换成另一个
# 其实要实现这个功能,只需要固定左上角的坐标就可以了

# S形方块
S_BLOCK = [Block(['.OO',
  'OO.',
  '...'], Point(0, 0), Point(2, 1), 'S', 1),
 Block(['O..',
  'OO.',
  '.O.'], Point(0, 0), Point(1, 2), 'S', 0)]
# Z形方块
Z_BLOCK = [Block(['OO.',
  '.OO',
  '...'], Point(0, 0), Point(2, 1), 'Z', 1),
 Block(['.O.',
  'OO.',
  'O..'], Point(0, 0), Point(1, 2), 'Z', 0)]
# I型方块
I_BLOCK = [Block(['.O..',
  '.O..',
  '.O..',
  '.O..'], Point(1, 0), Point(1, 3), 'I', 1),
 Block(['....',
  '....',
  'OOOO',
  '....'], Point(0, 2), Point(3, 2), 'I', 0)]
# O型方块
O_BLOCK = [Block(['OO',
  'OO'], Point(0, 0), Point(1, 1), 'O', 0)]
# J型方块
J_BLOCK = [Block(['O..',
  'OOO',
  '...'], Point(0, 0), Point(2, 1), 'J', 1),
 Block(['.OO',
  '.O.',
  '.O.'], Point(1, 0), Point(2, 2), 'J', 2),
 Block(['...',
  'OOO',
  '..O'], Point(0, 1), Point(2, 2), 'J', 3),
 Block(['.O.',
  '.O.',
  'OO.'], Point(0, 0), Point(1, 2), 'J', 0)]
# L型方块
L_BLOCK = [Block(['..O',
  'OOO',
  '...'], Point(0, 0), Point(2, 1), 'L', 1),
 Block(['.O.',
  '.O.',
  '.OO'], Point(1, 0), Point(2, 2), 'L', 2),
 Block(['...',
  'OOO',
  'O..'], Point(0, 1), Point(2, 2), 'L', 3),
 Block(['OO.',
  '.O.',
  '.O.'], Point(0, 0), Point(1, 2), 'L', 0)]
# T型方块
T_BLOCK = [Block(['.O.',
  'OOO',
  '...'], Point(0, 0), Point(2, 1), 'T', 1),
 Block(['.O.',
  '.OO',
  '.O.'], Point(1, 0), Point(2, 2), 'T', 2),
 Block(['...',
  'OOO',
  '.O.'], Point(0, 1), Point(2, 2), 'T', 3),
 Block(['.O.',
  'OO.',
  '.O.'], Point(0, 0), Point(1, 2), 'T', 0)]

BLOCKS = {'O': O_BLOCK,
 'I': I_BLOCK,
 'Z': Z_BLOCK,
 'T': T_BLOCK,
 'L': L_BLOCK,
 'S': S_BLOCK,
 'J': J_BLOCK}


def get_block():
 block_name = random.choice('OIZTLSJ')
 b = BLOCKS[block_name]
 idx = random.randint(0, len(b) - 1)
 return b[idx]


def get_next_block(block):
 b = BLOCKS[block.name]
 return b[block.next]

第二部——构建主函数

import sys
import time
import pygame
from pygame.locals import *
import blocks

SIZE = 30 # 每个小方格大小
BLOCK_HEIGHT = 25 # 游戏区高度
BLOCK_WIDTH = 10 # 游戏区宽度
BORDER_WIDTH = 4 # 游戏区边框宽度
BORDER_COLOR = (40, 40, 200) # 游戏区边框颜色
SCREEN_WIDTH = SIZE * (BLOCK_WIDTH + 5) # 游戏屏幕的宽
SCREEN_HEIGHT = SIZE * BLOCK_HEIGHT # 游戏屏幕的高
BG_COLOR = (40, 40, 60) # 背景色
BLOCK_COLOR = (20, 128, 200) #
BLACK = (0, 0, 0)
RED = (200, 30, 30) # GAME OVER 的字体颜色


def print_text(screen, font, x, y, text, fcolor=(255, 255, 255)):
 imgText = font.render(text, True, fcolor)
 screen.blit(imgText, (x, y))


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

 font1 = pygame.font.SysFont('SimHei', 24) # 黑体24
 font2 = pygame.font.Font(None, 72) # GAME OVER 的字体
 font_pos_x = BLOCK_WIDTH * SIZE + BORDER_WIDTH + 10 # 右侧信息显示区域字体位置的X坐标
 gameover_size = font2.size('GAME OVER')
 font1_height = int(font1.size('得分')[1])

 cur_block = None # 当前下落方块
 next_block = None # 下一个方块
 cur_pos_x, cur_pos_y = 0, 0

 game_area = None # 整个游戏区域
 game_over = True
 start = False # 是否开始,当start = True,game_over = True 时,才显示 GAME OVER
 score = 0 # 得分
 orispeed = 0.5 # 原始速度
 speed = orispeed # 当前速度
 pause = False # 暂停
 last_drop_time = None # 上次下落时间
 last_press_time = None # 上次按键时间

 def _dock():
 nonlocal cur_block, next_block, game_area, cur_pos_x, cur_pos_y, game_over, score, speed
 for _i in range(cur_block.start_pos.Y, cur_block.end_pos.Y + 1):
 for _j in range(cur_block.start_pos.X, cur_block.end_pos.X + 1):
 if cur_block.template[_i][_j] != '.':
  game_area[cur_pos_y + _i][cur_pos_x + _j] = '0'
 if cur_pos_y + cur_block.start_pos.Y <= 0:
 game_over = True
 else:
 # 计算消除
 remove_idxs = []
 for _i in range(cur_block.start_pos.Y, cur_block.end_pos.Y + 1):
 if all(_x == '0' for _x in game_area[cur_pos_y + _i]):
  remove_idxs.append(cur_pos_y + _i)
 if remove_idxs:
 # 计算得分
 remove_count = len(remove_idxs)
 if remove_count == 1:
  score += 100
 elif remove_count == 2:
  score += 300
 elif remove_count == 3:
  score += 700
 elif remove_count == 4:
  score += 1500
 speed = orispeed - 0.03 * (score // 10000)
 # 消除
 _i = _j = remove_idxs[-1]
 while _i >= 0:
  while _j in remove_idxs:
  _j -= 1
  if _j < 0:
  game_area[_i] = ['.'] * BLOCK_WIDTH
  else:
  game_area[_i] = game_area[_j]
  _i -= 1
  _j -= 1
 cur_block = next_block
 next_block = blocks.get_block()
 cur_pos_x, cur_pos_y = (BLOCK_WIDTH - cur_block.end_pos.X - 1) // 2, -1 - cur_block.end_pos.Y

 def _judge(pos_x, pos_y, block):
 nonlocal game_area
 for _i in range(block.start_pos.Y, block.end_pos.Y + 1):
 if pos_y + block.end_pos.Y >= BLOCK_HEIGHT:
 return False
 for _j in range(block.start_pos.X, block.end_pos.X + 1):
 if pos_y + _i >= 0 and block.template[_i][_j] != '.' and game_area[pos_y + _i][pos_x + _j] != '.':
  return False
 return True

 while True:
 for event in pygame.event.get():
 if event.type == QUIT:
 sys.exit()
 elif event.type == KEYDOWN:
 if event.key == K_RETURN:
  if game_over:
  start = True
  game_over = False
  score = 0
  last_drop_time = time.time()
  last_press_time = time.time()
  game_area = [['.'] * BLOCK_WIDTH for _ in range(BLOCK_HEIGHT)]
  cur_block = blocks.get_block()
  next_block = blocks.get_block()
  cur_pos_x, cur_pos_y = (BLOCK_WIDTH - cur_block.end_pos.X - 1) // 2, -1 - cur_block.end_pos.Y
 elif event.key == K_SPACE:
  if not game_over:
  pause = not pause
 elif event.key in (K_w, K_UP):
  # 旋转
  # 其实记得不是很清楚了,比如
  # .0.
  # .00
  # ..0
  # 这个在最右边靠边的情况下是否可以旋转,我试完了网上的俄罗斯方块,是不能旋转的,这里我们就按不能旋转来做
  # 我们在形状设计的时候做了很多的空白,这样只需要规定整个形状包括空白部分全部在游戏区域内时才可以旋转
  if 0 <= cur_pos_x <= BLOCK_WIDTH - len(cur_block.template[0]):
  _next_block = blocks.get_next_block(cur_block)
  if _judge(cur_pos_x, cur_pos_y, _next_block):
  cur_block = _next_block

 if event.type == pygame.KEYDOWN:
 if event.key == pygame.K_LEFT:
 if not game_over and not pause:
  if time.time() - last_press_time > 0.1:
  last_press_time = time.time()
  if cur_pos_x > - cur_block.start_pos.X:
  if _judge(cur_pos_x - 1, cur_pos_y, cur_block):
  cur_pos_x -= 1
 if event.key == pygame.K_RIGHT:
 if not game_over and not pause:
  if time.time() - last_press_time > 0.1:
  last_press_time = time.time()
  # 不能移除右边框
  if cur_pos_x + cur_block.end_pos.X + 1 < BLOCK_WIDTH:
  if _judge(cur_pos_x + 1, cur_pos_y, cur_block):
  cur_pos_x += 1
 if event.key == pygame.K_DOWN:
 if not game_over and not pause:
  if time.time() - last_press_time > 0.1:
  last_press_time = time.time()
  if not _judge(cur_pos_x, cur_pos_y + 1, cur_block):
  _dock()
  else:
  last_drop_time = time.time()
  cur_pos_y += 1

 _draw_background(screen)

 _draw_game_area(screen, game_area)

 _draw_gridlines(screen)

 _draw_info(screen, font1, font_pos_x, font1_height, score)
 # 画显示信息中的下一个方块
 _draw_block(screen, next_block, font_pos_x, 30 + (font1_height + 6) * 5, 0, 0)

 if not game_over:
 cur_drop_time = time.time()
 if cur_drop_time - last_drop_time > speed:
 if not pause:
  # 不应该在下落的时候来判断到底没,我们玩俄罗斯方块的时候,方块落到底的瞬间是可以进行左右移动
  if not _judge(cur_pos_x, cur_pos_y + 1, cur_block):
  _dock()
  else:
  last_drop_time = cur_drop_time
  cur_pos_y += 1
 else:
 if start:
 print_text(screen, font2,
  (SCREEN_WIDTH - gameover_size[0]) // 2, (SCREEN_HEIGHT - gameover_size[1]) // 2,
  'GAME OVER', RED)

 # 画当前下落方块
 _draw_block(screen, cur_block, 0, 0, cur_pos_x, cur_pos_y)

 pygame.display.flip()


# 画背景
def _draw_background(screen):
 # 填充背景色
 screen.fill(BG_COLOR)
 # 画游戏区域分隔线
 pygame.draw.line(screen, BORDER_COLOR,
  (SIZE * BLOCK_WIDTH + BORDER_WIDTH // 2, 0),
  (SIZE * BLOCK_WIDTH + BORDER_WIDTH // 2, SCREEN_HEIGHT), BORDER_WIDTH)


# 画网格线
def _draw_gridlines(screen):
 # 画网格线 竖线
 for x in range(BLOCK_WIDTH):
 pygame.draw.line(screen, BLACK, (x * SIZE, 0), (x * SIZE, SCREEN_HEIGHT), 1)
 # 画网格线 横线
 for y in range(BLOCK_HEIGHT):
 pygame.draw.line(screen, BLACK, (0, y * SIZE), (BLOCK_WIDTH * SIZE, y * SIZE), 1)


# 画已经落下的方块
def _draw_game_area(screen, game_area):
 if game_area:
 for i, row in enumerate(game_area):
 for j, cell in enumerate(row):
 if cell != '.':
  pygame.draw.rect(screen, BLOCK_COLOR, (j * SIZE, i * SIZE, SIZE, SIZE), 0)


# 画单个方块
def _draw_block(screen, block, offset_x, offset_y, pos_x, pos_y):
 if block:
 for i in range(block.start_pos.Y, block.end_pos.Y + 1):
 for j in range(block.start_pos.X, block.end_pos.X + 1):
 if block.template[i][j] != '.':
  pygame.draw.rect(screen, BLOCK_COLOR,
   (offset_x + (pos_x + j) * SIZE, offset_y + (pos_y + i) * SIZE, SIZE, SIZE), 0)


# 画得分等信息
def _draw_info(screen, font, pos_x, font_height, score):
 print_text(screen, font, pos_x, 10, f'得分: ')
 print_text(screen, font, pos_x, 10 + font_height + 6, f'{score}')
 print_text(screen, font, pos_x, 20 + (font_height + 6) * 2, f'速度: ')
 print_text(screen, font, pos_x, 20 + (font_height + 6) * 3, f'{score // 10000}')
 print_text(screen, font, pos_x, 30 + (font_height + 6) * 4, f'下一个:')


if __name__ == '__main__':
 main()

游戏截图

python实现俄罗斯方块小游戏

运行效果

python实现俄罗斯方块小游戏

更多俄罗斯方块精彩文章请点击专题:俄罗斯方块游戏集合 进行学习。

更多有趣的经典小游戏实现专题,也分享给大家:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
CentOS中升级Python版本的方法详解
Jul 10 Python
初学python的操作难点总结(新手必看篇)
Aug 03 Python
python中使用xlrd读excel使用xlwt写excel的实例代码
Jan 31 Python
Python OpenCV读取png图像转成jpg图像存储的方法
Oct 28 Python
pandas DataFrame 删除重复的行的实现方法
Jan 29 Python
pyinstaller打包单个exe后无法执行错误的解决方法
Jun 21 Python
python celery分布式任务队列的使用详解
Jul 08 Python
Python 中list ,set,dict的大规模查找效率对比详解
Oct 11 Python
通过实例了解Python str()和repr()的区别
Jan 17 Python
Python django框架开发发布会签到系统(web开发)
Feb 12 Python
python基于Kivy写一个图形桌面时钟程序
Jan 28 Python
Python 内置函数速查表一览
Jun 02 Python
iPython pylab模式启动方式
Apr 24 #Python
python实现扫雷小游戏
Apr 24 #Python
jupyter 使用Pillow包显示图像时inline显示方式
Apr 24 #Python
pyspark 随机森林的实现
Apr 24 #Python
Jupyter打开图形界面并画出正弦函数图像实例
Apr 24 #Python
pyspark给dataframe增加新的一列的实现示例
Apr 24 #Python
Pandas将列表(List)转换为数据框(Dataframe)
Apr 24 #Python
You might like
php-redis中的sort排序函数总结
2015/07/08 PHP
Yii2 输出xml格式数据的方法
2016/05/03 PHP
PHP实现基于图的深度优先遍历输出1,2,3...n的全排列功能
2017/11/10 PHP
详解thinkphp中的volist标签
2018/01/15 PHP
PHP设计模式之抽象工厂模式实例分析
2019/03/25 PHP
jquery在Chrome下获取图片的长宽问题解决
2013/03/20 Javascript
JS实现多物体缓冲运动实例代码
2013/11/29 Javascript
图片翻转效果具体实现代码
2014/01/09 Javascript
JavaScript简单表格编辑功能实现方法
2015/04/16 Javascript
轻松实现jQuery添加删除按钮Click事件
2017/03/13 Javascript
JavaScrpt中如何使用 cookie 设置查看与删除功能
2017/07/09 Javascript
详谈JS中数组的迭代方法和归并方法
2017/08/11 Javascript
javascript如何用递归写一个简单的树形结构示例
2017/09/06 Javascript
JS与SQL方式随机生成高强度密码示例
2018/12/29 Javascript
layui-table表复选框勾选的所有行数据获取的例子
2019/09/13 Javascript
Angular 多模块项目构建过程
2020/02/13 Javascript
[05:28]刀塔密之一:团结则存
2014/07/03 DOTA
Python文件夹与文件的相关操作(推荐)
2016/07/25 Python
Django的HttpRequest和HttpResponse对象详解
2018/01/26 Python
解决python2 绘图title,xlabel,ylabel出现中文乱码的问题
2019/01/29 Python
Python 使用 attrs 和 cattrs 实现面向对象编程的实践
2019/06/12 Python
解决安装python3.7.4报错Can''t connect to HTTPS URL because the SSL module is not available
2019/07/31 Python
如何使用PyCharm引入需要使用的包的方法
2020/09/22 Python
如何使用pycharm连接Databricks的步骤详解
2020/09/23 Python
python Matplotlib基础--如何添加文本和标注
2021/01/26 Python
Giglio英国站:意大利奢侈品购物网
2018/03/06 全球购物
孕妇内衣和胸罩:Cake Maternity
2018/07/16 全球购物
Ajxa常见问题都有哪些
2014/03/26 面试题
好的自荐信的要求
2013/10/30 职场文书
语文教学随笔感言
2014/02/18 职场文书
简历中个人自我评价分享
2014/03/15 职场文书
老师对学生的寄语
2014/04/09 职场文书
法制演讲稿
2014/09/10 职场文书
民主评议党员总结
2014/10/20 职场文书
2015年幼儿园班主任个人工作总结
2015/10/22 职场文书
职场领导同事生日简短祝福语
2019/08/06 职场文书