关于python3.x:Python3编程实战Tetris机器人game类

8次阅读

共计 3823 个字符,预计需要花费 10 分钟才能阅读完成。

系列文章入口

《Python3 编程实战 Tetris 机器人》

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!")

统计可打消层

clearRows 函数查找能打消的层,将其打消,返回可打消层总数。

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)

消层函数

消层函数,依据 clearRows 函数统计的可消层行号,打消游戏空间的满行。算法的难点在于要同时管制两个变量,一个是从下到上遍历游戏空间,另一方面要将满行以上的空间数据下移,下移的步长为曾经打消的行数。

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

方块管制

方块管制曾经在 Tetris 类实现,在 game 类中,只是转发事件到以后方块即可。惟一多了一个 moveDownEnd – 方块直落函数。

def moveDownEnd(self):
    while self.moveDown():      # 循环着落,直到不能再落
        pass

游戏速度管制

游戏速度管制实现很容易,只须要定时触发一次 down 函数就能够了。

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

相干我的项目

曾经实现了 C ++ 版,我的项目地址:

https://gitee.com/zhoutk/qtetris
正文完
 0