编程语言:python(3.6.4)

主要应用的模块:pygame

首先列出我的核心思路:

1,图像由“核心变量”完全控制,图像变化的本质是 变量的改变

2,自上而下式的思考,图像变化的问题将一步步转为 一系列具体的变量修改

3,“核心变量”在思考过程中并非不可变更,为了写函数方便,可以适当让步

正文开始:

核心变量到图像

首先看成品图预览图

从上图和游戏玩法可以得出以下两点:

1,方块位置十分有规律

2,两类方块(上面移动的,下方固定的 都比较有特点)

方块的大小都是固定的,只需要操心位置的问题,下面建坐标系

下一步,坐标的储存方式

记录方式有两种:

1,横纵坐标做一个二元元组,再用一个列表装着一堆二元元组

例如:[(20,1),(20,2),(20,3),(20,4)]代表第20行的1~4列的四个方块

2,二维数组,一行是一个列表,用两个索引代表横纵坐标,值为1就代表有方块,0就是没有方块

例如:block[20][1] 值为1就表示20行第1列有方块,block[20][5] 为0表示20行第5列有没有方块

讲道理,两种记录方式没什么大区别,而且第一种似乎更好用

但后面会有这样的问题

怎么判断一行是否被填满,填满后怎么消除,消除后怎么使上方的方块下落。

两种记录方式对应的解法:

1,假如判断第2行 只要依次判断(2, 0), (2, 1)···· (2, 8), (2, 9) 是否都存在于列表就可以,消除、下落就有点麻烦,以第2行为例 遍历列表 2行以下的不修改,2行的全部清除,2行以上的 行数-1

2,被填满 等价于 全是1  等价于 没有0 ,一个not in 就可以啦,pop就可以清除一行,而且后面列表的索引会向前补(实现下落),然后在最后补充一个空列表就完事啦(防止被删光)

所以

充当背景的方块 就使用2号记录方式

下一步 对接pygame绘制函数

核心变量的声明

background = [[0 for i in range(10)]for j in range(21)]
active = []

绘制函数

# 第一版
def new_draw():screen.fill(white)for i in range(1, 21):for j in range(10):bolck = background[i][j]if bolck:pygame.draw.rect(screen, blue, (j * 25 + 1, 500 - i * 25 + 1, 23, 23))for i, j in active:pygame.draw.rect(screen, blue, (j * 25+1, 500 - i * 25 + 1, 23, 23))pygame.display.update()

补充:坐标转换

键盘到图像(本质:键盘到核心变量)

下面简略列出需要的函数

名称 内容 发生时机
左右移动 修改y轴坐标 键盘事件
旋转 复杂的坐标转化 键盘事件
下落 修改x轴坐标 键盘事件,计时器
下落检查 检查是否可以继续下落 下落  前后
检查方块 逐行检查是否可以消除, 下落检查 后
消除方块 检查方块 后
生成方块 产生下一个方块 消除方块 后
检查存活

生成的方块无法放置<=>

堆到顶端<=>game over

生成方块 后

首先,方块移动的难点在“旋转”上

Q:为什么不先考虑左右移动
A:旋转的问题的有些复杂,需要变更“核心变量”核心变量一但变更 其它相关函数都得改写所以为了省心,优先考虑可能涉及“核心变量”的事情

解决思路:

1,为每个形状建立一个“状态库”,手写出每个姿态,旋转时再读取

2,旋转前后存在明确的数学关系

选那个没有悬念

追加一个变量,记录旋转中心坐标

旋转时依照方程转换坐标

公式很简单吧

如果旋转在原点,将会更简单

PS:注意坐标系,公式不能直接抄

所以,从记录“绝对坐标”变更为“中心坐标+相对坐标”

PS:绘制函数需要做相应的调整

旋转过程 ( x , y ) --> (-y , x)

重要的细节:移动是有限制的

方块在边界处,就得限制向外的移动,如果移动后与已有的方块重叠,也得限制移动

代码时间

左右移动

def move_LR(n):"""n=-1代表向左,n=1代表向右"""x, y = centrey += nfor i, j in active:i += xj += yif j < 0 or j > 9 or background[i][j]:breakelse:centre.clear()centre.extend([x, y])

PS:centre是列表

