@本文来源于公众号:csdn2299,喜欢可以关注公众号 程序员学府

文章目录

  • 前言
  • 外形
  • 方块
  • 停靠

前言

本文代码基于 python3.6 和 pygame1.9.4。

俄罗斯方块是儿时最经典的游戏之一,刚开始接触 pygame 的时候就想写一个俄罗斯方块。但是想到旋转,停靠,消除等操作,感觉好像很难啊,等真正写完了发现,一共也就 300 行代码,并没有什么难的。

先来看一个游戏截图,有点丑,好吧,我没啥美术细胞,但是主体功能都实现了,可以玩起来。
现在来看一下实现的过程。

外形

俄罗斯方块整个界面分为两部分,一部分是左边的游戏区域,另一部分是右边的显示区域,显示得分、速度、下一个方块样式等。这里就不放截图了,看上图就可以。

游戏区域跟贪吃蛇一样,是由一个个小方格组成的,为了看得直观,我特意画了网格线。

import sys
import pygame
from pygame.locals import *SIZE = 30 # 每个小方格大小
BLOCK_HEIGHT = 20 # 游戏区高度
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) # 背景色
BLACK = (0, 0, 0)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) # 黑体24font_pos_x = BLOCK_WIDTH * SIZE + BORDER_WIDTH + 10 # 右侧信息显示区域字体位置的X坐标font1_height = int(font1.size('得分')[1])score = 0  # 得分while True:for event in pygame.event.get():if event.type == QUIT:sys.exit()# 填充背景色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)# 画网格线 竖线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)print_text(screen, font1, font_pos_x, 10, f'得分: ')print_text(screen, font1, font_pos_x, 10 + font1_height + 6, f'{score}')print_text(screen, font1, font_pos_x, 20 + (font1_height + 6) * 2, f'速度: ')print_text(screen, font1, font_pos_x, 20 + (font1_height + 6) * 3, f'{score // 10000}')print_text(screen, font1, font_pos_x, 30 + (font1_height + 6) * 4, f'下一个:')pygame.display.flip()if __name__ == '__main__':main()

方块

接下来就是要定义方块,方块的形状一共有以下 7 种:

这里我做了多次的更改,因为方块最大的长度是长条形的,为4格,所以我统一用了 4 × 4 的方格来定义。这也是可以的,只是后来发现不方便。

为了直观,直接以一个二维数组来定义方块,其中 . 表示空的, 0 表示实心的。(用 . 表示空是为了看得直观,如果用空格会看不清。)
例如 I 行,以 4 × 4 方格定义为

['.0..','.0..','.0..','.0..']

['....','....','0000','....']

方块最难的是需要实现旋转功能,比如 I 型,就有横和竖两种形态。所谓旋转,表面上看,是把方块顺时针旋转了 90°,但实际做的时候,我们并不需要正真的去实现这个“旋转”的效果。

最终实现的时候,这些图形都是我们画在界面上的,而每一次刷新,界面上所有内容都会被清空重画,所以旋转只是画当前方块的时候不再画之前的形状,而是画旋转后的形状。

比如这个 I 型,定义成了 4 × 4 的形状,但实际上只需要 1 × 4 或 4 × 1 就可以了,其他剩下的地方都是空的。它不像 T 型,T 型不是一个矩形,如果用一个矩形来定义,必然有 2 个位置是空的。那么,I 型真的有必要定义成 4 × 4 吗?

答案是肯定的。想想看,如果是 4 × 1 的一个横条,旋转后变成 1 × 4 的竖条,这个位置怎么确定?好像有点困难。但是如果是 4 × 4 的正方形,我们只需要固定起点坐标(左上角)不变,把竖条的 4 × 4 直接替换掉横条的 4 × 4 区域,是不是就实现旋转了?而且位置很容易计算。

另外一点,在有些情况下是不可以旋转的。比如 I 型的竖条,在紧贴左右边框的时候是不可以旋转的。这点我有印象,可以肯定。但是对于其他的形状,我就不是很确定了,我百度搜了下,找了个网页版的俄罗斯方块玩了下,发现也是不可以的。例如:
在紧贴右边框的时候是无法旋转的。如果要每一个形状都去判断一下,那实在是太烦了。从方块的定义入手,就可以很简单的实现。

例如竖条行,定义是:

['.0..','.0..','.0..','.0..']

竖条是可以贴边的,所以当它在最左边的时候,X 轴坐标是 -1,这是因为定义中左边一竖排是空的。我们只需判定,当方块所定义的形状(包括空的部分)完全在游戏区域内时才可以旋转。

