Python3 编程实战 Tetris 机器人(game 类)
作者:zhoutk
来源:SegmentFault 思否社区
系列文章地址
https://segmentfault.com/a/1190000040121026
game类
游戏逻辑控制类,是界面与Tetris类之间的粘合者,接受界面的鼠标及键盘事件,操作Tetris类,实现游戏逻辑。单个方块的操作,在Tetris中已经实现,game类主要是实现消行算法、新方块的产生、游戏速度控制等。
设计思路
消层算法简单的处理就是发现一行,消除一行。本项目使用一点技巧,先找出所有可消除行,把行号存入数组中,一次性消除。游戏速度的控制,使用定时器来实现,但发现python的定时器与其它语言有些差别,会不断产生新的定时器对象,开始感觉有些不对劲,但也没有重视。后来确认,这会产生内存泄漏,后使用tkinter.after替换了。
相关常数
SCORES = (0,1,3,7,10) # 消层分值设定
STEPUPSCORE = 50 # 每增长50分,速度加快一个等级
STEPUPINTERVAL = 100 # 每增长一个等级,定时器间隔时间减少100毫秒
具体实现
游戏状态变量
game.gameRunningStatus
0 : 游戏未开始 1 : 手动游戏 2 : 游戏回放 5 : 游戏暂停
开始游戏
def start(self):
self.gameRunningStatus = 1
self.gameSpeedInterval = 1000 # 初始游戏速度
self.gameSpeed = 1 # 游戏速度等级
self.gameLevels = 0 # 消层数
self.gameScores = 0 # 总得分
self.app.updateGameInfo(1,0,0) # 初始化界面信息
self.canvas.delete(ALL) # 清空游戏空间
self.nextCanvas.delete(ALL) # 下一方块空间清空
initGameRoom() # 初始化游戏空间数据
self.tetris = Tetris(self.canvas, 4, 0, random.randint(0,6)) # 随机生成第一个方块
for i in range(random.randint(0,4)): # 旋转随机次数,方块出场式
self.tetris.rotate()
self.nextTetris = Tetris(self.nextCanvas, 1, 1, random.randint(0,6)) # 随机生成下一方块
for i in range(random.randint(0,4)): # 下一方块初始形态(随机)
self.nextTetris.rotate()
self.tick = Timer(self.gameSpeedInterval / 1000, self.tickoff) # 控制游戏速度定时器
self.tick.start()
生成下一方块
def generateNext(self):
cleanLevels = self.clearRows() # 统计可消除层数
if cleanLevels > 0: # 有可消层,计算分值
self.gameLevels += cleanLevels
self.gameScores += SCORES[cleanLevels]
if self.gameScores / STEPUPSCORE >= self.gameSpeed:
self.gameSpeed += 1
self.gameSpeedInterval -= STEPUPINTERVAL
self.app.updateGameInfo(self.gameSpeed, self.gameLevels, self.gameScores)
self.tetris = Tetris(self.canvas, 4, 0, self.nextTetris.getTetrisShape()) # 复制nexTetris到游戏空间
for i in range(self.nextTetris.getRotateCount()):
if not self.tetris.rotate():
break
if self.tetris.canPlace(4, 0): # 判定游戏是否结束
self.nextCanvas.delete(ALL) # 游戏未结束,生成新的方块放入下一方块空间
self.nextTetris = Tetris(self.nextCanvas, 1, 1, random.randint(0,6))
for i in range(random.randint(0,4)):
self.nextTetris.rotate()
else: # 游戏结束
self.gameRunningStatus = 0
self.canvas.create_text(150, 200, text = "Game is over!", fill="white", font = "Times 28 italic bold")
self.app.setStartButtonText("Start")
print("game is over!")
统计可消除层
def clearRows(self):
occupyLines = [] # 存储可消除层行号
h = 20
while h > 0:
allOccupy = 0
for i in range(1, 11):
if GameRoom[h][i]:
allOccupy += 1 # block统计
if allOccupy == 10: # 行满
occupyLines.append(h) # 存储行号
elif allOccupy == 0: # 有一个空位,跳过些行
break
h -= 1
if len(occupyLines) > 0: # 有可消层
self.doCleanRows(occupyLines) # 消除可消层
return len(occupyLines)
消层函数
def doCleanRows(self, lines):
index = 0 # 存储已经消除了多少行
h = lines[index] # 满行行号数据
while h >= 0: # 只需要从最下面一满行开始即可
if index < len(lines) and h == lines[index]: # 找到一可消行
index += 1 # 已消行总数加1
for j in range(1, 11):
GameRoom[h][j] = 0 # 游戏空间数据消行
for b in self.canvas.find_closest(\ # Canvas元件消除
j * BLOCKSIDEWIDTH - HALFBLOCKWIDTH, \
h * BLOCKSIDEWIDTH - HALFBLOCKWIDTH):
self.canvas.delete(b)
else: # 移动游戏空间数据
count = 0 # 空位统计,全空,可以提前结束循环
for j in range(1, 11):
if GameRoom[h][j] == 1:
count += 1
GameRoom[h + index][j] = GameRoom[h][j] # 注意index变量,这是移动步长,与已经消除行数有关
GameRoom[h][j] = 0
for b in self.canvas.find_closest(j * BLOCKSIDEWIDTH - HALFBLOCKWIDTH, h * BLOCKSIDEWIDTH - HALFBLOCKWIDTH):
self.canvas.move(b, 0, index * BLOCKSIDEWIDTH)
if count == 0: # 发现整行位全空,提前退出
break
h -= 1
方块控制
def moveDownEnd(self):
while self.moveDown(): # 循环下落,直到不能再落
pass
游戏速度控制
def tickoff(self):
if self.gameRunningStatus == 1:
self.moveDown()
self.tick = Timer(self.gameSpeedInterval / 1000, self.tickoff)
self.tick.start()
内容预告
项目地址
https://gitee.com/zhoutk/ptetris
或
https://github.com/zhoutk/ptetris
运行方法
1. install python3, git
2. git clone https://gitee.com/zhoutk/ptetris (or download and unzip source code)
3. cd ptetris
4. python3 tetris
This project surpport windows, linux, macOs
on linux, you must install tkinter first, use this command:
sudo apt install python3-tk
相关项目
https://gitee.com/zhoutk/qtetris
评论