Q:clear + extend 是什么骚操作?不可以直接赋值吗?
A:函数内部可以读取 但不能修改全局变量但是可以调用全局变量的方法所以clear+extend修改centra这样就不用将centra传入传出啦(危险操作,谨慎使用)

旋转的

def rotate():x, y = centrel = [(-j, i) for i, j in active]for i, j in l:i += xj += yif j < 0 or j > 9 or background[i][j]:breakelse:active.clear()active.extend(l)

PS:因为旋转的机制很简陋,会有田字形方块的也能旋转的奇怪现象发生。

讲道理下落并不难,关键是下落结束后会有很多后事要处理

1,检查是否落到底部,是:继续,否:跳出

2,active的信息转到background,

3,检查background是否有“行”被填满 是:继续,否:跳至5

4,清掉满行,补上空行,计分

5,生成新的active,检查其位置是否被占(被占<=>方块被堆至顶部<=>game over)

那就开始撸代码

def move_down():x, y = centrex -= 1for i, j in active:i += xj += yif background[i][j]:breakelse:centre.clear()centre.extend([x, y])return# 如果新位置未被占用 通过return结束# 如果新位置被占用则继续向下执行x, y = centrefor i, j in active:background[x + i][y + j] = 1l = []for i in range(1, 20):if 0 not in background[i]:l.append(i)# l装 行号,鉴于删去后,部分索引变化,对其降序排列,倒着删除l.sort(reverse=True)for i in l:background.pop(i)background.append([0 for j in range(10)])# 随删随补
score[0] += len(l)pygame.display.set_caption("分数:%d" % (score[0]))active.clear()active.extend(list(random.choice(all_block)))# all_block保存7种形状的信息,手打出来的
    centre.clear()centre.extend([20, 4])x, y = centrefor i, j in active:i += xj += yif background[i][j]:breakelse:returnalive.append(1)

控制结构

下一步组装

因为核心变量发生变化,new_draw重写

def new_draw():screen.fill(white)for i in range(1, 21):for j in range(10):bolck = background[i][j]if bolck:pygame.draw.rect(screen, blue, (j * 25 + 1, 500 - i * 25 + 1, 23, 23))x, y = centrefor i, j in active:i += xj += ypygame.draw.rect(screen, blue, (j * 25 + 1, 500 - i * 25 + 1, 23, 23))pygame.display.update()

核心变量定义

all_block = (((0, 0), (0, -1), (0, 1), (0, 2)),((0, 0), (0, 1), (-1, 0), (-1, 1)),((0, 0), (0, -1), (-1, 0), (-1, 1)),((0, 0), (0, 1), (-1, -1), (-1, 0)),((0, 0), (0, 1), (1, 0), (0, -1)),((0, 0), (1, 0), (-1, 0), (1, -1)),((0, 0), (1, 0), (-1, 0), (1, 1)))
background = [[0 for i in range(10)] for j in range(24)]
background[0] = [1 for i in range(10)]
active = list(random.choice(all_block))
centre = [20, 4]
score = [0]

标红处的说明:

1,生成方块的时的中心为[20,4]

可能会有方块伸展到 21 层,然后引发 越界错误   ̄へ ̄

所以一口气 将上限设为 24

2,因为测试时发现,方块直接从底部漏了出去(⊙﹏⊙)

所以,在第零行加一层地板φ(>ω<*)

注意尽管第0行 满足 "没有0"的条件,但是

    l = []for i in range(1, 20):if 0 not in background[i]:l.append(i)

这个部分是从第1行才开始检查的(~ ̄▽ ̄)~

3,我懒,不想传参,所以 老套路

pygame固定结构,控制结构,控制变量,龙套变量

pygame.init()
screen = pygame.display.set_mode((250, 500))
pygame.display.set_caption("俄罗斯方块")
fclock = pygame.time.Clock()black = 0, 0, 0
white = 255, 255, 255
blue = 0, 0, 255times = 0
alive = []
press = False
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:move_LR(-1)elif event.key == pygame.K_RIGHT:move_LR(1)elif event.key == pygame.K_UP:rotate()elif event.key == pygame.K_DOWN:press = Trueelif event.type == pygame.KEYUP:if event.key == pygame.K_DOWN:press = Falseif press:times += 10if times >= 50:move_down()times = 0else:times += 1if alive:pygame.display.set_caption("over分数:%d" % (score[0]))time.sleep(3)breaknew_draw()fclock.tick(100)