我之前所说,全都定义成 4 × 4 不好,原因就在这里,对于 T 型等其他形状,无法做这个判定。所以,对于 T 型等形状,我们可以定义成 3 × 3 的格式:

['.0.','000','...']

还有一种情况是无法旋转的,就是旋转后的位置已经被别的方块占了。另外下落,左右移动,都要做这个判断。既然这些是一致的,那么就可以用同一个方法来判断。

先要定义一个 game_area 变量,用于存放整个游戏区域当前的状态:

game_area = [['.'] * BLOCK_WIDTH for _ in range(BLOCK_HEIGHT)]

初始状态全是空的,所以全部用 . 初始化就可以了。
另外,需要一些变量定义当前下落方块的状态

cur_block = None # 当前下落方块
cur_pos_x, cur_pos_y = 0, 0 # 当前下落方块的坐标

方块我们是以二维数组的方式定义的,并且存在空行和空列,如果我们遍历这个二维数组判断其所在的区域在当前游戏区域内是否已经被别的方块所占,这个是可以实现的。我们考虑另外一种情况,一个竖条形,左边一排是空的,这空的一排是可以移出游戏区域的,这个怎么判断?每次左移的时候都去判断一下左边一排全都是空吗?这太麻烦了。并且方块都是固定的,所以这些我们可以提前定义好。最终方块定义如下:

