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语言中的按位运算符
Nov 26 Python
python实现对一个完整url进行分割的方法
Apr 29 Python
Python中的zipfile模块使用详解
Jun 25 Python
Python实现读取文件最后n行的方法
Feb 23 Python
python中文分词教程之前向最大正向匹配算法详解
Nov 02 Python
Python通过Django实现用户注册和邮箱验证功能代码
Dec 11 Python
通过pycharm使用git的步骤(图文详解)
Jun 13 Python
python发送多人邮件没有展示收件人问题的解决方法
Jun 21 Python
利用python实现短信和电话提醒功能的例子
Aug 08 Python
python3将变量写入SQL语句的实现方式
Mar 02 Python
Python filter()及reduce()函数使用方法解析
Sep 05 Python
Python Pandas知识点之缺失值处理详解
May 11 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 生成随机验证码图片代码
2010/02/08 PHP
ThinkPHP之A方法实例讲解
2014/06/20 PHP
php生成酷炫的四个字符验证码
2016/04/22 PHP
PHP页面跳转操作实例分析(header方法)
2016/09/28 PHP
统计PHP目录中的文件数方法
2019/03/05 PHP
PHP中的empty、isset、isnull的区别与使用实例
2019/03/22 PHP
javascript下string.format函数补充
2010/08/24 Javascript
工作中常用到的JS表单验证代码(包括例子)
2010/11/11 Javascript
js实现刷新iframe的方法汇总
2015/04/27 Javascript
jquery中toggle函数交替使用问题
2015/06/22 Javascript
javascript html5摇一摇功能的实现
2016/04/19 Javascript
用jquery获取自定义的标签属性的值简单实例
2016/09/17 Javascript
微信公众号开发 实现点击返回按钮就返回到聊天界面
2016/12/15 Javascript
BootStrap与Select2使用小结
2017/02/17 Javascript
基于vue的fullpage.js单页滚动插件
2017/03/20 Javascript
js省市区级联查询(插件版&amp;无插件版)
2017/03/21 Javascript
微信小程序对接七牛云存储的方法
2017/07/30 Javascript
JS实现简易留言板增删功能
2020/02/08 Javascript
JS常用排序方法实例代码解析
2020/03/03 Javascript
python模拟登录百度代码分享(获取百度贴吧等级)
2013/12/27 Python
简述Python中的面向对象编程的概念
2015/04/27 Python
Python抽象类的新写法
2015/06/18 Python
Python实现Mysql数据库连接池实例详解
2017/04/11 Python
Python实现的径向基(RBF)神经网络示例
2018/02/06 Python
python scipy求解非线性方程的方法(fsolve/root)
2018/11/12 Python
Python生成rsa密钥对操作示例
2019/04/26 Python
Python代码覆盖率统计工具coverage.py用法详解
2020/11/25 Python
css3 2D图片转动样式可以扩充到Js当中
2014/04/29 HTML / CSS
Smallable英国家庭概念店:设计师童装及家居装饰
2017/07/05 全球购物
巴西美妆购物网站:Kutiz Beauté
2019/03/13 全球购物
什么是servlet链?
2014/07/13 面试题
优秀毕业生求职信范文
2014/01/02 职场文书
社会学专业求职信
2014/07/17 职场文书
交通局领导班子群众路线教育实践活动对照检查材料思想汇报
2014/10/09 职场文书
2015年调度员工作总结
2015/04/30 职场文书
开业庆典致辞
2015/08/01 职场文书