说明:

1,原来按一次“下”,方块只会移动一格。。。。

所以修正了一下,支持 长按,为此加了一个变量press

2,times用于计时

3,游戏结束的有点突兀,直接就brake啦

最后发现漏了一行没拷上来

import pygame, sys, random, time

下面是全部代码

import pygame, sys, random, time# 第二版
def new_draw():screen.fill(white)for i in range(1, 21):for j in range(10):bolck = background[i][j]if bolck:pygame.draw.rect(screen, blue, (j * 25 + 1, 500 - i * 25 + 1, 23, 23))x, y = centrefor i, j in active:i += xj += ypygame.draw.rect(screen, blue, (j * 25 + 1, 500 - i * 25 + 1, 23, 23))pygame.display.update()def move_LR(n):"""n=-1代表向左,n=1代表向右"""x, y = centrey += nfor i, j in active:i += xj += yif j < 0 or j > 9 or background[i][j]:breakelse:centre.clear()centre.extend([x, y])def rotate():x, y = centrel = [(-j, i) for i, j in active]for i, j in l:i += xj += yif j < 0 or j > 9 or background[i][j]:breakelse:active.clear()active.extend(l)def move_down():x, y = centrex -= 1for i, j in active:i += xj += yif background[i][j]:breakelse:centre.clear()centre.extend([x, y])return# 如果新位置未被占用 通过return结束# 如果新位置被占用则继续向下执行x, y = centrefor i, j in active:background[x + i][y + j] = 1l = []for i in range(1, 20):if 0 not in background[i]:l.append(i)# l装 行号,鉴于删去后,部分索引变化,对其降序排列,倒着删除l.sort(reverse=True)for i in l:background.pop(i)background.append([0 for j in range(10)])# 随删随补
score[0] += len(l)pygame.display.set_caption("分数:%d" % (score[0]))active.clear()active.extend(list(random.choice(all_block)))# all_block保存7种形状的信息,手打出来的
    centre.clear()centre.extend([20, 4])x, y = centrefor i, j in active:i += xj += yif background[i][j]:breakelse:returnalive.append(1)pygame.init()
screen = pygame.display.set_mode((250, 500))
pygame.display.set_caption("俄罗斯方块")
fclock = pygame.time.Clock()all_block = (((0, 0), (0, -1), (0, 1), (0, 2)),((0, 0), (0, 1), (-1, 0), (-1, 1)),((0, 0), (0, -1), (-1, 0), (-1, 1)),((0, 0), (0, 1), (-1, -1), (-1, 0)),((0, 0), (0, 1), (1, 0), (0, -1)),((0, 0), (1, 0), (-1, 0), (1, -1)),((0, 0), (1, 0), (-1, 0), (1, 1)))
background = [[0 for i in range(10)] for j in range(24)]
background[0] = [1 for i in range(10)]
active = list(random.choice(all_block))
centre = [20, 4]
score = [0]black = 0, 0, 0
white = 255, 255, 255
blue = 0, 0, 255times = 0
alive = []
press = False
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:move_LR(-1)elif event.key == pygame.K_RIGHT:move_LR(1)elif event.key == pygame.K_UP:rotate()elif event.key == pygame.K_DOWN:press = Trueelif event.type == pygame.KEYUP:if event.key == pygame.K_DOWN:press = Falseif press:times += 10if times >= 50:move_down()times = 0else:times += 1if alive:pygame.display.set_caption("over分数:%d" % (score[0]))time.sleep(3)breaknew_draw()fclock.tick(100)

all

本文就此结束

如果有疏漏或不对的地方,欢迎评论指正

#

转载于:https://www.cnblogs.com/ansver/p/9103064.html

