《Python3编程实战Tetris机器人》python
在测试过程当中,发现程序出错,但关闭定时器,不进行自动下落就不会有问题。缘由是Timer会新开一个线程,线程和主线会产生资源冲突。linux
首先想到的是加锁,游戏逻辑很简单,加锁应该很容易解决问题。但无论我粗粒度加,仍是尽可能细粒度加,最后都会死锁。最后进行打印,发现程序停在了tkinter.Canvas.move处,我的认为这是tkinter的bug。
此路不通,换个思路。开一个工做线程,来完成全部的操做,主线程与定时器操做,都只是往工做线程中提交任务。也就是只让一个工做线程来作任务,这样就把资源冲突的问题避开了。git
加锁方案分析github
tickLock[0] = True with curTetrisLock: print("-------+++---00000000--- get lock", tickLock) if ke.keysym == 'Left': self.game.moveLeft() if ke.keysym == 'Right': self.game.moveRight() if ke.keysym == 'Up': self.game.rotate() if ke.keysym == 'Down': self.game.moveDown() if ke.keysym == 'space': self.game.moveDownEnd() print("-------+++---00000000--- lose lock", tickLock)
def tickoff(self): if self.gameRunningStatus == 1: if not tickLock[0]: with curTetrisLock: print("------------------ get lock", tickLock[1]) self.moveDown() print("================== lose lock", tickLock[1]) self.tick = Timer(self.gameSpeedInterval / 1000, self.tickoff) self.tick.start()
程序最后停在了Block类中的tkinter.Canvas.move处,每次都由定时器触发,没法释放。
有兴趣的同窗能够到项目中,切换到lockbug分支去研究,我写了不少打印输出方便问题定位。编程
新增一个Queue,键盘响应与定时器响应往队列中增长任务单元,工做线程逐一处理这些任务。任务单元以下设计:segmentfault
("cmd",(data))
每个任务单元都是一个二元元组(方便数据解构),第一个是字符串,为命令;第二个是元组,是数据包(也按方便解构的方式去设计),由每一个命令自行定义。windows
def opWork(self): while True: if not opQueue.empty(): cmd,data = opQueue.get() if op == "Left": self.moveLeft() elif op == "Right": self.moveRight() elif op == "Up": self.rotate() elif op == "Down": self.moveDown() elif op == "space": self.moveDownEnd() elif op == "quit": break else: time.sleep(0.01)
def processKeyboardEvent(self, ke): if self.game.getGameRunningStatus() == 1: if ke.keysym == 'Left': opQueue.put(('Left',())) if ke.keysym == 'Right': opQueue.put(('Right',())) if ke.keysym == 'Up': opQueue.put(('Up',())) if ke.keysym == 'Down': opQueue.put(('Down',())) if ke.keysym == 'space': opQueue.put(('space',()))
游戏控制主要函数,在方块下落到底部后,进行消层、统计得分、速度等级断定、游戏是否结束断定以及将下一方块移入游戏空间并再生成一个方块显示在下一方块显示空间中。函数
def tickoff(self): if self.gameRunningStatus == 1: opQueue.put(('Down'),()) 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