from collections import namedtuplePoint = namedtuple('Point', 'X Y')
Block = namedtuple('Block', 'template start_pos end_pos name next')# S形方块
S_BLOCK = [Block(['.00','00.','...'], Point(0, 0), Point(2, 1), 'S', 1),Block(['0..','00.','.0.'], Point(0, 0), Point(1, 2), 'S', 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]

判断是否可以旋转,下落,移动的方法也很容易实现了

def _judge(pos_x, pos_y, block):nonlocal game_areafor _i in range(block.start_pos.Y, block.end_pos.Y + 1):if pos_y + block.end_pos.Y >= BLOCK_HEIGHT:return Falsefor _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 Falsereturn True

停靠

最后一个问题是停靠,当方块下落到底或者遇到别的方块之后,就不能在下落了。我将此称之为“停靠”,有个名字说起来也方便一点。

首先是要判断是否可以停靠,停靠发生之后,就是将当前方块的非空点画到游戏区域上,说白了,就是将cur_block的非空点按对应位置复制到game_area里去。并且计算是否有一排被全部填满了,全部填满则消除。

def _dock():nonlocal cur_block, next_block, game_area, cur_pos_x, cur_pos_y, game_overfor _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 = Trueelse:# 计算消除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:# 消除_i = _j = remove_idxs[-1]while _i >= 0:while _j in remove_idxs:_j -= 1if _j < 0:game_area[_i] = ['.'] * BLOCK_WIDTHelse:game_area[_i] = game_area[_j]_i -= 1_j -= 1cur_block = next_blocknext_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

至此,整个俄罗斯方块的主体功能就算是完成了。

这里很多参数是可以调的,例如觉得旋转别扭,可以直接调整方块的定义,而无需去改动代码逻辑。
非常感谢你的阅读
大学的时候选择了自学python,工作了发现吃了计算机基础不好的亏,学历不行这是没办法的事,只能后天弥补,于是在编码之外开启了自己的逆袭之路,不断的学习python核心知识,深入的研习计算机基础知识,整理好了,我放在我们的微信公众号《程序员学府》,如果你也不甘平庸,那就与我一起在编码之外,不断成长吧!

其实这里不仅有技术,更有那些技术之外的东西,比如,如何做一个精致的程序员,而不是“屌丝”,程序员本身就是高贵的一种存在啊,难道不是吗?[点击加入]想做你自己想成为高尚人,加油!

python小技巧:300行代码实现俄罗斯方块相关推荐

  1. Python 游戏:300行代码实现俄罗斯方块

    本文代码基于 python 3.6 和 pygame1.9.4. 俄罗斯方块是儿时最经典的游戏之一,刚开始接触 pygame 的时候就想写一个俄罗斯方块.但是想到旋转,停靠,消除等操作,感觉好像很难啊 ...

  2. python编程小游戏代码-Python小游戏之300行代码实现俄罗斯方块

    前言 本文代码基于 python3.6 和 pygame1.9.4. 俄罗斯方块是儿时最经典的游戏之一,刚开始接触 pygame 的时候就想写一个俄罗斯方块.但是想到旋转,停靠,消除等操作,感觉好像很 ...

  3. python小游戏源码-Python小游戏之300行代码实现俄罗斯方块

    Python小游戏之300行代码实现俄罗斯方块 来源:中文源码网 浏览: 次 日期:2019年11月5日 [下载文档: Python小游戏之300行代码实现俄罗斯方块.txt ] (友情提示:右键点上 ...

  4. python编写小游戏代码_Python小游戏之300行代码实现俄罗斯方块

    Python小游戏之300行代码实现俄罗斯方块 来源:中文源码网 浏览: 次 日期:2019年11月5日 [下载文档: Python小游戏之300行代码实现俄罗斯方块.txt ] (友情提示:右键点上 ...

  5. python小游戏-16行代码实现3D撞球小游戏!-源码下载

    python小游戏-16行代码实现3D撞球小游戏!-源码下载 所属网站分类: 资源下载 > python小游戏 作者:搞笑 链接: http://www.pythonheidong.com/bl ...

  6. python小游戏代码大全-Python小游戏之300行代码实现俄罗斯方块

    前言 本文代码基于 python3.6 和 pygame1.9.4. 俄罗斯方块是儿时最经典的游戏之一,刚开始接触 pygame 的时候就想写一个俄罗斯方块.但是想到旋转,停靠,消除等操作,感觉好像很 ...

  7. python编写游戏300行代码_300行代码实现Python游戏:俄罗斯方块

    本文代码基于 python3.6 和 pygame1.9.4. 俄罗斯方块是儿时最经典的游戏之一,刚开始接触 pygame 的时候就想写一个俄罗斯方块.但是想到旋转,停靠,消除等操作,感觉好像很难啊, ...

  8. python300行代码_Python:游戏:300行代码实现俄罗斯方块

    本文代码基于 python3.6 和 pygame1.9.4.python 俄罗斯方块是儿时最经典的游戏之一,刚开始接触 pygame 的时候就想写一个俄罗斯方块.可是想到旋转,停靠,消除等操做,感受 ...

  9. Python小技巧:两行代码实现批量给图片填加水印,这也太简单了~

    文章目录 先让我哔哔一下 准备工作 代码解析 1.单张图片添加水印 2.批量填加多张图片水印 先让我哔哔一下 来个超级超级简单的小案例,有手就行的那种~ 我们平时要给图片加水印,但是又不会PS,免不了 ...

最新文章

  1. 属性处理器Spring攻略学习笔记(2.12)------外部化Bean配置
  2. 中望CAD 2021中文版
  3. 蓝桥杯练习系统习题-历年真题解析2(完整版)
  4. 如何使用idea REST Clinet 代替PostMan发送Http请求
  5. 神策数据上线“点击分析”,深度感知用户点击行为
  6. 自编码器及其相关模型
  7. 为什么Java在后来的版本中,给接口增加了默认方法、静态方法、私有方法?
  8. sql 把特定数据排在最前面
  9. cocos2d 嵌入网页_在 cocos2d-x 中嵌入浏览器
  10. Microsoft Dynamics CRM 2015 之安装SQL Server 2012过程中出现“启用windows功能NetFx3时出错...
  11. 大数据-概念-应用-弊端
  12. iOS 新浪微博客户端Demo实践之(六) 微博评论列表页面和发评论
  13. Zigbee之旅(五):几个重要的CC2430基础实验——串口通信
  14. 决定使用JBPM3、JBPM4、Drools Folw 还是等待JBPM5?
  15. 北航、商汤、UCSD 提出首个点云二值网络 BiPointNet(ICLR2021)
  16. 基于遥感的草原与沙漠化监测
  17. 外地户籍应届毕业生落户上海申请及办理流程(2017更新)
  18. python中去除全角空格
  19. 论文学习笔记 MUSE: Secure Inference Resilient to Malicious Clients
  20. SSM3==理解静态代理、动态代理Proxy.newProxyInstance、cglib代理==通过纯XML配置spring AOP,通过纯注解配置spring AOP

热门文章

  1. 14.2 Numpy实现逆傅里叶变换
  2. 计算机论文致谢词范文500字,论文致谢词范文500字(精选5篇)
  3. 三种食物会让肿瘤疯长
  4. 土地估价师继续教育培训心得体会
  5. JS分别取数值的整数部分和小数部分的几种方法
  6. python符号积分
  7. pytorch迁移学习载入部分权重
  8. EBS 常用模块到XLA的关联字段追溯
  9. MySQL系列:innodb源码分析之表空间管理
  10. 微信小程序项目实例——手势解锁