俄罗斯方块(一):简版相关推荐

  1. [置顶]完美简版学生信息管理系统(附有源码)管理系统

    简版学生信息管理系统 目前为止找到的简版系统中最新.最全的java类管理系统 点击进入简版系统 如果无法直接连接,请进入: https://blog.csdn.net/weixin_43419816/ ...

  2. 7句话让Codex给我做了个小游戏,还是极简版塞尔达,一玩简直停不下来

    点击上方"视学算法",选择加"星标"或"置顶" 重磅干货,第一时间送达 梦晨 萧箫 发自 凹非寺 量子位 | 公众号 QbitAI 什么,7 ...

  3. 来,一起手撸一个简版 Redis(附源码)

    点击上方 视学算法,选择 设为星标 优质文章,及时送达 作者 | 凯京技术团队 来自 | my.oschina.net/keking/blog/3037372 今天主要介绍两个开源项目,然后创建应用最 ...

  4. 2012年中国移动地图和导航市场研究报告简版

    2019独角兽企业重金招聘Python工程师标准>>> 2012年中国移动地图和导航市场研究报告简版 2012年中国移动地图和导航市场用户规模为2.53亿人,增长率为62.2%.伴随 ...

  5. 10分钟手撸极简版ORM框架!

    最近很多小伙伴对ORM框架的实现很感兴趣,不少读者在冰河的微信上问:冰河,你知道ORM框架是如何实现的吗?比如像MyBatis和Hibernte这种ORM框架,它们是如何实现的呢? 为了能够让小伙伴们 ...

  6. 《数字孪生体技术白皮书(2019)》(简版)全文

    来源:<数字孪生体实验室原创> 12月27日,数字孪生体实验室与安世亚太联合正式发布了<数字孪生体技术白皮书(2019)>. 白皮书的第一部分关注对数字孪生体的抽象和总结.无论 ...

  7. Dockerfile 简版大全,附赠编写实例

    基础镜像可以用于创建Docker容器.镜像可以非常基础,仅仅包含操作系统:也可以非常丰富,包含灵巧的应用栈,随时可以发布.当你在使用Docker构建镜像的时候,每一个命令都会在前一个命令的基础上形成一 ...

  8. react-redux简版实现

    Provider组件 Provider用于建立能够被子组件访问的全局属性,核心API有两个: childContextTypes静态属性,用于指定被子组件访问的全局属性类型 getChildConte ...

  9. HTML5 新元素标签系列:最简版 HTML5

    我们不讨论为什么我们现在就可以用 HTML5 而不是等到2022,这篇文章将给你提供一系列 HTML样板,你现在就可以把他们应用在你的项目中.   五秒内开始用 HTML5 是你页面的标志符合 HTM ...

  10. 写一个简版 asp.net core

    动手写一个简版 asp.net core Intro 之前看到过蒋金楠老师的一篇 200 行代码带你了解 asp.net core 框架,最近参考蒋老师和 Edison 的文章和代码,结合自己对 as ...

最新文章

  1. 690啊690,你不是找骂吗?
  2. SQL update select语句
  3. cakephp 安装mysql_CakePHP的安装的简单方法
  4. 串匹配算法——BF算法
  5. 价值199的wp移植Emlog主题模板PandaPRO
  6. [手把手教]discuzX2插件制作教程__最菜鸟级别的入门坎 【三】
  7. Mybatis if test 中int判断非空的坑
  8. 红橙Darren视频笔记 仿汽车之家 可拖动列表
  9. 黑马乐优商城项目资源分享
  10. 免费下载IOS/MAc付费软件
  11. 雷达多普勒频率计算公式_智能驾驶之眼-毫米波雷达技术详解
  12. MapReduce论文中文版--The Google File System
  13. 计算机课程 图层关系认识 课件,PhotoShop系列视频讲座(八讲)
  14. HTTP中常见的各种状态码详解及解决方案
  15. 设置BIOS从USB启动!
  16. 关于SPING与EJB的胡言乱语
  17. 为什么iPhone通常比Android具有更好的音质?
  18. 可定制的小程序组件库:Wux Weapp
  19. python制作心形照片墙_这个七夕节,用Python为女友绘制一张爱心照片墙吧!
  20. weui 搜索 weui-search-bar

热门文章

  1. Java APNS开源库apns4j-1.0.1发布
  2. react + antd pro 项目搭建及发布流程
  3. 用 WasmEdge 和 YoMo 对实时数据流进行 AI 推理
  4. 开源SCADA组态软件Qt,C#,和WEB大全
  5. c语言不允许对数组大小作动态定义,c语言第07章数组.ppt
  6. 记一次失败的导师霸面
  7. js使用BOS Uploader上传视频到百度云
  8. linux服务器运维实战记录,linux运维好书推荐《高性能Linux服务器运维实战》
  9. Git:分支的工作流程
  10. 小白笔记本【函数篇】(updating)