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 相关文章推荐
python 获取文件列表(或是目录例表)
Mar 25 Python
python实现用户管理系统
Jan 10 Python
Python基于滑动平均思想实现缺失数据填充的方法
Feb 21 Python
python实现的接收邮件功能示例【基于网易POP3服务器】
Sep 11 Python
python生成器推导式用法简单示例
Oct 08 Python
使用Python进行中文繁简转换的实现代码
Oct 18 Python
创建Shapefile文件并写入数据的例子
Nov 26 Python
Python中filter与lambda的结合使用详解
Dec 24 Python
linux 下python多线程递归复制文件夹及文件夹中的文件
Jan 02 Python
python实现猜拳游戏
Mar 04 Python
TensorFlow的reshape操作 tf.reshape的实现
Apr 19 Python
python3跳出一个循环的实例操作
Aug 18 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循环语句笔记(foreach,list)
2011/11/29 PHP
bcastr2.0 通用的图片浏览器
2006/11/22 Javascript
枚举JavaScript对象的函数
2006/12/22 Javascript
jQuery实现复选框成对选择及对应取消的方法
2015/03/03 Javascript
jQuery实现鼠标划过展示大图的方法
2015/03/09 Javascript
JS正则表达式修饰符global(/g)用法分析
2016/12/27 Javascript
js实现移动端轮播图效果
2020/12/09 Javascript
javascript如何用递归写一个简单的树形结构示例
2017/09/06 Javascript
shiro授权的实现原理
2017/09/21 Javascript
Vue.js做select下拉列表的实例(ul-li标签仿select标签)
2018/03/02 Javascript
Windows下支持自动更新的Electron应用脚手架的方法
2018/12/24 Javascript
可能被忽略的一些JavaScript数组方法细节
2019/02/28 Javascript
在weex中愉快的使用scss的方法步骤
2020/01/02 Javascript
原生JS实现无缝轮播图片
2020/06/24 Javascript
JS前后端实现身份证号验证代码解析
2020/07/23 Javascript
一篇超完整的Vue新手入门指导教程
2020/11/18 Vue.js
[00:32]DOTA2上海特级锦标赛 Ehome战队宣传片
2016/03/03 DOTA
Flask框架的学习指南之制作简单blog系统
2016/11/20 Python
django+js+ajax实现刷新页面的方法
2017/05/22 Python
Python实现动态图解析、合成与倒放
2018/01/18 Python
TensorFlow实现创建分类器
2018/02/06 Python
Python常见字典内建函数用法示例
2018/05/14 Python
flask框架路由常用定义方式总结
2019/07/23 Python
利用pandas向一个csv文件追加写入数据的实现示例
2020/04/23 Python
如何对python的字典进行排序
2020/06/19 Python
Python unittest基本使用方法代码实例
2020/06/29 Python
巴西图书和电子产品购物网站:Saraiva
2017/06/07 全球购物
德国网上花店:Valentins
2018/08/15 全球购物
PHP笔试题
2012/02/22 面试题
以下为Windows NT 下的32 位C++程序,请计算sizeof 的值
2016/12/07 面试题
个人自荐书
2013/12/20 职场文书
自荐信格式简述
2014/01/25 职场文书
教师竞聘演讲稿
2014/05/16 职场文书
幼儿园教师自我评价
2015/03/04 职场文书
幼儿园开学报名通知
2015/07/16 职场文书
看看如何用Python绘制小米新版天价logo
2021/04/20 Python